From 90a15a9753a4e882a4a0d7ce04fdae9ec5d29683 Mon Sep 17 00:00:00 2001 From: François Revel Date: Tue, 3 Jun 2008 19:07:09 +0000 Subject: The BeOS-specific part of the BeOS (and Haiku) port, modeled mostly from the GTK version. Some fixes are needed elsewhere but non-obvious ones I'll post on the mailing list for discussion. Currently it opens windows with a toolbar, url and status bar, a (yet empty) menu bar. Rendering seems to work including scrolling at scale 1 (other non-tested). framesets seems broken though. svn path=/trunk/netsurf/; revision=4253 --- beos/beos_bitmap.cpp | 425 ++++++++++++ beos/beos_bitmap.h | 34 + beos/beos_fetch_rsrc.cpp | 371 +++++++++++ beos/beos_fetch_rsrc.h | 29 + beos/beos_filetype.cpp | 317 +++++++++ beos/beos_filetype.h | 21 + beos/beos_font.cpp | 556 ++++++++++++++++ beos/beos_font.h | 30 + beos/beos_gui.cpp | 1018 ++++++++++++++++++++++++++++ beos/beos_gui.h | 57 ++ beos/beos_history.cpp | 181 +++++ beos/beos_history.h | 35 + beos/beos_login.cpp | 192 ++++++ beos/beos_options.cpp | 273 ++++++++ beos/beos_options.h | 33 + beos/beos_plotters.cpp | 753 +++++++++++++++++++++ beos/beos_plotters.h | 57 ++ beos/beos_res.rdef | 350 ++++++++++ beos/beos_res.rsrc | Bin 0 -> 11584 bytes beos/beos_scaffolding.cpp | 1607 +++++++++++++++++++++++++++++++++++++++++++++ beos/beos_scaffolding.h | 71 ++ beos/beos_schedule.cpp | 209 ++++++ beos/beos_schedule.h | 26 + beos/beos_throbber.cpp | 144 ++++ beos/beos_throbber.h | 35 + beos/beos_thumbnail.cpp | 133 ++++ beos/beos_treeview.cpp | 130 ++++ beos/beos_window.cpp | 1570 +++++++++++++++++++++++++++++++++++++++++++ beos/beos_window.h | 64 ++ beos/options.h | 37 ++ beos/res/adblock.css | 1 + beos/res/beosdefault.css | 21 + beos/res/ca-bundle.txt | 1 + beos/res/default.css | 1 + beos/res/messages | 1 + beos/res/netsurf.xpm | 317 +++++++++ beos/res/throbber.gif | Bin 0 -> 5175 bytes 37 files changed, 9100 insertions(+) create mode 100644 beos/beos_bitmap.cpp create mode 100644 beos/beos_bitmap.h create mode 100644 beos/beos_fetch_rsrc.cpp create mode 100644 beos/beos_fetch_rsrc.h create mode 100644 beos/beos_filetype.cpp create mode 100644 beos/beos_filetype.h create mode 100644 beos/beos_font.cpp create mode 100644 beos/beos_font.h create mode 100644 beos/beos_gui.cpp create mode 100644 beos/beos_gui.h create mode 100644 beos/beos_history.cpp create mode 100644 beos/beos_history.h create mode 100644 beos/beos_login.cpp create mode 100644 beos/beos_options.cpp create mode 100644 beos/beos_options.h create mode 100644 beos/beos_plotters.cpp create mode 100644 beos/beos_plotters.h create mode 100644 beos/beos_res.rdef create mode 100644 beos/beos_res.rsrc create mode 100644 beos/beos_scaffolding.cpp create mode 100644 beos/beos_scaffolding.h create mode 100644 beos/beos_schedule.cpp create mode 100644 beos/beos_schedule.h create mode 100644 beos/beos_throbber.cpp create mode 100644 beos/beos_throbber.h create mode 100644 beos/beos_thumbnail.cpp create mode 100644 beos/beos_treeview.cpp create mode 100644 beos/beos_window.cpp create mode 100644 beos/beos_window.h create mode 100644 beos/options.h create mode 120000 beos/res/adblock.css create mode 100644 beos/res/beosdefault.css create mode 120000 beos/res/ca-bundle.txt create mode 120000 beos/res/default.css create mode 120000 beos/res/messages create mode 100644 beos/res/netsurf.xpm create mode 100644 beos/res/throbber.gif (limited to 'beos') diff --git a/beos/beos_bitmap.cpp b/beos/beos_bitmap.cpp new file mode 100644 index 000000000..6f950394f --- /dev/null +++ b/beos/beos_bitmap.cpp @@ -0,0 +1,425 @@ +/* + * Copyright 2004 James Bursa + * + * 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 . + */ + +/** \file + * Generic bitmap handling (BeOS implementation). + * + * This implements the interface given by desktop/bitmap.h using BBitmap. + */ + +#include +#include +#include +#include +#include +extern "C" { +#include "content/content.h" +#include "image/bitmap.h" +#include "utils/log.h" +} +#include "beos/beos_bitmap.h" +#include "beos/beos_scaffolding.h" + +struct bitmap { + BBitmap *primary; + BBitmap *shadow; // in NetSurf's ABGR order + BBitmap *pretile_x; + BBitmap *pretile_y; + BBitmap *pretile_xy; + bool opaque; +}; + +#define MIN_PRETILE_WIDTH 256 +#define MIN_PRETILE_HEIGHT 256 + +#warning TODO: check rgba order +#warning TODO: add correct locking (not strictly required) + + +/** Convert to BeOS RGBA32_LITTLE (strictly BGRA) from NetSurf's favoured ABGR format. + * Copies the converted data elsewhere. Operation is rotate left 8 bits. + * + * \param pixels Array of 32-bit values, in the form of ABGR. This will + * be overwritten with new data in the form of BGRA. + * \param width Width of the bitmap + * \param height Height of the bitmap + * \param rowstride Number of bytes to skip after each row (this + * implementation requires this to be a multiple of 4.) + */ +#if 0 +static inline void nsbeos_abgr_to_bgra(void *src, void *dst, int width, int height, + size_t rowstride) +{ + u_int32_t *from = (u_int32_t *)src; + u_int32_t *to = (u_int32_t *)dst; + + rowstride >>= 2; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + u_int32_t e = from[x]; + to[x] = (e >> 24) | (e << 8); + } + from += rowstride; + to += rowstride; + } +} +#endif +static inline void nsbeos_rgba_to_bgra(void *src, void *dst, int width, int height, + size_t rowstride) +{ + struct abgr { uint8 a, b, g, r; }; + struct rgba { uint8 r, g, b ,a; }; + struct bgra { uint8 b, g, r, a; }; + struct rgba *from = (struct rgba *)src; + struct bgra *to = (struct bgra *)dst; + + rowstride >>= 2; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + to[x].b = from[x].b; + to[x].g = from[x].g; + to[x].r = from[x].r; + to[x].a = from[x].a; + if (from[x].a == 0) + *(rgb_color *)&to[x] = B_TRANSPARENT_32_BIT; + } + from += rowstride; + to += rowstride; + } +} + + +/** + * Create a bitmap. + * + * \param width width of image in pixels + * \param height width of image in pixels + * \param state a flag word indicating the initial state + * \return an opaque struct bitmap, or NULL on memory exhaustion + */ + +struct bitmap *bitmap_create(int width, int height, unsigned int state) +{ + struct bitmap *bmp = (struct bitmap *)malloc(sizeof(struct bitmap)); + if (bmp == NULL) + return NULL; + + BRect frame(0, 0, width - 1, height - 1); + //XXX: bytes per row ? + bmp->primary = new BBitmap(frame, 0, B_RGBA32); + bmp->shadow = new BBitmap(frame, 0, B_RGBA32); + + bmp->pretile_x = bmp->pretile_y = bmp->pretile_xy = NULL; + + bmp->opaque = false; + +#if 0 /* GTK */ + bmp->primary = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, + width, height); + + /* fill the pixbuf in with 100% transparent black, as the memory + * won't have been cleared. + */ + gdk_pixbuf_fill(bmp->primary, 0); + bmp->pretile_x = bmp->pretile_y = bmp->pretile_xy = NULL; +#endif + return bmp; +} + + +/** + * Sets whether a bitmap should be plotted opaque + * + * \param bitmap a bitmap, as returned by bitmap_create() + * \param opaque whether the bitmap should be plotted opaque + */ +void bitmap_set_opaque(struct bitmap *bitmap, bool opaque) +{ + assert(bitmap); +/* todo: set bitmap as opaque */ + bitmap->opaque = true; +} + + +/** + * Tests whether a bitmap has an opaque alpha channel + * + * \param bitmap a bitmap, as returned by bitmap_create() + * \return whether the bitmap is opaque + */ +bool bitmap_test_opaque(struct bitmap *bitmap) +{ + assert(bitmap); +/* todo: test if bitmap as opaque */ + return bitmap->opaque; +} + + +/** + * Gets whether a bitmap should be plotted opaque + * + * \param bitmap a bitmap, as returned by bitmap_create() + */ +bool bitmap_get_opaque(struct bitmap *bitmap) +{ + assert(bitmap); +/* todo: get whether bitmap is opaque */ + return bitmap->opaque; +} + + +/** + * Return a pointer to the pixel data in a bitmap. + * + * \param bitmap a bitmap, as returned by bitmap_create() + * \return pointer to the pixel buffer + * + * The pixel data is packed as BITMAP_FORMAT, possibly with padding at the end + * of rows. The width of a row in bytes is given by bitmap_get_rowstride(). + */ + +char *bitmap_get_buffer(struct bitmap *bitmap) +{ + assert(bitmap); + return (char *)(bitmap->shadow->Bits()); +} + + +/** + * Find the width of a pixel row in bytes. + * + * \param bitmap a bitmap, as returned by bitmap_create() + * \return width of a pixel row in the bitmap + */ + +size_t bitmap_get_rowstride(struct bitmap *bitmap) +{ + assert(bitmap); + return (bitmap->primary->BytesPerRow()); +} + + +static void +nsbeos_bitmap_free_pretiles(struct bitmap *bitmap) +{ +#define FREE_TILE(XY) if (bitmap->pretile_##XY) delete (bitmap->pretile_##XY); bitmap->pretile_##XY = NULL + FREE_TILE(x); + FREE_TILE(y); + FREE_TILE(xy); +#undef FREE_TILE +} + +/** + * Free a bitmap. + * + * \param bitmap a bitmap, as returned by bitmap_create() + */ + +void bitmap_destroy(struct bitmap *bitmap) +{ + assert(bitmap); + nsbeos_bitmap_free_pretiles(bitmap); + delete bitmap->primary; + delete bitmap->shadow; + free(bitmap); +} + + +/** + * Save a bitmap in the platform's native format. + * + * \param bitmap a bitmap, as returned by bitmap_create() + * \param path pathname for file + * \param flags modify the behaviour of the save + * \return true on success, false on error and error reported + */ + +bool bitmap_save(struct bitmap *bitmap, const char *path, unsigned flags) +{ +#warning WRITEME +#if 0 /* GTK */ + GError *err = NULL; + + gdk_pixbuf_save(bitmap->primary, path, "png", &err, NULL); + + if (err == NULL) + /* TODO: report an error here */ + return false; + +#endif + return true; +} + + +/** + * The bitmap image has changed, so flush any persistant cache. + * + * \param bitmap a bitmap, as returned by bitmap_create() + */ +void bitmap_modified(struct bitmap *bitmap) { + // convert the shadow (ABGR) to into the primary bitmap + nsbeos_rgba_to_bgra(bitmap->shadow->Bits(), bitmap->primary->Bits(), + bitmap->primary->Bounds().Width() + 1, + bitmap->primary->Bounds().Height() + 1, + bitmap->primary->BytesPerRow()); + nsbeos_bitmap_free_pretiles(bitmap); +} + + +/** + * The bitmap image can be suspended. + * + * \param bitmap a bitmap, as returned by bitmap_create() + * \param private_word a private word to be returned later + * \param suspend the function to be called upon suspension + * \param resume the function to be called when resuming + */ +void bitmap_set_suspendable(struct bitmap *bitmap, void *private_word, + void (*invalidate)(struct bitmap *bitmap, void *private_word)) { +} + +static BBitmap * +nsbeos_bitmap_generate_pretile(BBitmap *primary, int repeat_x, int repeat_y) +{ + int width = primary->Bounds().Width() + 1; + int height = primary->Bounds().Height() + 1; + size_t primary_stride = primary->BytesPerRow(); + BRect frame(0, 0, width * repeat_x - 1, height * repeat_y - 1); + BBitmap *result = new BBitmap(frame, 0, B_RGBA32); + + char *target_buffer = (char *)result->Bits(); + int x,y,row; + /* This algorithm won't work if the strides are not multiples */ + assert((size_t)(result->BytesPerRow()) == + (primary_stride * repeat_x)); + + if (repeat_x == 1 && repeat_y == 1) { + delete result; + // just return a copy + return new BBitmap(primary); + } + + for (y = 0; y < repeat_y; ++y) { + char *primary_buffer = (char *)primary->Bits(); + for (row = 0; row < height; ++row) { + for (x = 0; x < repeat_x; ++x) { + memcpy(target_buffer, + primary_buffer, primary_stride); + target_buffer += primary_stride; + } + primary_buffer += primary_stride; + } + } + return result; + +#if 0 /* GTK */ + BBitmap *result = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, + width * repeat_x, height * repeat_y); + char *target_buffer = (char *)gdk_pixbuf_get_pixels(result); + int x,y,row; + /* This algorithm won't work if the strides are not multiples */ + assert((size_t)gdk_pixbuf_get_rowstride(result) == + (primary_stride * repeat_x)); + + if (repeat_x == 1 && repeat_y == 1) { + g_object_ref(primary); + g_object_unref(result); + return primary; + } + + for (y = 0; y < repeat_y; ++y) { + char *primary_buffer = (char *)gdk_pixbuf_get_pixels(primary); + for (row = 0; row < height; ++row) { + for (x = 0; x < repeat_x; ++x) { + memcpy(target_buffer, + primary_buffer, primary_stride); + target_buffer += primary_stride; + } + primary_buffer += primary_stride; + } + } + return result; +#endif +} + +/** + * The primary image associated with this bitmap object. + * + * \param bitmap a bitmap, as returned by bitmap_create() + */ +BBitmap * +nsbeos_bitmap_get_primary(struct bitmap* bitmap) +{ + return bitmap->primary; +} + +/** + * The X-pretiled image associated with this bitmap object. + * + * \param bitmap a bitmap, as returned by bitmap_create() + */ +BBitmap * +nsbeos_bitmap_get_pretile_x(struct bitmap* bitmap) +{ + if (!bitmap->pretile_x) { + int width = bitmap->primary->Bounds().Width() + 1; + int xmult = (MIN_PRETILE_WIDTH + width - 1)/width; + LOG(("Pretiling %p for X*%d", bitmap, xmult)); + bitmap->pretile_x = nsbeos_bitmap_generate_pretile(bitmap->primary, xmult, 1); + } + return bitmap->pretile_x; + +} + +/** + * The Y-pretiled image associated with this bitmap object. + * + * \param bitmap a bitmap, as returned by bitmap_create() + */ +BBitmap * +nsbeos_bitmap_get_pretile_y(struct bitmap* bitmap) +{ + if (!bitmap->pretile_y) { + int height = bitmap->primary->Bounds().Height() + 1; + int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height; + LOG(("Pretiling %p for Y*%d", bitmap, ymult)); + bitmap->pretile_y = nsbeos_bitmap_generate_pretile(bitmap->primary, 1, ymult); + } + return bitmap->pretile_y; +} + +/** + * The XY-pretiled image associated with this bitmap object. + * + * \param bitmap a bitmap, as returned by bitmap_create() + */ +BBitmap * +nsbeos_bitmap_get_pretile_xy(struct bitmap* bitmap) +{ + if (!bitmap->pretile_xy) { + int width = bitmap->primary->Bounds().Width() + 1; + int height = bitmap->primary->Bounds().Height() + 1; + int xmult = (MIN_PRETILE_WIDTH + width - 1)/width; + int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height; + LOG(("Pretiling %p for X*%d Y*%d", bitmap, xmult, ymult)); + bitmap->pretile_xy = nsbeos_bitmap_generate_pretile(bitmap->primary, xmult, ymult); + } + return bitmap->pretile_xy; +} diff --git a/beos/beos_bitmap.h b/beos/beos_bitmap.h new file mode 100644 index 000000000..cecff4713 --- /dev/null +++ b/beos/beos_bitmap.h @@ -0,0 +1,34 @@ +/* + * Copyright 2006 Daniel Silverstone + * + * 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 . + */ + +#ifndef NS_BEOS_BITMAP_H +#define NS_BEOS_BITMAP_H + +#include +extern "C" { +#include "image/bitmap.h" +} + +BBitmap *nsbeos_bitmap_get_primary(struct bitmap*); +BBitmap *nsbeos_bitmap_get_pretile_x(struct bitmap*); +BBitmap *nsbeos_bitmap_get_pretile_y(struct bitmap*); +BBitmap *nsbeos_bitmap_get_pretile_xy(struct bitmap*); + + + +#endif /* NS_BEOS_BITMAP_H */ diff --git a/beos/beos_fetch_rsrc.cpp b/beos/beos_fetch_rsrc.cpp new file mode 100644 index 000000000..579953e0d --- /dev/null +++ b/beos/beos_fetch_rsrc.cpp @@ -0,0 +1,371 @@ +/* + * Copyright 2008 Rob Kendrick + * + * This file is part of NetSurf. + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* rsrc: URL handling. */ +#warning XXX: WRITEME + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for URL unescaping functions */ +extern "C" { +#include "utils/config.h" +#include "content/fetch.h" +#include "content/urldb.h" +#include "desktop/netsurf.h" +#include "desktop/options.h" +#include "render/form.h" +#include "utils/log.h" +#include "utils/messages.h" +#include "utils/url.h" +#include "utils/utils.h" +#include "utils/ring.h" +#include "utils/base64.h" +} +#include "beos/beos_fetch_rsrc.h" + +#include +#include + +struct fetch_rsrc_context { + struct fetch *parent_fetch; + char *name; + char *url; + char *mimetype; + char *data; + size_t datalen; + + bool aborted; + bool locked; + + struct fetch_rsrc_context *r_next, *r_prev; +}; + +static struct fetch_rsrc_context *ring = NULL; + +static BResources *gAppResources = NULL; + +static bool fetch_rsrc_initialise(const char *scheme) +{ + LOG(("fetch_rsrc_initialise called for %s", scheme)); + return true; +} + +static void fetch_rsrc_finalise(const char *scheme) +{ + LOG(("fetch_rsrc_finalise called for %s", scheme)); +} + +static void *fetch_rsrc_setup(struct fetch *parent_fetch, const char *url, + bool only_2xx, const char *post_urlenc, + struct form_successful_control *post_multipart, + const char **headers) +{ + struct fetch_rsrc_context *ctx; + ctx = (struct fetch_rsrc_context *)calloc(1, sizeof(*ctx)); + + if (ctx == NULL) + return NULL; + + ctx->parent_fetch = parent_fetch; + ctx->url = strdup(url); + + if (ctx->url == NULL) { + free(ctx); + return NULL; + } + + RING_INSERT(ring, ctx); + + return ctx; +} + +static bool fetch_rsrc_start(void *ctx) +{ + return true; +} + +static void fetch_rsrc_free(void *ctx) +{ + struct fetch_rsrc_context *c = (struct fetch_rsrc_context *)ctx; + + free(c->name); + free(c->url); + free(c->data); + free(c->mimetype); + RING_REMOVE(ring, c); + free(ctx); +} + +static void fetch_rsrc_abort(void *ctx) +{ + struct fetch_rsrc_context *c = (struct fetch_rsrc_context *)ctx; + + /* To avoid the poll loop having to deal with the fetch context + * disappearing from under it, we simply flag the abort here. + * The poll loop itself will perform the appropriate cleanup. + */ + c->aborted = true; +} + +static void fetch_rsrc_send_callback(fetch_msg msg, + struct fetch_rsrc_context *c, const void *data, + unsigned long size) +{ + c->locked = true; + fetch_send_callback(msg, c->parent_fetch, data, size); + c->locked = false; +} + +static bool fetch_rsrc_process(struct fetch_rsrc_context *c) +{ + char *params; + char *at = NULL; + char *slash; + char *comma = NULL; + char *unescaped; + uint32 type = 'data'; // default for embeded files + int32 id = 0; + + /* format of a rsrc: URL is: + * rsrc:[TYPE][@NUM]/name[,mime] + */ + + LOG(("*** Processing %s", c->url)); + + if (strlen(c->url) < 6) { + /* 6 is the minimum possible length (rsrc:/) */ + fetch_rsrc_send_callback(FETCH_ERROR, c, + "Malformed rsrc: URL", 0); + return false; + } + + /* skip the rsrc: part */ + params = c->url + sizeof("rsrc:") - 1; + + /* find the slash */ + if ( (slash = strchr(params, '/')) == NULL) { + fetch_rsrc_send_callback(FETCH_ERROR, c, + "Malformed rsrc: URL", 0); + return false; + } + comma = strchr(slash, ','); + c->name = strdup(slash + 1); + + if (!comma) { + /* there is no mimetype here, assume text/plain */ + c->mimetype = strdup("text/plain;charset=US-ASCII"); + } else { + /* make a copy of everything after the comma */ + c->mimetype = strdup(comma + 1); + c->name[strlen(c->name) - strlen(comma)] = '\0'; + } + + if (c->mimetype == NULL) { + fetch_rsrc_send_callback(FETCH_ERROR, c, + "Unable to allocate memory for mimetype in rsrc: URL", + 0); + return false; + } + + if (params[0] != '/') { + uint8 c1, c2, c3, c4; + if (sscanf(params, "%c%c%c%c", &c1, &c2, &c3, &c4) > 3) { + type = c1 << 24 | c2 << 16 | c3 << 8 | c4; + printf("type:%4.4s\n", &type); + } + } + + fprintf(stderr, "fetch_rsrc: 0x%08lx, %ld, '%s'\n", type, id, c->name); + + bool found; + if (id) + found = gAppResources->HasResource(type, id); + else + found = gAppResources->HasResource(type, c->name); + if (!found) { + fetch_rsrc_send_callback(FETCH_ERROR, c, + "Cannot locate rsrc: URL", + 0); + return false; + } + + size_t len; + const void *data; + if (id) + data = gAppResources->LoadResource(type, id, &len); + else + data = gAppResources->LoadResource(type, c->name, &len); + + if (!data) { + fetch_rsrc_send_callback(FETCH_ERROR, c, + "Cannot load rsrc: URL", + 0); + return false; + } + + c->datalen = len; + c->data = (char *)malloc(c->datalen); + if (c->data == NULL) { + fetch_rsrc_send_callback(FETCH_ERROR, c, + "Unable to allocate memory for rsrc: URL", 0); + return false; + } + memcpy(c->data, data, c->datalen); + + return true; +} + +static void fetch_rsrc_poll(const char *scheme) +{ + struct fetch_rsrc_context *c, *next; + struct cache_data cachedata; + + if (ring == NULL) return; + + cachedata.req_time = time(NULL); + cachedata.res_time = time(NULL); + cachedata.date = 0; + cachedata.expires = 0; + cachedata.age = INVALID_AGE; + cachedata.max_age = 0; + cachedata.no_cache = true; + cachedata.etag = NULL; + cachedata.last_modified = 0; + + /* Iterate over ring, processing each pending fetch */ + c = ring; + do { + /* Take a copy of the next pointer as we may destroy + * the ring item we're currently processing */ + next = c->r_next; + + /* Ignore fetches that have been flagged as locked. + * This allows safe re-entrant calls to this function. + * Re-entrancy can occur if, as a result of a callback, + * the interested party causes fetch_poll() to be called + * again. + */ + if (c->locked == true) { + continue; + } + + /* Only process non-aborted fetches */ + if (!c->aborted && fetch_rsrc_process(c) == true) { + fetch_set_http_code(c->parent_fetch, 200); + LOG(("setting rsrc: MIME type to %s, length to %zd", + c->mimetype, c->datalen)); + /* Any callback can result in the fetch being aborted. + * Therefore, we _must_ check for this after _every_ + * call to fetch_rsrc_send_callback(). + */ + fetch_rsrc_send_callback(FETCH_TYPE, + c, c->mimetype, c->datalen); + if (!c->aborted) { + fetch_rsrc_send_callback(FETCH_DATA, + c, c->data, c->datalen); + } + if (!c->aborted) { + fetch_rsrc_send_callback(FETCH_FINISHED, + c, &cachedata, 0); + } + } else { + LOG(("Processing of %s failed!", c->url)); + + /* Ensure that we're unlocked here. If we aren't, + * then fetch_rsrc_process() is broken. + */ + assert(c->locked == false); + } + + fetch_remove_from_queues(c->parent_fetch); + fetch_free(c->parent_fetch); + + /* Advance to next ring entry, exiting if we've reached + * the start of the ring or the ring has become empty + */ + } while ( (c = next) != ring && ring != NULL); +} + +/* BAppFileInfo is supposed to find the app's resources for us, + * but this won't work if we ever want to be used as a replicant. + * This trick should work regardless, + */ +static int find_app_resources() +{ + image_info info; + const char *path = NULL; + int32 cookie = 0; + while (get_next_image_info(0, &cookie, &info) == B_OK) { +//fprintf(stderr, "%p <> %p, %p\n", (char *)&find_app_resources, (char *)info.text, (char *)info.text + info.text_size); + if (((char *)&find_app_resources >= (char *)info.text) + && ((char *)&find_app_resources < (char *)info.text + info.text_size)) { +//fprintf(stderr, "match\n"); + path = info.name; + break; + } + } + if (path == NULL) + return B_ERROR; + +//fprintf(stderr, "loading resources from '%s'\n", path); + + BFile file(path, B_READ_ONLY); + if (file.InitCheck() < 0) + return file.InitCheck(); + gAppResources = new BResources; + status_t err; + err = gAppResources->SetTo(&file); + if (err >= B_OK) + return B_OK; + delete gAppResources; + gAppResources = NULL; + return err; +} + +void fetch_rsrc_register(void) +{ + int err; + err = find_app_resources(); + if (err < B_OK) { + warn_user("Resources", strerror(err)); + return; + } + fetch_add_fetcher("rsrc", + fetch_rsrc_initialise, + fetch_rsrc_setup, + fetch_rsrc_start, + fetch_rsrc_abort, + fetch_rsrc_free, + fetch_rsrc_poll, + fetch_rsrc_finalise); +} + +void fetch_rsrc_unregister(void) +{ + delete gAppResources; + gAppResources = NULL; +} diff --git a/beos/beos_fetch_rsrc.h b/beos/beos_fetch_rsrc.h new file mode 100644 index 000000000..529a1efeb --- /dev/null +++ b/beos/beos_fetch_rsrc.h @@ -0,0 +1,29 @@ +/* + * Copyright 2008 Rob Kendrick + * + * This file is part of NetSurf. + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** \file + * rsrc: URL method handler + */ + +#ifndef NETSURF_BEOS_FETCH_DATA_H +#define NETSURF_BEOS_FETCH_DATA_H + +void fetch_rsrc_register(void); +void fetch_rsrc_unregister(void); + +#endif diff --git a/beos/beos_filetype.cpp b/beos/beos_filetype.cpp new file mode 100644 index 000000000..a1211eab3 --- /dev/null +++ b/beos/beos_filetype.cpp @@ -0,0 +1,317 @@ +/* + * Copyright 2007 Rob Kendrick + * Copyright 2007 Vincent Sanders + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +extern "C" { +#include "content/fetch.h" +#include "utils/log.h" +#include "utils/hashtable.h" +#include "utils/utils.h" +} + +#include "beos/beos_filetype.h" + +#warning REMOVEME +static struct hash_table *mime_hash = NULL; + +void beos_fetch_filetype_init(const char *mimefile) +{ + BMessage mimes; + status_t err; + + err = BMimeType::GetInstalledTypes(&mimes); + if (err < B_OK) { + warn_user("Mime", strerror(err)); + return; + } + + mime_hash = hash_create(117); + + // just in case + hash_add(mime_hash, "css", "text/css"); + hash_add(mime_hash, "htm", "text/html"); + hash_add(mime_hash, "html", "text/html"); + hash_add(mime_hash, "jpg", "image/jpeg"); + hash_add(mime_hash, "jpeg", "image/jpeg"); + hash_add(mime_hash, "gif", "image/gif"); + hash_add(mime_hash, "png", "image/png"); + hash_add(mime_hash, "jng", "image/jng"); + + + BString type; + int i, j; + //mimes.PrintToStream(); + for (i = 0; mimes.FindString("types", i, &type) >= B_OK; i++) { + BMimeType mime(type.String()); + if (!mime.IsValid()) + continue; + BMessage extensions; + if (mime.GetFileExtensions(&extensions) < B_OK) + continue; + BString ext; + for (j = 0; extensions.FindString("extentions", i, &ext) >= B_OK; i++) { + hash_add(mime_hash, ext.String(), type.String()); + } + } + +#warning WRITEME +#if 0 + struct stat statbuf; + FILE *fh = NULL; + + /* first, check to see if /etc/mime.types in preference */ + + if ((stat("/etc/mime.types", &statbuf) == 0) && + S_ISREG(statbuf.st_mode)) { + mimefile = "/etc/mime.types"; + + } + + fh = fopen(mimefile, "r"); + + /* Some OSes (mentioning no Solarises) have a worthlessly tiny + * /etc/mime.types that don't include essential things, so we + * pre-seed our hash with the essentials. These will get + * over-ridden if they are mentioned in the mime.types file. + */ + + hash_add(mime_hash, "css", "text/css"); + hash_add(mime_hash, "htm", "text/html"); + hash_add(mime_hash, "html", "text/html"); + hash_add(mime_hash, "jpg", "image/jpeg"); + hash_add(mime_hash, "jpeg", "image/jpeg"); + hash_add(mime_hash, "gif", "image/gif"); + hash_add(mime_hash, "png", "image/png"); + hash_add(mime_hash, "jng", "image/jng"); + + if (fh == NULL) { + LOG(("Unable to open a mime.types file, so using a minimal one for you.")); + return; + } + + while (!feof(fh)) { + char line[256], *ptr, *type, *ext; + fgets(line, 256, fh); + if (!feof(fh) && line[0] != '#') { + ptr = line; + + /* search for the first non-whitespace character */ + while (isspace(*ptr)) + ptr++; + + /* is this line empty other than leading whitespace? */ + if (*ptr == '\n' || *ptr == '\0') + continue; + + type = ptr; + + /* search for the first non-whitespace char or NUL or + * NL */ + while (*ptr && (!isspace(*ptr)) && *ptr != '\n') + ptr++; + + if (*ptr == '\0' || *ptr == '\n') { + /* this mimetype has no extensions - read next + * line. + */ + continue; + } + + *ptr++ = '\0'; + + /* search for the first non-whitespace character which + * will be the first filename extenion */ + while (isspace(*ptr)) + ptr++; + + while(true) { + ext = ptr; + + /* search for the first whitespace char or + * NUL or NL which is the end of the ext. + */ + while (*ptr && (!isspace(*ptr)) && + *ptr != '\n') + ptr++; + + if (*ptr == '\0' || *ptr == '\n') { + /* special case for last extension on + * the line + */ + *ptr = '\0'; + hash_add(mime_hash, ext, type); + break; + } + + *ptr++ = '\0'; + hash_add(mime_hash, ext, type); + + /* search for the first non-whitespace char or + * NUL or NL, to find start of next ext. + */ + while (*ptr && (isspace(*ptr)) && *ptr != '\n') + ptr++; + } + } + } + + fclose(fh); +#endif +} + +void beos_fetch_filetype_fin(void) +{ + hash_destroy(mime_hash); +} + +const char *fetch_filetype(const char *unix_path) +{ + struct stat statbuf; + status_t err; + + stat(unix_path, &statbuf); + if (S_ISDIR(statbuf.st_mode)) + return "application/x-netsurf-directory"; + + if (strchr(unix_path, '.') == NULL) { + /* no extension anywhere! */ + return "text/plain"; + } + + // force some types + const char *ext; + ext = strrchr(unix_path, '.'); + if (!strcmp(ext, ".css")) + return "text/css"; + if (!strcmp(ext, ".html")) + return "text/html"; + if (!strcmp(ext, ".htm")) + return "text/html"; + + BNode node(unix_path); + if (node.InitCheck() < B_OK) { + warn_user("Mime", strerror(err)); + return "text/plain"; + } + + BNodeInfo info(&node); + if (info.InitCheck() < B_OK) { + warn_user("Mime", strerror(err)); + return "text/plain"; + } + + // NOT THREADSAFE + static char type[B_MIME_TYPE_LENGTH]; + if (info.GetType(type) < B_OK) { + // it might not have been sniffed yet... + update_mime_info(unix_path, false, true, false); + // try again + if (info.GetType(type) < B_OK) { + warn_user("Mime", strerror(err)); + return "text/plain"; + } + } + + return type; + +#warning WRITEME +#if 0 + struct stat statbuf; + char *ext; + const char *ptr; + char *lowerchar; + const char *type; + + stat(unix_path, &statbuf); + if (S_ISDIR(statbuf.st_mode)) + return "application/x-netsurf-directory"; + + if (strchr(unix_path, '.') == NULL) { + /* no extension anywhere! */ + return "text/plain"; + } + + ptr = unix_path + strlen(unix_path); + while (*ptr != '.' && *ptr != '/') + ptr--; + + if (*ptr != '.') + return "text/plain"; + + ext = strdup(ptr + 1); /* skip the . */ + + /* the hash table only contains lower-case versions - make sure this + * copy is lower case too. + */ + lowerchar = ext; + while(*lowerchar) { + *lowerchar = tolower(*lowerchar); + lowerchar++; + } + + type = hash_get(mime_hash, ext); + free(ext); + + return type != NULL ? type : "text/plain"; +#endif + return NULL; +} + +char *fetch_mimetype(const char *unix_path) +{ + return strdup(fetch_filetype(unix_path)); +} + +#ifdef TEST_RIG + +int main(int argc, char *argv[]) +{ + unsigned int c1, *c2; + const char *key; + + beos_fetch_filetype_init("./mime.types"); + + c1 = 0; c2 = 0; + + while ( (key = hash_iterate(mime_hash, &c1, &c2)) != NULL) { + printf("%s ", key); + } + + printf("\n"); + + if (argc > 1) { + printf("%s maps to %s\n", argv[1], fetch_filetype(argv[1])); + } + + beos_fetch_filetype_fin(); +} + +#endif diff --git a/beos/beos_filetype.h b/beos/beos_filetype.h new file mode 100644 index 000000000..d07ed698a --- /dev/null +++ b/beos/beos_filetype.h @@ -0,0 +1,21 @@ +/* + * Copyright 2007 Rob Kendrick + * Copyright 2007 Vincent Sanders + * + * 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 . + */ + +void beos_fetch_filetype_init(const char *mimefile); +void beos_fetch_filetype_fin(void); diff --git a/beos/beos_font.cpp b/beos/beos_font.cpp new file mode 100644 index 000000000..89c6736fb --- /dev/null +++ b/beos/beos_font.cpp @@ -0,0 +1,556 @@ +/* + * Copyright 2005 James Bursa + * + * 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 . + */ + +/** \file + * Font handling (BeOS implementation). + * TODO: check for correctness, the code is taken from the GTK one. + * maybe use the current view instead of constructing a new BFont each time ? + */ + + +#include +#include +#include +#include +#include +#include +extern "C" { +#include "css/css.h" +#include "render/font.h" +#include "utils/utils.h" +#include "utils/log.h" +#include "desktop/options.h" +} + +#include "beos/beos_gui.h" +#include "beos/beos_font.h" +#include "beos/beos_plotters.h" + +static void nsfont_style_to_font(BFont &font, + const struct css_style *style); + +/** + * Measure the width of a string. + * + * \param style css_style for this text, with style->font_size.size == + * CSS_FONT_SIZE_LENGTH + * \param string UTF-8 string to measure + * \param length length of string + * \param width updated to width of string[0..length) + * \return true on success, false on error and error reported + */ + +bool nsfont_width(const struct css_style *style, + const char *string, size_t length, + int *width) +{ + //fprintf(stderr, "%s(, '%s', %d, )\n", __FUNCTION__, string, length); + BFont font; +#if 0 /* GTK */ + PangoContext *context; + PangoLayout *layout; +#endif + + if (length == 0) { + *width = 0; + return true; + } + + nsfont_style_to_font(font, style); + *width = (int)font.StringWidth(string, length); + return true; +#if 0 /* GTK */ + context = gdk_pango_context_get(); + layout = pango_layout_new(context); + pango_layout_set_font_description(layout, desc); + pango_layout_set_text(layout, string, length); + + pango_layout_get_pixel_size(layout, width, 0); + + g_object_unref(layout); + g_object_unref(context); + pango_font_description_free(desc); +#endif + return true; +} + + +static int utf8_char_len(const char *c) +{ + uint8 *p = (uint8 *)c; + uint8 m = 0xE0; + uint8 v = 0xC0; + int i; + if (!*p) + return 0; + if ((*p & 0x80) == 0) + return 1; + if ((*p & 0xC0) == 0x80) + return 1; // actually one of the remaining bytes... + for (i = 2; i < 5; i++) { + if ((*p & m) == v) + return i; + v = (v >> 1) | 0x80; + m = (m >> 1) | 0x80; + } + return i; +} + +/** + * Find the position in a string where an x coordinate falls. + * + * \param style css_style for this text, with style->font_size.size == + * CSS_FONT_SIZE_LENGTH + * \param string UTF-8 string to measure + * \param length length of string + * \param x x coordinate to search for + * \param char_offset updated to offset in string of actual_x, [0..length] + * \param actual_x updated to x coordinate of character closest to x + * \return true on success, false on error and error reported + */ + +bool nsfont_position_in_string(const struct css_style *style, + const char *string, size_t length, + int x, size_t *char_offset, int *actual_x) +{ + //LOG(("(, '%s', %d, %d, , )", string, length, x)); + //fprintf(stderr, "%s(, '%s', %d, %d, , )\n", __FUNCTION__, string, length, x); + int index; + BFont font; +#if 0 /* GTK */ + PangoFontDescription *desc; + PangoContext *context; + PangoLayout *layout; + PangoRectangle pos; +#endif + + nsfont_style_to_font(font, style); + BString str(string); + int32 len = str.CountChars(); + float escapements[len]; + float esc = 0.0; + float current = 0.0; + int i; + index = 0; + font.GetEscapements(string, len, escapements); + // slow but it should work + for (i = 0; string[index] && i < len; i++) { + if (x < current) + break; + esc += escapements[i]; + current = font.Size() * esc; + index += utf8_char_len(&string[index]); + } + *actual_x = (int)current; + *char_offset = i; //index; +#if 0 /* GTK */ + context = gdk_pango_context_get(); + layout = pango_layout_new(context); + pango_layout_set_font_description(layout, desc); + pango_layout_set_text(layout, string, length); + + pango_layout_xy_to_index(layout, x * PANGO_SCALE, 0, &index, 0); + if (pango_layout_xy_to_index(layout, x * PANGO_SCALE, + 0, &index, 0) == 0) + index = length; + + pango_layout_index_to_pos(layout, index, &pos); + + g_object_unref(layout); + g_object_unref(context); + pango_font_description_free(desc); + + *char_offset = index; + *actual_x = PANGO_PIXELS(pos.x); +#endif + + return true; +} + + +/** + * Find where to split a string to make it fit a width. + * + * \param style css_style for this text, with style->font_size.size == + * CSS_FONT_SIZE_LENGTH + * \param string UTF-8 string to measure + * \param length length of string + * \param x width available + * \param char_offset updated to offset in string of actual_x, [0..length] + * \param actual_x updated to x coordinate of character closest to x + * \return true on success, false on error and error reported + * + * On exit, [char_offset == 0 || + * string[char_offset] == ' ' || + * char_offset == length] + */ + +bool nsfont_split(const struct css_style *style, + const char *string, size_t length, + int x, size_t *char_offset, int *actual_x) +{ + //fprintf(stderr, "%s(, '%s', %d, %d, , )\n", __FUNCTION__, string, length, x); + //LOG(("(, '%s', %d, %d, , )", string, length, x)); + int index = 0; + BFont font; +#if 0 /* GTK */ + PangoFontDescription *desc; + PangoContext *context; + PangoLayout *layout; + PangoLayoutLine *line; + PangoLayoutIter *iter; + PangoRectangle rect; +#endif + + nsfont_style_to_font(font, style); + BString str(string); + int32 len = str.CountChars(); + float escapements[len]; + float esc = 0.0; + float current = 0.0; + float last_x = 0.0; + int i; + int last_space = 0; + font.GetEscapements(string, len, escapements); + // slow but it should work + for (i = 0; string[index] && i < len; i++) { + if (string[index] == ' ') { + last_x = current; + last_space = index; + } + if (x < current) { + *actual_x = (int)last_x; + *char_offset = last_space; + return true; + } + esc += escapements[i]; + current = font.Size() * esc; + index += utf8_char_len(&string[index]); + } + *actual_x = MIN(*actual_x, (int)current); + *char_offset = index; + return true; + +#if 0 /* GTK */ + context = gdk_pango_context_get(); + layout = pango_layout_new(context); + pango_layout_set_font_description(layout, desc); + pango_layout_set_text(layout, string, length); + + pango_layout_set_width(layout, x * PANGO_SCALE); + pango_layout_set_wrap(layout, PANGO_WRAP_WORD); + line = pango_layout_get_line(layout, 1); + if (line) + index = line->start_index - 1; + + iter = pango_layout_get_iter(layout); + pango_layout_iter_get_line_extents(iter, NULL, &rect); + pango_layout_iter_free(iter); + + g_object_unref(layout); + g_object_unref(context); + pango_font_description_free(desc); + + *char_offset = index; + *actual_x = PANGO_PIXELS(rect.width); +#endif + + return true; +} + + +/** + * Render a string. + * + * \param style css_style for this text, with style->font_size.size == + * CSS_FONT_SIZE_LENGTH + * \param string UTF-8 string to measure + * \param length length of string + * \param x x coordinate + * \param y y coordinate + * \param c colour for text + * \return true on success, false on error and error reported + */ + +bool nsfont_paint(const struct css_style *style, + const char *string, size_t length, + int x, int y, colour bg, colour c) +{ + //fprintf(stderr, "%s(, '%s', %d, %d, %d, )\n", __FUNCTION__, string, length, x, y); + //CALLED(); + BFont font; + rgb_color oldbg; + rgb_color background; + rgb_color foreground; + BView *view; + float size; + + if (length == 0) + return true; + + nsfont_style_to_font(font, style); + background = nsbeos_rgb_colour(bg); + foreground = nsbeos_rgb_colour(c); + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + warn_user("No GC", 0); + return false; + } + + oldbg = view->LowColor(); + drawing_mode oldmode = view->DrawingMode(); +#if 0 + if (oldbg != background) + view->SetLowColor(background); +#endif + view->SetLowColor(B_TRANSPARENT_32_BIT); + + //view->SetScale() XXX + +//printf("nsfont_paint: Size: %f\n", font.Size()); + size = (float)(font.Size() * nsbeos_plot_get_scale()); +#warning XXX use scale + + view->SetFont(&font); + view->SetHighColor(foreground); + view->SetDrawingMode(B_OP_OVER); + + BString line(string, length); + + BPoint where(x, y + 1); + view->DrawString(line.String(), where); + + view->SetDrawingMode(oldmode); + if (oldbg != background) + view->SetLowColor(oldbg); + + //nsbeos_current_gc_unlock(); + +#if 0 /* GTK */ + size = (float)((double)pango_font_description_get_size(desc) * nsgtk_plot_get_scale()); + if (pango_font_description_get_size_is_absolute(desc)) + pango_font_description_set_absolute_size(desc, size); + else + pango_font_description_set_size(desc, size); + + PangoFontDescription *desc; + PangoLayout *layout; + gint size; +#ifdef CAIRO_VERSION + int width, height; +#else + PangoLayoutLine *line; + PangoContext *context; + GdkColor colour = { 0, + ((c & 0xff) << 8) | (c & 0xff), + (c & 0xff00) | (c & 0xff00 >> 8), + ((c & 0xff0000) >> 8) | (c & 0xff0000 >> 16) }; +#endif + + if (length == 0) + return true; + + desc = nsfont_style_to_font(font, style); + size = (gint)((double)pango_font_description_get_size(desc) * nsgtk_plot_get_scale()); + if (pango_font_description_get_size_is_absolute(desc)) + pango_font_description_set_absolute_size(desc, size); + else + pango_font_description_set_size(desc, size); + +#ifdef CAIRO_VERSION + layout = pango_cairo_create_layout(current_cr); +#else + context = gdk_pango_context_get(); + layout = pango_layout_new(context); +#endif + + pango_layout_set_font_description(layout, desc); + pango_layout_set_text(layout, string, length); + +#ifdef CAIRO_VERSION + pango_layout_get_pixel_size(layout, &width, &height); + cairo_move_to(current_cr, x, y - height); + nsgtk_set_colour(c); + pango_cairo_show_layout(current_cr, layout); +#else + line = pango_layout_get_line(layout, 0); + gdk_draw_layout_line_with_colors(current_drawable, current_gc, + x, y, line, &colour, 0); + + g_object_unref(context); +#endif + g_object_unref(layout); + pango_font_description_free(desc); +#endif + + return true; +} + + +/** + * Convert a css_style to a PangoFontDescription. + * + * \param style css_style for this text, with style->font_size.size == + * CSS_FONT_SIZE_LENGTH + * \return a new Pango font description + */ + +static void nsfont_style_to_font(BFont &font, + const struct css_style *style) +{ + float size; + uint16 face = 0; + const char *family; +// PangoFontDescription *desc; +// PangoWeight weight = PANGO_WEIGHT_NORMAL; +// PangoStyle styl = PANGO_STYLE_NORMAL; + + assert(style->font_size.size == CSS_FONT_SIZE_LENGTH); + + switch (style->font_family) { + case CSS_FONT_FAMILY_SERIF: + family = option_font_serif; + break; + case CSS_FONT_FAMILY_MONOSPACE: + family = option_font_mono; + break; + case CSS_FONT_FAMILY_CURSIVE: + family = option_font_cursive; + break; + case CSS_FONT_FAMILY_FANTASY: + family = option_font_fantasy; + break; + case CSS_FONT_FAMILY_SANS_SERIF: + default: + family = option_font_sans; + break; + } + + + switch (style->font_style) { + case CSS_FONT_STYLE_ITALIC: + face = B_ITALIC_FACE; + break; + case CSS_FONT_STYLE_OBLIQUE: + face = B_ITALIC_FACE; + // XXX: no OBLIQUE flag ?? + // maybe find "Oblique" style + // or use SetShear() ? + break; + default: + break; + } + + switch (style->font_weight) { + case CSS_FONT_WEIGHT_NORMAL: + break; + case CSS_FONT_WEIGHT_BOLD: + case CSS_FONT_WEIGHT_600: + case CSS_FONT_WEIGHT_700: +#ifndef __HAIKU__XXX + case CSS_FONT_WEIGHT_800: + case CSS_FONT_WEIGHT_900: +#endif + face |= B_BOLD_FACE; break; +#ifdef __HAIKU__XXX + case CSS_FONT_WEIGHT_BOLDER: + case CSS_FONT_WEIGHT_800: + case CSS_FONT_WEIGHT_900: + face |= B_HEAVY_FACE; break; + case CSS_FONT_WEIGHT_100: + case CSS_FONT_WEIGHT_200: + case CSS_FONT_WEIGHT_300: + case CSS_FONT_WEIGHT_LIGHTER: + face |= B_LIGHT_FACE; break; +#endif +/* + case CSS_FONT_WEIGHT_100: weight = 100; break; + case CSS_FONT_WEIGHT_200: weight = 200; break; + case CSS_FONT_WEIGHT_300: weight = 300; break; + case CSS_FONT_WEIGHT_400: weight = 400; break; + case CSS_FONT_WEIGHT_500: weight = 500; break; + case CSS_FONT_WEIGHT_600: weight = 600; break; + case CSS_FONT_WEIGHT_700: weight = 700; break; + case CSS_FONT_WEIGHT_800: weight = 800; break; + case CSS_FONT_WEIGHT_900: weight = 900; break; +*/ + default: break; + } + + if (!face) + face = B_REGULAR_FACE; + +//fprintf(stderr, "nsfont_style_to_font: %d, %d, %d -> '%s' %04x\n", style->font_family, style->font_style, style->font_weight, family, face); + + if (family) + font.SetFamilyAndFace((const font_family)family, face); + else { + //XXX not used + font = be_plain_font; + font.SetFace(face); + } + +#if 0 + *font_size = css_len2px(&style->font_size.value.length, style) * + 72.0 / 90.0 * 16.; + if (*font_size < option_font_min_size * 1.6) + *font_size = option_font_min_size * 1.6; + if (1600 < *font_size) + *font_size = 1600; +#endif + +#if 0 /* GTK */ + if (style->font_size.value.length.unit == CSS_UNIT_PX) + size = style->font_size.value.length.value; + else + size = css_len2pt(&style->font_size.value.length, style); + //XXX ? + if (style->font_size.value.length.unit == CSS_UNIT_PX) + font.SetSize(size); + else + font.SetSize(font.Size() + size); +#endif + +//fprintf(stderr, "nsfont_style_to_font: value %f unit %d\n", style->font_size.value.length.value, style->font_size.value.length.unit); + if (style->font_size.value.length.unit == CSS_UNIT_PT) + size = style->font_size.value.length.value; + else + size = css_len2pt(&style->font_size.value.length, style); + // * 72.0 / 90.0; + + //XXX: pango stuff ? + if (size < abs(option_font_min_size / 10)) + size = option_font_min_size / 10; + +//fprintf(stderr, "nsfont_style_to_font: %f %d\n", size, style->font_size.value.length.unit); + + font.SetSize(size); + + +#if 0 /* GTK */ + switch (style->font_variant) { + case CSS_FONT_VARIANT_SMALL_CAPS: + pango_font_description_set_variant(desc, PANGO_VARIANT_SMALL_CAPS); + break; + case CSS_FONT_VARIANT_NORMAL: + default: + pango_font_description_set_variant(desc, PANGO_VARIANT_NORMAL); + } +#endif +} diff --git a/beos/beos_font.h b/beos/beos_font.h new file mode 100644 index 000000000..06b8edaff --- /dev/null +++ b/beos/beos_font.h @@ -0,0 +1,30 @@ +/* + * Copyright 2005 James Bursa + * + * 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 . + */ + +/** \file + * Font handling (GTK interface). + */ + +#include + + +struct css_style; + +bool nsfont_paint(const struct css_style *style, + const char *string, size_t length, + int x, int y, colour bg, colour c); diff --git a/beos/beos_gui.cpp b/beos/beos_gui.cpp new file mode 100644 index 000000000..601bdb5b6 --- /dev/null +++ b/beos/beos_gui.cpp @@ -0,0 +1,1018 @@ +/* + * Copyright 2005 James Bursa + * + * 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 _GNU_SOURCE /* for strndup */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern "C" { +#include "content/content.h" +#include "content/fetch.h" +#include "content/fetchers/fetch_curl.h" +#include "content/urldb.h" +#include "desktop/401login.h" +#include "desktop/browser.h" +#include "desktop/cookies.h" +#include "desktop/gui.h" +#include "desktop/netsurf.h" +#include "desktop/options.h" + +#include "render/box.h" +#include "render/form.h" +#include "render/html.h" +#include "utils/log.h" +#include "utils/messages.h" +#include "utils/url.h" +#include "utils/utf8.h" +#include "utils/utils.h" +} + +#include "beos/beos_gui.h" + +#include "beos/beos_options.h" +//#include "beos/beos_completion.h" +#include "beos/beos_window.h" +#include "beos/options.h" +#include "beos/beos_throbber.h" +#include "beos/beos_history.h" +#include "beos/beos_filetype.h" +//#include "beos/beos_download.h" +#include "beos/beos_schedule.h" +#include "beos/beos_fetch_rsrc.h" + + +/* Where to search for shared resources. Must have trailing / */ +#define RESPATH "/boot/apps/netsurf/res/" +//TODO: use resources + +bool gui_in_multitask = false; + +char *default_stylesheet_url; +char *adblock_stylesheet_url; +char *options_file_location; +char *glade_file_location; + +struct gui_window *search_current_window = 0; + +BWindow *wndAbout; +BWindow *wndWarning; +//GladeXML *gladeWindows; +BWindow *wndTooltip; +//beosLabel *labelTooltip; +BFilePanel *wndOpenFile; + +//static beosWidget *select_menu; +static struct browser_window *select_menu_bw; +static struct form_control *select_menu_control; + +static thread_id sBAppThreadID; + +static int sEventPipe[2]; + +#if 0 /* GTK */ +static void nsbeos_create_ssl_verify_window(struct browser_window *bw, + struct content *c, const struct ssl_cert_info *certs, + unsigned long num); +static void nsbeos_ssl_accept(BButton *w, gpointer data); +static void nsbeos_ssl_reject(BButton *w, gpointer data); +static void nsbeos_select_menu_clicked(BCheckMenuItem *checkmenuitem, + gpointer user_data); +#endif + +// #pragma mark - class NSBrowserFrameView + + +NSBrowserApplication::NSBrowserApplication() + : BApplication("application/x-vnd.NetSurf") +{ +} + + +NSBrowserApplication::~NSBrowserApplication() +{ +} + + +void +NSBrowserApplication::MessageReceived(BMessage *message) +{ + switch (message->what) { + case B_REFS_RECEIVED: + // messages for top-level + // we'll just send them to the first window + case 'back': + case 'forw': + case 'stop': + case 'relo': + case 'home': + case 'urlc': + case 'urle': + case 'menu': + //DetachCurrentMessage(); + //nsbeos_pipe_message(message, this, fGuiWindow); + break; + default: + BApplication::MessageReceived(message); + } +} + + +void +NSBrowserApplication::RefsReceived(BMessage *message) +{ + DetachCurrentMessage(); + NSBrowserWindow *win = nsbeos_find_last_window(); + if (!win) + return; + win->Unlock(); + nsbeos_pipe_message_top(message, win, win->Scaffolding()); +} + + +bool +NSBrowserApplication::QuitRequested() +{ + // let it notice it + nsbeos_pipe_message(new BMessage(B_QUIT_REQUESTED), NULL, NULL); + // we'll let the main thread Quit() ourselves when it's done. + return false; +} + + +// #pragma mark - implementation + + +// XXX doesn't work +static char *generate_default_css() +{ + BString text; + rgb_color colBg = { 255, 255, 255, 255 }; + rgb_color colFg = { 0, 0, 0, 255 }; + rgb_color colControlBg = { 255, 255, 255, 255 }; + rgb_color colControlFg = { 0, 0, 0, 255 }; + const char *url = "file://beosdefault.css"; + + text << "/*\n"; + text << " * This file is part of NetSurf, http://netsurf-browser.org/\n"; + text << " */\n"; + text << "\n"; + text << "/* Load base stylesheet. */\n"; + text << "\n"; + text << "@import \"default.css\";\n"; + text << "\n"; + text << "/* Apply BeOS specific rules. */\n"; + text << "\n"; + text << "\n"; + text << "\n"; + text << "\n"; + + text << "input { font-size: 95%; border: medium inset #ddd; }\n"; + text << "input[type=button], input[type=reset], input[type=submit], button {\n"; + text << " background-color: #ddd; border: medium outset #ddd; }\n"; + text << "input[type=checkbox], input[type=radio] { font-size: 105%; }\n"; + text << "input[type=file] { background-color: #ddd; border: medium inset #ddd; }\n"; + text << "\n"; + text << "select { background-color: #ddd; border: medium inset #ddd; font-size: 95%; }\n"; + text << "select:after { border-left:4px ridge #ddd; }\n"; + text << "\n"; + text << "textarea { font-size: 95%; border: medium inset #ddd; }\n"; + + struct content *c; + c = content_create(url); + if (c == NULL) + return NULL; + + const char *params[] = { 0 }; + if (!content_set_type(c, CONTENT_CSS, "text/css", params)) + return NULL; + + if (!content_process_data(c, text.String(), text.Length())) + return NULL; + + content_set_done(c); + + return strdup(url); +} + +/** + * Locate a shared resource file by searching known places in order. + * + * \param buf buffer to write to. must be at least PATH_MAX chars + * \param filename file to look for + * \param def default to return if file not found + * \return buf + * + * Search order is: ~/.netsurf/, $NETSURFRES/ (where NETSURFRES is an + * environment variable), and finally the path specified by the #define + * at the top of this file. + */ + +static char *find_resource(char *buf, const char *filename, const char *def) +{ + CALLED(); + char *cdir = getenv("HOME"); + char t[PATH_MAX]; + + if (cdir != NULL) { + strcpy(t, cdir); + strcat(t, "/.netsurf/"); + strcat(t, filename); + realpath(t, buf); + if (access(buf, R_OK) == 0) + return buf; + } + + cdir = getenv("NETSURFRES"); + + if (cdir != NULL) { + realpath(cdir, buf); + strcat(buf, "/"); + strcat(buf, filename); + if (access(buf, R_OK) == 0) + return buf; + } + + strcpy(t, RESPATH); + strcat(t, filename); + realpath(t, buf); + if (access(buf, R_OK) == 0) + return buf; + + if (def[0] == '~') { + snprintf(t, PATH_MAX, "%s%s", getenv("HOME"), def + 1); + realpath(t, buf); + } else { + realpath(def, buf); + } + + return buf; +} + +/** + * Check that ~/.netsurf/ exists, and if it doesn't, create it. + */ +static void check_homedir(void) +{ + CALLED(); +//TODO: use find_directory(); + char *hdir = getenv("HOME"); + char buf[BUFSIZ]; + + if (hdir == NULL) { + /* we really can't continue without a home directory. */ + LOG(("HOME is not set - nowhere to store state!")); + die("NetSurf requires HOME to be set in order to run.\n"); + + } + + snprintf(buf, BUFSIZ, "%s/.netsurf", hdir); + if (access(buf, F_OK) != 0) { + LOG(("You don't have a ~/.netsurf - creating one for you.")); + if (mkdir(buf, 0777) == -1) { + LOG(("Unable to create %s", buf)); + die("NetSurf requires ~/.netsurf to exist, but it cannot be created.\n"); + } + } +} + +static int32 bapp_thread(void *arg) +{ + be_app->Lock(); + be_app->Run(); + return 0; +} + +void gui_init(int argc, char** argv) +{ + char buf[PATH_MAX]; + CALLED(); + + if (pipe(sEventPipe) < 0) + return; + + new NSBrowserApplication; + sBAppThreadID = spawn_thread(bapp_thread, "BApplication(NetSurf)", B_NORMAL_PRIORITY, (void *)find_thread(NULL)); + if (sBAppThreadID < B_OK) + return; /* #### handle errors */ + if (resume_thread(sBAppThreadID) < B_OK) + return; + + fetch_rsrc_register(); + + check_homedir(); + + //nsbeos_completion_init(); + + find_resource(buf, "throbber.gif", "./beos/res/throbber.gif"); + nsbeos_throbber_initialise(buf); + if (nsbeos_throbber == NULL) + die("Unable to load throbber image.\n"); + + find_resource(buf, "Choices", "~/.netsurf/Choices"); + LOG(("Using '%s' as Preferences file", buf)); + options_file_location = strdup(buf); + options_read(buf); + + + /* check what the font settings are, setting them to a default font + * if they're not set - stops Pango whinging + */ +#define SETFONTDEFAULT(x,y) (x) = ((x) != NULL) ? (x) : strdup((y)) + //XXX: use be_plain_font & friends, when we can check if font is serif or not. +/* + font_family family; + font_style style; + be_plain_font->GetFamilyAndStyle(&family, &style); + SETFONTDEFAULT(option_font_sans, family); + SETFONTDEFAULT(option_font_serif, family); + SETFONTDEFAULT(option_font_mono, family); + SETFONTDEFAULT(option_font_cursive, family); + SETFONTDEFAULT(option_font_fantasy, family); +*/ +#ifdef __HAIKU__ + SETFONTDEFAULT(option_font_sans, "DejaVu Sans"); + SETFONTDEFAULT(option_font_serif, "DejaVu Serif"); + SETFONTDEFAULT(option_font_mono, "DejaVu Mono"); + SETFONTDEFAULT(option_font_cursive, "DejaVu Sans"); + SETFONTDEFAULT(option_font_fantasy, "DejaVu Sans"); +#else + SETFONTDEFAULT(option_font_sans, "Bitstream Vera Sans"); + SETFONTDEFAULT(option_font_serif, "Bitstream Vera Serif"); + SETFONTDEFAULT(option_font_mono, "Bitstream Vera Sans Mono"); + SETFONTDEFAULT(option_font_cursive, "Bitstream Vera Serif"); + SETFONTDEFAULT(option_font_fantasy, "Bitstream Vera Serif"); +#if 0 + SETFONTDEFAULT(option_font_sans, "Swis721 BT"); + SETFONTDEFAULT(option_font_serif, "Dutch801 Rm BT"); + //SETFONTDEFAULT(option_font_mono, "Monospac821 BT"); + SETFONTDEFAULT(option_font_mono, "Courier10 BT"); + SETFONTDEFAULT(option_font_cursive, "Swis721 BT"); + SETFONTDEFAULT(option_font_fantasy, "Swis721 BT"); +#endif +#endif + + nsbeos_options_init(); + + if (!option_cookie_file) { + find_resource(buf, "Cookies", "~/.netsurf/Cookies"); + LOG(("Using '%s' as Cookies file", buf)); + option_cookie_file = strdup(buf); + } + if (!option_cookie_jar) { + find_resource(buf, "Cookies", "~/.netsurf/Cookies"); + LOG(("Using '%s' as Cookie Jar file", buf)); + option_cookie_jar = strdup(buf); + } + if (!option_cookie_file || !option_cookie_jar) + die("Failed initialising cookie options"); + + if (!option_url_file) { + find_resource(buf, "URLs", "~/.netsurf/URLs"); + LOG(("Using '%s' as URL file", buf)); + option_url_file = strdup(buf); + } + + if (!option_ca_path) { + find_resource(buf, "certs", "/etc/ssl/certs"); + LOG(("Using '%s' as certificate path", buf)); + option_ca_path = strdup(buf); + } + + find_resource(buf, "messages", "./beos/res/messages"); + LOG(("Using '%s' as Messages file", buf)); + messages_load(buf); + + find_resource(buf, "mime.types", "/etc/mime.types"); + beos_fetch_filetype_init(buf); + + /* set up stylesheet urls */ + find_resource(buf, "beosdefault.css", "./beos/res/beosdefault.css"); + default_stylesheet_url = path_to_url(buf); + //default_stylesheet_url = generate_default_css(); + LOG(("Using '%s' as Default CSS URL", default_stylesheet_url)); + + find_resource(buf, "adblock.css", "./beos/res/adblock.css"); + adblock_stylesheet_url = path_to_url(buf); + LOG(("Using '%s' as AdBlock CSS URL", adblock_stylesheet_url)); + + urldb_load(option_url_file); + urldb_load_cookies(option_cookie_file); + + //nsbeos_history_init(); + //nsbeos_download_initialise(); + + be_app->Unlock(); + +#if 0 /* GTK */ + PangoFontDescription *fontdesc; + + gtk_init(&argc, &argv); + + check_homedir(); + + find_resource(buf, "netsurf.glade", "./beos/res/netsurf.glade"); + LOG(("Using '%s' as Glade template file", buf)); + glade_file_location = strdup(buf); + + glade_init(); + gladeWindows = glade_xml_new(glade_file_location, NULL, NULL); + if (gladeWindows == NULL) + die("Unable to load Glade window definitions.\n"); + glade_xml_signal_autoconnect(gladeWindows); + + find_resource(buf, "netsurf.xpm", "./beos/res/netsurf.xpm"); + beos_window_set_default_icon_from_file(buf, NULL); + + wndTooltip = beos_WINDOW(glade_xml_get_widget(gladeWindows, "wndTooltip")); + labelTooltip = beos_LABEL(glade_xml_get_widget(gladeWindows, "tooltip")); + + nsbeos_completion_init(); + + find_resource(buf, "throbber.gif", "./beos/res/throbber.gif"); + nsbeos_throbber_initialise(buf); + if (nsbeos_throbber == NULL) + die("Unable to load throbber image.\n"); + + find_resource(buf, "Choices", "~/.netsurf/Choices"); + LOG(("Using '%s' as Preferences file", buf)); + options_file_location = strdup(buf); + options_read(buf); + + /* check what the font settings are, setting them to a default font + * if they're not set - stops Pango whinging + */ +#define SETFONTDEFAULT(x,y) (x) = ((x) != NULL) ? (x) : strdup((y)) + SETFONTDEFAULT(option_font_sans, "Sans"); + SETFONTDEFAULT(option_font_serif, "Serif"); + SETFONTDEFAULT(option_font_mono, "Monospace"); + SETFONTDEFAULT(option_font_cursive, "Serif"); + SETFONTDEFAULT(option_font_fantasy, "Serif"); + + nsbeos_options_init(); + + if (!option_cookie_file) { + find_resource(buf, "Cookies", "~/.netsurf/Cookies"); + LOG(("Using '%s' as Cookies file", buf)); + option_cookie_file = strdup(buf); + } + if (!option_cookie_jar) { + find_resource(buf, "Cookies", "~/.netsurf/Cookies"); + LOG(("Using '%s' as Cookie Jar file", buf)); + option_cookie_jar = strdup(buf); + } + if (!option_cookie_file || !option_cookie_jar) + die("Failed initialising cookie options"); + + if (!option_url_file) { + find_resource(buf, "URLs", "~/.netsurf/URLs"); + LOG(("Using '%s' as URL file", buf)); + option_url_file = strdup(buf); + } + + if (!option_ca_path) { + find_resource(buf, "certs", "/etc/ssl/certs"); + LOG(("Using '%s' as certificate path", buf)); + option_ca_path = strdup(buf); + } + + find_resource(buf, "messages", "./beos/res/messages"); + LOG(("Using '%s' as Messages file", buf)); + messages_load(buf); + + find_resource(buf, "mime.types", "/etc/mime.types"); + beos_fetch_filetype_init(buf); + + /* set up stylesheet urls */ + find_resource(buf, "beosdefault.css", "./beos/res/beosdefault.css"); + default_stylesheet_url = path_to_url(buf); + LOG(("Using '%s' as Default CSS URL", default_stylesheet_url)); + + find_resource(buf, "adblock.css", "./beos/res/adblock.css"); + adblock_stylesheet_url = path_to_url(buf); + LOG(("Using '%s' as AdBlock CSS URL", adblock_stylesheet_url)); + + urldb_load(option_url_file); + urldb_load_cookies(option_cookie_file); + + wndAbout = beos_WINDOW(glade_xml_get_widget(gladeWindows, "wndAbout")); + beos_label_set_text(beos_LABEL( + glade_xml_get_widget(gladeWindows, "labelVersion")), + netsurf_version); + beos_image_set_from_file(beos_IMAGE( + glade_xml_get_widget(gladeWindows, "imageLogo")), + find_resource(buf, "netsurf-logo.png", "netsurf-logo.png")); + fontdesc = pango_font_description_from_string("Monospace 8"); + beos_widget_modify_font(beos_WIDGET( + glade_xml_get_widget(gladeWindows, "textviewGPL")), fontdesc); + + wndWarning = beos_WINDOW(glade_xml_get_widget(gladeWindows, "wndWarning")); + wndOpenFile = beos_DIALOG(glade_xml_get_widget(gladeWindows, "wndOpenFile")); + + nsbeos_history_init(); + nsbeos_download_initialise(); +#endif +} + + +void gui_init2(int argc, char** argv) +{ + CALLED(); + const char *addr = "http://netsurf-browser.org/welcome/"; + + if (option_homepage_url != NULL && option_homepage_url[0] != '\0') + addr = option_homepage_url; + + if (argc > 1) addr = argv[1]; + browser_window_create(addr, 0, 0, true); +} + + +void nsbeos_pipe_message(BMessage *message, BView *_this, struct gui_window *gui) +{ + if (message == NULL) { + fprintf(stderr, "%s(NULL)!\n", __FUNCTION__); + return; + } + if (_this) + message->AddPointer("View", _this); + if (gui) + message->AddPointer("gui_window", gui); + int len = write(sEventPipe[1], &message, sizeof(void *)); + //LOG(("nsbeos_pipe_message: %d written", len)); + printf("nsbeos_pipe_message: %d written\n", len); +} + + +void nsbeos_pipe_message_top(BMessage *message, BWindow *_this, struct beos_scaffolding *scaffold) +{ + if (message == NULL) { + fprintf(stderr, "%s(NULL)!\n", __FUNCTION__); + return; + } + if (_this) + message->AddPointer("Window", _this); + if (scaffold) + message->AddPointer("scaffolding", scaffold); + int len = write(sEventPipe[1], &message, sizeof(void *)); + //LOG(("nsbeos_pipe_message: %d written", len)); + printf("nsbeos_pipe_message: %d written\n", len); +} + + +void gui_poll(bool active) +{ + CALLED(); + CURLMcode code; + + fd_set read_fd_set, write_fd_set, exc_fd_set; + int max_fd = 0; + struct timeval timeout; + unsigned int fd_count = 0; + bool block = true; + + if (browser_reformat_pending) + block = false; + + if (active) { + fetch_poll(); + FD_ZERO(&read_fd_set); + FD_ZERO(&write_fd_set); + FD_ZERO(&exc_fd_set); + code = curl_multi_fdset(fetch_curl_multi, + &read_fd_set, + &write_fd_set, + &exc_fd_set, + &max_fd); + assert(code == CURLM_OK); + } + + // our own event pipe + FD_SET(sEventPipe[0], &read_fd_set); + max_fd = MAX(max_fd, sEventPipe[0] + 1); + + + bigtime_t next_schedule = earliest_callback_timeout - system_time(); + timeout.tv_sec = (long)(next_schedule / 1000000LL); + timeout.tv_usec = (long)(next_schedule % 1000000LL); + LOG(("gui_poll: select(%d, ..., %Ldus", max_fd, next_schedule)); + + fd_count = select(max_fd, &read_fd_set, &write_fd_set, &exc_fd_set, + /*block?NULL:*/( + earliest_callback_timeout == B_INFINITE_TIMEOUT) ? NULL : &timeout); + + if (max_fd > 0 && FD_ISSET(sEventPipe[0], &read_fd_set)) { + BMessage *message; + int len = read(sEventPipe[0], &message, sizeof(void *)); + LOG(("gui_poll: BMessage ? %d read", len)); + if (len == sizeof(void *)) + nsbeos_dispatch_event(message); + } + + +/* + for (unsigned int i = 0; fd_count && i < max_fd; i++) { + g_main_context_remove_poll(0, fd_list[i]); + free(fd_list[i]); + fd_count--; + } +*/ + +#if 0 /* GTK */ + CURLMcode code; + fd_set read_fd_set, write_fd_set, exc_fd_set; + int max_fd; + GPollFD *fd_list[1000]; + unsigned int fd_count = 0; + bool block = true; + + if (browser_reformat_pending) + block = false; + + if (active) { + fetch_poll(); + FD_ZERO(&read_fd_set); + FD_ZERO(&write_fd_set); + FD_ZERO(&exc_fd_set); + code = curl_multi_fdset(fetch_curl_multi, + &read_fd_set, + &write_fd_set, + &exc_fd_set, + &max_fd); + assert(code == CURLM_OK); + for (int i = 0; i <= max_fd; i++) { + if (FD_ISSET(i, &read_fd_set)) { + GPollFD *fd = malloc(sizeof *fd); + fd->fd = i; + fd->events = G_IO_IN | G_IO_HUP | G_IO_ERR; + g_main_context_add_poll(0, fd, 0); + fd_list[fd_count++] = fd; + } + if (FD_ISSET(i, &write_fd_set)) { + GPollFD *fd = malloc(sizeof *fd); + fd->fd = i; + fd->events = G_IO_OUT | G_IO_ERR; + g_main_context_add_poll(0, fd, 0); + fd_list[fd_count++] = fd; + } + if (FD_ISSET(i, &exc_fd_set)) { + GPollFD *fd = malloc(sizeof *fd); + fd->fd = i; + fd->events = G_IO_ERR; + g_main_context_add_poll(0, fd, 0); + fd_list[fd_count++] = fd; + } + } + } + + beos_main_iteration_do(block); + + for (unsigned int i = 0; i != fd_count; i++) { + g_main_context_remove_poll(0, fd_list[i]); + free(fd_list[i]); + } +#endif + + schedule_run(); + + if (browser_reformat_pending) + nsbeos_window_process_reformats(); +} + + +void gui_multitask(void) +{ + gui_in_multitask = true; +#if 0 /* GTK */ + while (beos_events_pending()) + beos_main_iteration(); +#endif + gui_in_multitask = false; +} + + +void gui_quit(void) +{ + CALLED(); + urldb_save_cookies(option_cookie_jar); + urldb_save(option_url_file); + free(default_stylesheet_url); + free(adblock_stylesheet_url); + free(option_cookie_file); + free(option_cookie_jar); + beos_fetch_filetype_fin(); + fetch_rsrc_unregister(); +} + + + +struct gui_download_window *gui_download_window_create(const char *url, + const char *mime_type, struct fetch *fetch, + unsigned int total_size) +{ + return 0; +} + + +void gui_download_window_data(struct gui_download_window *dw, const char *data, + unsigned int size) +{ +} + + +void gui_download_window_error(struct gui_download_window *dw, + const char *error_msg) +{ +} + + +void gui_download_window_done(struct gui_download_window *dw) +{ +} + +#if 0 /* GTK */ +static void nsbeos_select_menu_clicked(BCheckMenuItem *checkmenuitem, + gpointer user_data) +{ + browser_window_form_select(select_menu_bw, select_menu_control, + (intptr_t)user_data); +} +#endif + +void gui_create_form_select_menu(struct browser_window *bw, + struct form_control *control) +{ + CALLED(); +#if 0 /* GTK */ + + intptr_t i; + struct form_option *option; + + beosWidget *menu_item; + + /* control->data.select.multiple is true if multiple selections + * are allowable. We ignore this, as the core handles it for us. + * Yay. \o/ + */ + + if (select_menu != NULL) + beos_widget_destroy(select_menu); + + select_menu = beos_menu_new(); + select_menu_bw = bw; + select_menu_control = control; + + for (i = 0, option = control->data.select.items; option; + i++, option = option->next) { + menu_item = beos_check_menu_item_new_with_label(option->text); + if (option->selected) + beos_check_menu_item_set_active( + beos_CHECK_MENU_ITEM(menu_item), TRUE); + + g_signal_connect(menu_item, "toggled", + G_CALLBACK(nsbeos_select_menu_clicked), (gpointer)i); + + beos_menu_shell_append(beos_MENU_SHELL(select_menu), menu_item); + } + + beos_widget_show_all(select_menu); + + beos_menu_popup(beos_MENU(select_menu), NULL, NULL, NULL, + NULL /* data */, 0, beos_get_current_event_time()); + +#endif +} + +void gui_window_save_as_link(struct gui_window *g, struct content *c) +{ +} + +/** + * Broadcast an URL that we can't handle. + */ + +void gui_launch_url(const char *url) +{ + status_t status; + // try to open it as an URI + BString mimeType = "application/x-vnd.Be.URL."; + BString arg(url); + mimeType.Append(arg, arg.FindFirst(":")); + + // the protocol should be alphanum + // we just check if it's registered + // if not there is likely no supporting app anyway + if (!BMimeType::IsValid(mimeType.String())) + return; + char *args[2] = { (char *)url, NULL }; + status = be_roster->Launch(mimeType.String(), 1, args); + if (status < B_OK) + warn_user("Cannot launch url", strerror(status)); +} + + +bool gui_search_term_highlighted(struct gui_window *g, + unsigned start_offset, unsigned end_offset, + unsigned *start_idx, unsigned *end_idx) +{ + return false; +} + + +/** + * Display a warning for a serious problem (eg memory exhaustion). + * + * \param warning message key for warning message + * \param detail additional message, or 0 + */ + +void warn_user(const char *warning, const char *detail) +{ + LOG(("warn_user: %s (%s)", warning, detail)); + BAlert *alert; + BString text(warning); + if (detail) + text << ":\n" << detail; +#if 0 + alert = new BAlert("NetSurf Warning", text.String(), "Ok", NULL, NULL, + B_WIDTH_AS_USUAL, B_WARNING_ALERT); + alert->Go(); +#else + alert = new BAlert("NetSurf Warning", text.String(), "Debug", "Ok", NULL, + B_WIDTH_AS_USUAL, B_WARNING_ALERT); + if (alert->Go() < 1) + debugger("warn_user"); +#endif +} + +void die(const char * const error) +{ + fprintf(stderr, "%s", error); + BAlert *alert; + BString text("Cannot continue:\n"); + text << error; +#if 0 + alert = new BAlert("NetSurf Error", text.String(), "Ok", NULL, NULL, + B_WIDTH_AS_USUAL, B_STOP_ALERT); + alert->Go(); +#else + alert = new BAlert("NetSurf Error", text.String(), "Debug", "Ok", NULL, + B_WIDTH_AS_USUAL, B_STOP_ALERT); + if (alert->Go() < 1) + debugger("die"); +#endif + exit(EXIT_FAILURE); +} + + +void hotlist_visited(struct content *content) +{ +} + +void gui_cert_verify(struct browser_window *bw, struct content *c, + const struct ssl_cert_info *certs, unsigned long num) +{ + CALLED(); +#if 0 /* GTK */ + nsbeos_create_ssl_verify_window(bw, c, certs, num); +#endif +} + +static void nsbeos_create_ssl_verify_window(struct browser_window *bw, + struct content *c, const struct ssl_cert_info *certs, + unsigned long num) +{ + CALLED(); +#if 0 /* GTK */ + GladeXML *x = glade_xml_new(glade_file_location, NULL, NULL); + beosWindow *wnd = beos_WINDOW(glade_xml_get_widget(x, "wndSSLProblem")); + beosButton *accept, *reject; + void **session = calloc(sizeof(void *), 4); + + session[0] = bw; + session[1] = strdup(c->url); + session[2] = x; + session[3] = wnd; + + accept = beos_BUTTON(glade_xml_get_widget(x, "sslaccept")); + reject = beos_BUTTON(glade_xml_get_widget(x, "sslreject")); + + g_signal_connect(G_OBJECT(accept), "clicked", + G_CALLBACK(nsbeos_ssl_accept), (gpointer)session); + g_signal_connect(G_OBJECT(reject), "clicked", + G_CALLBACK(nsbeos_ssl_reject), (gpointer)session); + + beos_widget_show(beos_WIDGET(wnd)); +#endif +} + +#if 0 /* GTK */ +static void nsbeos_ssl_accept(beosButton *w, gpointer data) +{ + void **session = data; + struct browser_window *bw = session[0]; + char *url = session[1]; + GladeXML *x = session[2]; + beosWindow *wnd = session[3]; + + urldb_set_cert_permissions(url, true); + browser_window_go(bw, url, 0, true); + + beos_widget_destroy(beos_WIDGET(wnd)); + g_object_unref(G_OBJECT(x)); + free(url); + free(session); +} + +static void nsbeos_ssl_reject(beosButton *w, gpointer data) +{ + void **session = data; + GladeXML *x = session[2]; + beosWindow *wnd = session[3]; + + beos_widget_destroy(beos_WIDGET(wnd)); + g_object_unref(G_OBJECT(x)); + free(session[1]); + free(session); +} +#endif + +utf8_convert_ret utf8_to_local_encoding(const char *string, size_t len, + char **result) +{ + assert(string && result); + + if (len == 0) + len = strlen(string); + + *result = strndup(string, len); + if (!(*result)) + return UTF8_CONVERT_NOMEM; + + return UTF8_CONVERT_OK; +} + +utf8_convert_ret utf8_from_local_encoding(const char *string, size_t len, + char **result) +{ + assert(string && result); + + if (len == 0) + len = strlen(string); + + *result = strndup(string, len); + if (!(*result)) + return UTF8_CONVERT_NOMEM; + + return UTF8_CONVERT_OK; +} + +char *path_to_url(const char *path) +{ + char *r = (char *)malloc(strlen(path) + 7 + 1); + + strcpy(r, "file://"); + strcat(r, path); + + return r; +} + +char *url_to_path(const char *url) +{ + return strdup(url + 5); +} + +bool cookies_update(const char *domain, const struct cookie_data *data) +{ + return true; +} diff --git a/beos/beos_gui.h b/beos/beos_gui.h new file mode 100644 index 000000000..0e9f1e266 --- /dev/null +++ b/beos/beos_gui.h @@ -0,0 +1,57 @@ +/* + * Copyright 2005 James Bursa + * + * 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 . + */ + +#include +#include +#include +#include + +#define CALLED() fprintf(stderr, "%s()\n", __FUNCTION__); + +extern bool gui_in_multitask; +#if 0 /* GTK */ +//extern GladeXML *gladeWindows; +//extern char *glade_file_location; +#endif +extern char *options_file_location; + +class NSBrowserApplication : public BApplication { +public: + NSBrowserApplication(); +virtual ~NSBrowserApplication(); + +virtual void MessageReceived(BMessage *message); +virtual void RefsReceived(BMessage *message); + +virtual bool QuitRequested(); +}; + + + +extern BWindow *wndAbout; + +extern BWindow *wndTooltip; +#if 0 /* GTK */ +//extern GtkLabel *labelTooltip; +#endif + +extern BFilePanel *wndOpenFile; + +void nsbeos_pipe_message(BMessage *message, BView *_this, struct gui_window *gui); +void nsbeos_pipe_message_top(BMessage *message, BWindow *_this, struct beos_scaffolding *scaffold); + diff --git a/beos/beos_history.cpp b/beos/beos_history.cpp new file mode 100644 index 000000000..07413f3c8 --- /dev/null +++ b/beos/beos_history.cpp @@ -0,0 +1,181 @@ +/* + * 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 . + */ + +extern "C" { +#include "utils/log.h" +#include "content/urldb.h" +} + +#include "beos/beos_history.h" +#include "beos/beos_gui.h" +#include "beos/beos_window.h" + +#include +#include + + +enum +{ + COL_TITLE = 0, + COL_ADDRESS, + COL_LASTVISIT, + COL_TOTALVISITS, + COL_THUMBNAIL, + COL_NCOLS +}; + +BWindow *wndHistory; +#warning XXX +#if 0 /* GTK */ +static GtkTreeView *treeview; +static GtkTreeStore *history_tree; +static GtkTreeSelection *selection; + +static bool nsgtk_history_add_internal(const char *, const struct url_data *); +static void nsgtk_history_selection_changed(GtkTreeSelection *, gpointer); +#endif + +void nsgtk_history_init(void) +{ +#warning XXX +#if 0 /* GTK */ + GtkCellRenderer *renderer; + + wndHistory = GTK_WINDOW(glade_xml_get_widget(gladeWindows, + "wndHistory")); + treeview = GTK_TREE_VIEW(glade_xml_get_widget(gladeWindows, + "treeHistory")); + history_tree = gtk_tree_store_new(COL_NCOLS, + G_TYPE_STRING, /* title */ + G_TYPE_STRING, /* address */ + G_TYPE_STRING, /* last visit */ + G_TYPE_INT, /* nr. visits */ + GDK_TYPE_PIXBUF); /* thumbnail */ + + selection = gtk_tree_view_get_selection(treeview); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); + g_signal_connect(G_OBJECT(selection), "changed", + G_CALLBACK(nsgtk_history_selection_changed), NULL); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(treeview, -1, "Title", + renderer, + "text", + COL_TITLE, + NULL); + + gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(history_tree)); + +#endif + nsbeos_history_update(); +} + +void nsbeos_history_update(void) +{ +#warning XXX +#if 0 /* GTK */ + gtk_tree_store_clear(history_tree); + urldb_iterate_entries(nsgtk_history_add_internal); +#endif +} + +bool nsbeos_history_add_internal(const char *url, const struct url_data *data) +{ +#warning XXX +#if 0 /* GTK */ + GtkTreeIter iter; + + if (data->visits > 0) + { + gtk_tree_store_append(history_tree, &iter, NULL); + gtk_tree_store_set(history_tree, &iter, + COL_TITLE, data->title, + COL_ADDRESS, url, + COL_LASTVISIT, "Unknown", + COL_TOTALVISITS, data->visits, + -1); + } + +#endif + return true; +} + +#warning XXX +#if 0 /* GTK */ +void nsgtk_history_selection_changed(GtkTreeSelection *treesel, gpointer g) +{ + GtkTreeIter iter; + GtkTreeModel *model = GTK_TREE_MODEL(history_tree); + if (gtk_tree_selection_get_selected(treesel, &model, &iter)) + { + gchar *b; + gint i; + char buf[20]; + + gtk_tree_model_get(model, &iter, COL_ADDRESS, &b, -1); + gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(gladeWindows, + "labelHistoryAddress")), b); + + gtk_tree_model_get(model, &iter, COL_LASTVISIT, &b, -1); + gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(gladeWindows, + "labelHistoryLastVisit")), b); + + gtk_tree_model_get(model, &iter, COL_TOTALVISITS, + &i, -1); + snprintf(buf, 20, "%d", i); + gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(gladeWindows, + "labelHistoryVisits")), buf); + + + + } + else + { + + } +} + +void nsgtk_history_row_activated(GtkTreeView *tv, GtkTreePath *path, + GtkTreeViewColumn *column, gpointer g) +{ + GtkTreeModel *model; + GtkTreeIter iter; + + model = gtk_tree_view_get_model(tv); + if (gtk_tree_model_get_iter(model, &iter, path)) + { + gchar *b; + + gtk_tree_model_get(model, &iter, COL_ADDRESS, &b, -1); + + browser_window_create((const char *)b, NULL, NULL, true); + } +} +#endif + +void global_history_add(const char *url) +{ + const struct url_data *data; + + data = urldb_get_url_data(url); + if (!data) + return; + + nsbeos_history_add_internal(url, data); + +} diff --git a/beos/beos_history.h b/beos/beos_history.h new file mode 100644 index 000000000..c11a73873 --- /dev/null +++ b/beos/beos_history.h @@ -0,0 +1,35 @@ +/* + * 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 . + */ + +#ifndef __NSBEOS_HISTORY_H__ +#define __NSBEOS_HISTORY_H__ + +#include +#include + +extern BWindow *wndHistory; + +void nsbeos_history_init(void); +void nsbeos_history_update(void); +#warning XXX +#if 0 /* GTK */ +void nsbeos_history_row_activated(GtkTreeView *, GtkTreePath *, + GtkTreeViewColumn *, gpointer); +#endif + +#endif /* __NSGTK_HISTORY_H__ */ diff --git a/beos/beos_login.cpp b/beos/beos_login.cpp new file mode 100644 index 000000000..da1433b1c --- /dev/null +++ b/beos/beos_login.cpp @@ -0,0 +1,192 @@ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +extern "C" { +#include "utils/log.h" +#include "content/content.h" +#include "content/urldb.h" +#include "desktop/browser.h" +#include "desktop/401login.h" +#include "desktop/gui.h" +#include "utils/messages.h" +#include "utils/url.h" +#include "utils/utils.h" +} +#include "beos/beos_gui.h" + +struct session_401 { + char *url; /**< URL being fetched */ + char *host; /**< Host for user display */ + char *realm; /**< Authentication realm */ + struct browser_window *bw; /**< Browser window handle */ +#warning WRITEME +#if 0 /* GTK */ + GladeXML *x; /**< Our glade windows */ + GtkWindow *wnd; /**< The login window itself */ + GtkEntry *user; /**< Widget with username */ + GtkEntry *pass; /**< Widget with password */ +#endif +}; + +static void create_login_window(struct browser_window *bw, const char *host, + const char *realm, const char *fetchurl); +static void destroy_login_window(struct session_401 *session); +#warning WRITEME +#if 0 /* GTK */ +static void nsgtk_login_next(GtkWidget *w, gpointer data); +static void nsgtk_login_ok_clicked(GtkButton *w, gpointer data); +static void nsgtk_login_cancel_clicked(GtkButton *w, gpointer data); +#endif + +void gui_401login_open(struct browser_window *bw, struct content *c, + const char *realm) +{ + char *host; + url_func_result res; + + res = url_host(c->url, &host); + assert(res == URL_FUNC_OK); + + create_login_window(bw, host, realm, c->url); + + free(host); +} + +void create_login_window(struct browser_window *bw, const char *host, + const char *realm, const char *fetchurl) +{ + struct session_401 *session; + +#warning WRITEME +#if 0 /* GTK */ + /* create a new instance of the login window, and get handles to all + * the widgets we're interested in. + */ + + GladeXML *x = glade_xml_new(glade_file_location, NULL, NULL); + GtkWindow *wnd = GTK_WINDOW(glade_xml_get_widget(x, "wndLogin")); + GtkLabel *lhost, *lrealm; + GtkEntry *euser, *epass; + GtkButton *bok, *bcan; + + lhost = GTK_LABEL(glade_xml_get_widget(x, "labelLoginHost")); + lrealm = GTK_LABEL(glade_xml_get_widget(x, "labelLoginRealm")); + euser = GTK_ENTRY(glade_xml_get_widget(x, "entryLoginUser")); + epass = GTK_ENTRY(glade_xml_get_widget(x, "entryLoginPass")); + bok = GTK_BUTTON(glade_xml_get_widget(x, "buttonLoginOK")); + bcan = GTK_BUTTON(glade_xml_get_widget(x, "buttonLoginCan")); + + /* create and fill in our session structure */ + + session = calloc(1, sizeof(struct session_401)); + session->url = strdup(fetchurl); + session->host = strdup(host); + session->realm = strdup(realm ? realm : "Secure Area"); + session->bw = bw; + session->x = x; + session->wnd = wnd; + session->user = euser; + session->pass = epass; + + /* fill in our new login window */ + + gtk_label_set_text(GTK_LABEL(lhost), host); + gtk_label_set_text(lrealm, realm); + gtk_entry_set_text(euser, ""); + gtk_entry_set_text(epass, ""); + + /* attach signal handlers to the Login and Cancel buttons in our new + * window to call functions in this file to process the login + */ + g_signal_connect(G_OBJECT(bok), "clicked", + G_CALLBACK(nsgtk_login_ok_clicked), (gpointer)session); + g_signal_connect(G_OBJECT(bcan), "clicked", + G_CALLBACK(nsgtk_login_cancel_clicked), + (gpointer)session); + + /* attach signal handlers to the entry boxes such that pressing + * enter in one progresses the focus onto the next widget. + */ + + g_signal_connect(G_OBJECT(euser), "activate", + G_CALLBACK(nsgtk_login_next), (gpointer)epass); + g_signal_connect(G_OBJECT(epass), "activate", + G_CALLBACK(nsgtk_login_next), (gpointer)bok); + + /* make sure the username entry box currently has the focus */ + gtk_widget_grab_focus(GTK_WIDGET(euser)); + + /* finally, show the window */ + gtk_widget_show(GTK_WIDGET(wnd)); +#endif +} + +void destroy_login_window(struct session_401 *session) +{ + free(session->url); + free(session->host); + free(session->realm); +#warning WRITEME +#if 0 /* GTK */ + gtk_widget_destroy(GTK_WIDGET(session->wnd)); + g_object_unref(G_OBJECT(session->x)); +#endif + free(session); +} + +#warning WRITEME +#if 0 /* GTK */ +void nsgtk_login_next(GtkWidget *w, gpointer data) +{ + gtk_widget_grab_focus(GTK_WIDGET(data)); +} + +void nsgtk_login_ok_clicked(GtkButton *w, gpointer data) +{ + /* close the window and destroy it, having continued the fetch + * assoicated with it. + */ + + struct session_401 *session = (struct session_401 *)data; + const gchar *user = gtk_entry_get_text(session->user); + const gchar *pass = gtk_entry_get_text(session->pass); + char *auth; + + auth = malloc(strlen(user) + strlen(pass) + 2); + sprintf(auth, "%s:%s", user, pass); + urldb_set_auth_details(session->url, session->realm, auth); + free(auth); + + browser_window_go(session->bw, session->url, 0, true); + + destroy_login_window(session); +} + +void nsgtk_login_cancel_clicked(GtkButton *w, gpointer data) +{ + /* just close and destroy the window */ + destroy_login_window((struct session_401 *)data); +} +#endif diff --git a/beos/beos_options.cpp b/beos/beos_options.cpp new file mode 100644 index 000000000..c56c38a43 --- /dev/null +++ b/beos/beos_options.cpp @@ -0,0 +1,273 @@ +/* + * 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 . + */ + +#include +#include +#include +extern "C" { +#include "utils/log.h" +#include "desktop/options.h" +} +#include "beos/options.h" +#include "beos/beos_gui.h" +#include "beos/beos_scaffolding.h" +#include "beos/beos_options.h" +//#include "beos/beos_window.h" +#include +#include + +BWindow *wndPreferences; + +#if 0 /* GTK */ +GtkWindow *wndPreferences; + +static GtkWidget *entryHomePageURL, + *checkHideAdverts, + *checkDisablePopups, + *checkDisablePlugins, + *spinHistoryAge, + *checkHoverURLs, + *checkRequestOverwrite, + *checkDisplayRecentURLs, + *checkSendReferer, + + *comboProxyType, + *entryProxyHost, + *entryProxyPort, + *entryProxyUser, + *entryProxyPassword, + *spinMaxFetchers, + *spinFetchesPerHost, + *spinCachedConnections, + + *checkUseCairo, + *checkResampleImages, + *spinAnimationSpeed, + *checkDisableAnimations, + + *fontSansSerif, + *fontSerif, + *fontMonospace, + *fontCursive, + *fontFantasy, + *comboDefault, + *spinDefaultSize, + *spinMinimumSize, + + *spinMemoryCacheSize, + *spinDiscCacheAge; + +#define FIND_WIDGET(x) (x) = glade_xml_get_widget(gladeWindows, #x); if ((x) == NULL) LOG(("Unable to find widget '%s'!", #x)) +#endif + +void nsbeos_options_init(void) { +#if 0 /* GTK */ + wndPreferences = GTK_WINDOW(glade_xml_get_widget(gladeWindows, + "wndPreferences")); + + /* get widget objects */ + FIND_WIDGET(entryHomePageURL); + FIND_WIDGET(checkHideAdverts); + FIND_WIDGET(checkDisablePopups); + FIND_WIDGET(checkDisablePlugins); + FIND_WIDGET(spinHistoryAge); + FIND_WIDGET(checkHoverURLs); + FIND_WIDGET(checkRequestOverwrite); + FIND_WIDGET(checkDisplayRecentURLs); + FIND_WIDGET(checkSendReferer); + + FIND_WIDGET(comboProxyType); + FIND_WIDGET(entryProxyHost); + FIND_WIDGET(entryProxyPort); + FIND_WIDGET(entryProxyUser); + FIND_WIDGET(entryProxyPassword); + FIND_WIDGET(spinMaxFetchers); + FIND_WIDGET(spinFetchesPerHost); + FIND_WIDGET(spinCachedConnections); + + FIND_WIDGET(checkUseCairo); + FIND_WIDGET(checkResampleImages); + FIND_WIDGET(spinAnimationSpeed); + FIND_WIDGET(checkDisableAnimations); + + FIND_WIDGET(fontSansSerif); + FIND_WIDGET(fontSerif); + FIND_WIDGET(fontMonospace); + FIND_WIDGET(fontCursive); + FIND_WIDGET(fontFantasy); + FIND_WIDGET(comboDefault); + FIND_WIDGET(spinDefaultSize); + FIND_WIDGET(spinMinimumSize); + + FIND_WIDGET(spinMemoryCacheSize); + FIND_WIDGET(spinDiscCacheAge); + +#endif + /* set the widgets to reflect the current options */ + nsbeos_options_load(); +} + +#if 0 /* GTK */ +#define SET_ENTRY(x, y) gtk_entry_set_text(GTK_ENTRY((x)), (y)) +#define SET_SPIN(x, y) gtk_spin_button_set_value(GTK_SPIN_BUTTON((x)), (y)) +#define SET_CHECK(x, y) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON((x)), (y)) +#define SET_COMBO(x, y) gtk_combo_box_set_active(GTK_COMBO_BOX((x)), (y)) +#define SET_FONT(x, y) gtk_font_button_set_font_name(GTK_FONT_BUTTON((x)), (y)) +#endif + +void nsbeos_options_load(void) { +#warning WRITEME +#if 0 /* GTK */ + char b[20]; + int proxytype = 0; + + SET_ENTRY(entryHomePageURL, + option_homepage_url ? option_homepage_url : ""); + SET_CHECK(checkHideAdverts, option_block_ads); + SET_CHECK(checkDisplayRecentURLs, option_url_suggestion); + SET_CHECK(checkSendReferer, option_send_referer); + + switch (option_http_proxy_auth) { + case OPTION_HTTP_PROXY_AUTH_NONE: + proxytype = 1; + break; + case OPTION_HTTP_PROXY_AUTH_BASIC: + proxytype = 2; + break; + case OPTION_HTTP_PROXY_AUTH_NTLM: + proxytype = 3; + break; + } + + if (option_http_proxy == false) + proxytype = 0; + + SET_COMBO(comboProxyType, proxytype); + SET_ENTRY(entryProxyHost, + option_http_proxy_host ? option_http_proxy_host : ""); + snprintf(b, 20, "%d", option_http_proxy_port); + SET_ENTRY(entryProxyPort, b); + SET_ENTRY(entryProxyUser, option_http_proxy_auth_user ? + option_http_proxy_auth_user : ""); + SET_ENTRY(entryProxyPassword, option_http_proxy_auth_pass ? + option_http_proxy_auth_pass : ""); + + SET_SPIN(spinMaxFetchers, option_max_fetchers); + SET_SPIN(spinFetchesPerHost, option_max_fetchers_per_host); + SET_SPIN(spinCachedConnections, option_max_cached_fetch_handles); + + SET_CHECK(checkUseCairo, option_render_cairo); + SET_CHECK(checkResampleImages, option_render_resample); + SET_SPIN(spinAnimationSpeed, option_minimum_gif_delay / 100); + SET_CHECK(checkDisableAnimations, !option_animate_images); + + SET_FONT(fontSansSerif, option_font_sans); + SET_FONT(fontSerif, option_font_serif); + SET_FONT(fontMonospace, option_font_mono); + SET_FONT(fontCursive, option_font_cursive); + SET_FONT(fontFantasy, option_font_fantasy); + SET_COMBO(comboDefault, option_font_default - 1); + SET_SPIN(spinDefaultSize, option_font_size / 10); + SET_SPIN(spinMinimumSize, option_font_min_size / 10); + + SET_SPIN(spinMemoryCacheSize, option_memory_cache_size >> 20); + SET_SPIN(spinDiscCacheAge, option_disc_cache_age); +#endif +} + +#if 0 /* GTK */ +#define GET_ENTRY(x, y) if ((y)) free((y)); \ + (y) = strdup(gtk_entry_get_text(GTK_ENTRY((x)))) +#define GET_CHECK(x, y) (y) = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON((x))) +#define GET_SPIN(x, y) (y) = gtk_spin_button_get_value(GTK_SPIN_BUTTON((x))) +#define GET_COMBO(x, y) (y) = gtk_combo_box_get_active(GTK_COMBO_BOX((x))) +#define GET_FONT(x, y) if ((y)) free((y)); \ + (y) = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON((x)))) +#endif + +void nsbeos_options_save(void) { +#warning WRITEME +#if 0 /* GTK */ + char *b = NULL; + int i; + + GET_ENTRY(entryHomePageURL, option_homepage_url); + GET_CHECK(checkDisplayRecentURLs, option_url_suggestion); + + GET_COMBO(comboProxyType, i); + LOG(("proxy type: %d", i)); + switch (i) + { + case 0: + option_http_proxy = false; + option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_NONE; + break; + case 1: + option_http_proxy = true; + option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_NONE; + break; + case 2: + option_http_proxy = true; + option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_BASIC; + break; + case 3: + option_http_proxy = true; + option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_NTLM; + break; + default: + option_http_proxy = false; + option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_NONE; + break; + } + + GET_ENTRY(entryProxyHost, option_http_proxy_host); + GET_ENTRY(entryProxyPort, b); + option_http_proxy_port = atoi(b); + free(b); + GET_ENTRY(entryProxyUser, option_http_proxy_auth_user); + GET_ENTRY(entryProxyPassword, option_http_proxy_auth_pass); + + GET_SPIN(spinMaxFetchers, option_max_fetchers); + GET_SPIN(spinFetchesPerHost, option_max_fetchers_per_host); + GET_SPIN(spinCachedConnections, option_max_cached_fetch_handles); + + GET_CHECK(checkUseCairo, option_render_cairo); + GET_CHECK(checkResampleImages, option_render_resample); + GET_SPIN(spinAnimationSpeed, option_minimum_gif_delay); + option_minimum_gif_delay *= 100; + + GET_FONT(fontSansSerif, option_font_sans); + GET_FONT(fontSerif, option_font_serif); + GET_FONT(fontMonospace, option_font_mono); + GET_FONT(fontCursive, option_font_cursive); + GET_FONT(fontFantasy, option_font_fantasy); + GET_COMBO(comboDefault, option_font_default); + option_font_default++; + + GET_SPIN(spinDefaultSize, option_font_size); + option_font_size *= 10; + GET_SPIN(spinMinimumSize, option_font_min_size); + option_font_min_size *= 10; + + GET_SPIN(spinMemoryCacheSize, option_memory_cache_size); + option_memory_cache_size <<= 20; + + options_write(options_file_location); + nsgtk_reflow_all_windows(); +#endif +} diff --git a/beos/beos_options.h b/beos/beos_options.h new file mode 100644 index 000000000..e5605a922 --- /dev/null +++ b/beos/beos_options.h @@ -0,0 +1,33 @@ +/* + * 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 . + */ + +#ifndef NETSURF_BEOS_OPTIONS_H +#define NETSURF_BEOS_OPTIONS_H + +#include + +#if 0 /* GTK */ +extern GtkWindow *wndPreferences; +#endif +extern BWindow *wndPreferences; + +void nsbeos_options_init(void); /** Init options and load window */ +void nsbeos_options_load(void); /** Load current options into window */ +void nsbeos_options_save(void); /** Save options from window */ + +#endif diff --git a/beos/beos_plotters.cpp b/beos/beos_plotters.cpp new file mode 100644 index 000000000..0cfee16a0 --- /dev/null +++ b/beos/beos_plotters.cpp @@ -0,0 +1,753 @@ +/* + * Copyright 2006 Rob Kendrick + * Copyright 2005 James Bursa + * + * 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 . + */ + +/** \file + * Target independent plotting (BeOS/Haiku implementation). + */ + +#include +#include +#include +#include +#include +#include +extern "C" { +#include "desktop/plotters.h" +#include "render/font.h" +#include "utils/log.h" +#include "utils/utils.h" +#include "desktop/options.h" +} +#include "beos/beos_font.h" +#include "beos/beos_gui.h" +#include "beos/beos_plotters.h" +//#include "beos/beos_scaffolding.h" +//#include "beos/options.h" +#include "beos/beos_bitmap.h" + +#warning MAKE ME static +/*static*/ BView *current_view; + +#if 0 /* GTK */ +GtkWidget *current_widget; +GdkDrawable *current_drawable; +GdkGC *current_gc; +#ifdef CAIRO_VERSION +cairo_t *current_cr; +#endif +#endif + +static bool nsbeos_plot_clg(colour c); +static bool nsbeos_plot_rectangle(int x0, int y0, int width, int height, + int line_width, colour c, bool dotted, bool dashed); +static bool nsbeos_plot_line(int x0, int y0, int x1, int y1, int width, + colour c, bool dotted, bool dashed); +static bool nsbeos_plot_polygon(int *p, unsigned int n, colour fill); +static bool nsbeos_plot_path(float *p, unsigned int n, colour fill, float width, + colour c, float *transform); +static bool nsbeos_plot_fill(int x0, int y0, int x1, int y1, colour c); +static bool nsbeos_plot_clip(int clip_x0, int clip_y0, + int clip_x1, int clip_y1); +static bool nsbeos_plot_text(int x, int y, const struct css_style *style, + const char *text, size_t length, colour bg, colour c); +static bool nsbeos_plot_disc(int x, int y, int radius, colour c, bool filled); +static bool nsbeos_plot_arc(int x, int y, int radius, int angle1, int angle2, + colour c); +static bool nsbeos_plot_bitmap(int x, int y, int width, int height, + struct bitmap *bitmap, colour bg); +static bool nsbeos_plot_bitmap_tile(int x, int y, int width, int height, + struct bitmap *bitmap, colour bg, + bool repeat_x, bool repeat_y); + +#if 0 /* GTK */ +static GdkRectangle cliprect; +#endif +static float nsbeos_plot_scale = 1.0; + +#warning make patterns nicer +static const pattern kDottedPattern = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa }; +static const pattern kDashedPattern = { 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33 }; + +static const rgb_color kBlackColor = { 0, 0, 0, 255 }; + +struct plotter_table plot; + +const struct plotter_table nsbeos_plotters = { + nsbeos_plot_clg, + nsbeos_plot_rectangle, + nsbeos_plot_line, + nsbeos_plot_polygon, + nsbeos_plot_fill, + nsbeos_plot_clip, + nsbeos_plot_text, + nsbeos_plot_disc, + nsbeos_plot_arc, + nsbeos_plot_bitmap, + nsbeos_plot_bitmap_tile, + NULL, + NULL, + NULL, + nsbeos_plot_path +}; + + +BView *nsbeos_current_gc(void) +{ + return current_view; +} + +BView *nsbeos_current_gc_lock(void) +{ + BView *view = current_view; + if (view && view->LockLooper()) + return view; + return NULL; +} + +void nsbeos_current_gc_unlock(void) +{ + if (current_view) + current_view->UnlockLooper(); +} + +void nsbeos_current_gc_set(BView *view) +{ + // XXX: (un)lock previous ? + current_view = view; +} + + +bool nsbeos_plot_clg(colour c) +{ +#warning BView::Invalidate() ? + return true; +} + +bool nsbeos_plot_rectangle(int x0, int y0, int width, int height, + int line_width, colour c, bool dotted, bool dashed) +{ + pattern pat = B_SOLID_HIGH; + BView *view; + + if (dotted) + pat = kDottedPattern; + else if (dashed) + pat = kDashedPattern; + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + warn_user("No GC", 0); + return false; + } + + nsbeos_set_colour(c); + + BRect rect(x0, y0, x0 + width - 1, y0 + height - 1); + view->StrokeRect(rect, pat); + + //nsbeos_current_gc_unlock(); + +#if 0 /* GTK */ +#ifdef CAIRO_VERSION + if (option_render_cairo) { + if (line_width == 0) + line_width = 1; + + cairo_set_line_width(current_cr, line_width); + cairo_rectangle(current_cr, x0, y0, width, height); + cairo_stroke(current_cr); + } else +#endif + gdk_draw_rectangle(current_drawable, current_gc, + FALSE, x0, y0, width, height); + return true; +#endif +} + + +bool nsbeos_plot_line(int x0, int y0, int x1, int y1, int width, + colour c, bool dotted, bool dashed) +{ + pattern pat = B_SOLID_HIGH; + BView *view; + + if (dotted) + pat = kDottedPattern; + else if (dashed) + pat = kDashedPattern; + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + warn_user("No GC", 0); + return false; + } + + nsbeos_set_colour(c); + + BPoint start(x0, y0); + BPoint end(x1, y1); + view->StrokeLine(start, end, pat); + + //nsbeos_current_gc_unlock(); + +#if 0 /* GTK */ +#ifdef CAIRO_VERSION + if (option_render_cairo) { + if (width == 0) + width = 1; + + cairo_set_line_width(current_cr, width); + cairo_move_to(current_cr, x0, y0 - 0.5); + cairo_line_to(current_cr, x1, y1 - 0.5); + cairo_stroke(current_cr); + } else +#endif + gdk_draw_line(current_drawable, current_gc, + x0, y0, x1, y1); +#endif + return true; +} + + +bool nsbeos_plot_polygon(int *p, unsigned int n, colour fill) +{ + unsigned int i; + BView *view; + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + warn_user("No GC", 0); + return false; + } + + rgb_color color = nsbeos_rgb_colour(fill); + + view->BeginLineArray(n); + + for (i = 0; i < n; i++) { + BPoint start(p[2 * i], p[2 * i + 1]); + BPoint end(p[(2 * i + 2) % n], p[(2 * i + 3) % n]); + view->AddLine(start, end, color); + } + + view->EndLineArray(); + + //nsbeos_current_gc_unlock(); + +#if 0 /* GTK */ + nsbeos_set_colour(fill); + nsbeos_set_solid(); +#ifdef CAIRO_VERSION + if (option_render_cairo) { + cairo_set_line_width(current_cr, 0); + cairo_move_to(current_cr, p[0], p[1]); + for (i = 1; i != n; i++) { + cairo_line_to(current_cr, p[i * 2], p[i * 2 + 1]); + } + cairo_fill(current_cr); + cairo_stroke(current_cr); + } else +#endif + { + GdkPoint q[n]; + for (i = 0; i != n; i++) { + q[i].x = p[i * 2]; + q[i].y = p[i * 2 + 1]; + } + gdk_draw_polygon(current_drawable, current_gc, + TRUE, q, n); + } +#endif + return true; +} + + +bool nsbeos_plot_fill(int x0, int y0, int x1, int y1, colour c) +{ + BView *view; + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + warn_user("No GC", 0); + return false; + } + + nsbeos_set_colour(c); + + BRect rect(x0, y0, x1, y1); + view->FillRect(rect); + + //nsbeos_current_gc_unlock(); + +#if 0 /* GTK */ + nsbeos_set_colour(c); + nsbeos_set_solid(); +#ifdef CAIRO_VERSION + if (option_render_cairo) { + cairo_set_line_width(current_cr, 0); + cairo_rectangle(current_cr, x0, y0, x1 - x0, y1 - y0); + cairo_fill(current_cr); + cairo_stroke(current_cr); + } else +#endif + gdk_draw_rectangle(current_drawable, current_gc, + TRUE, x0, y0, x1 - x0, y1 - y0); +#endif + return true; +} + + +bool nsbeos_plot_clip(int clip_x0, int clip_y0, + int clip_x1, int clip_y1) +{ + BView *view; + //fprintf(stderr, "%s(%d, %d, %d, %d)\n", __FUNCTION__, clip_x0, clip_y0, clip_x1, clip_y1); + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + warn_user("No GC", 0); + return false; + } + + BRect rect(clip_x0, clip_y0, clip_x1, clip_y1); + BRegion clip(rect); + view->ConstrainClippingRegion(NULL); + if (view->Bounds() != rect) + view->ConstrainClippingRegion(&clip); + + + //nsbeos_current_gc_unlock(); + +#if 0 /* GTK */ +#ifdef CAIRO_VERSION + if (option_render_cairo) { + cairo_reset_clip(current_cr); + cairo_rectangle(current_cr, clip_x0, clip_y0, + clip_x1 - clip_x0, clip_y1 - clip_y0); + cairo_clip(current_cr); + } +#endif + cliprect.x = clip_x0; + cliprect.y = clip_y0; + cliprect.width = clip_x1 - clip_x0; + cliprect.height = clip_y1 - clip_y0; + gdk_gc_set_clip_rectangle(current_gc, &cliprect); +#endif + return true; +} + + +bool nsbeos_plot_text(int x, int y, const struct css_style *style, + const char *text, size_t length, colour bg, colour c) +{ + return nsfont_paint(style, text, length, x, y, bg, c); +} + + +bool nsbeos_plot_disc(int x, int y, int radius, colour c, bool filled) +{ + BView *view; + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + warn_user("No GC", 0); + return false; + } + + nsbeos_set_colour(c); + + BPoint center(x, y); + if (filled) + view->FillEllipse(center, radius, radius); + else + view->StrokeEllipse(center, radius, radius); + + //nsbeos_current_gc_unlock(); + +#if 0 /* GTK */ + nsbeos_set_colour(c); + nsbeos_set_solid(); +#ifdef CAIRO_VERSION + if (option_render_cairo) { + if (filled) + cairo_set_line_width(current_cr, 0); + else + cairo_set_line_width(current_cr, 1); + + cairo_arc(current_cr, x, y, radius, 0, M_PI * 2); + + if (filled) + cairo_fill(current_cr); + + cairo_stroke(current_cr); + } else +#endif + gdk_draw_arc(current_drawable, current_gc, + filled ? TRUE : FALSE, x - (radius), y - radius, + radius * 2, radius * 2, + 0, + 360 * 64); + +#endif + return true; +} + +bool nsbeos_plot_arc(int x, int y, int radius, int angle1, int angle2, colour c) +{ + BView *view; + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + warn_user("No GC", 0); + return false; + } + + nsbeos_set_colour(c); + + BPoint center(x, y); + float angle = angle1; // in degree + float span = angle2 - angle1; // in degree + view->StrokeArc(center, radius, radius, angle, span); + + //nsbeos_current_gc_unlock(); + +#if 0 /* GTK */ + nsbeos_set_colour(c); + nsbeos_set_solid(); +#ifdef CAIRO_VERSION + if (option_render_cairo) { + cairo_set_line_width(current_cr, 1); + cairo_arc(current_cr, x, y, radius, + (angle1 + 90) * (M_PI / 180), + (angle2 + 90) * (M_PI / 180)); + cairo_stroke(current_cr); + } else +#endif + gdk_draw_arc(current_drawable, current_gc, + FALSE, x - (radius), y - radius, + radius * 2, radius * 2, + angle1 * 64, angle2 * 64); + +#endif + return true; +} + +static bool nsbeos_plot_bbitmap(int x, int y, int width, int height, + BBitmap *b, colour bg) +{ + /* XXX: This currently ignores the background colour supplied. + * Does this matter? + */ + + if (width == 0 || height == 0) + return true; + + BView *view; + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + warn_user("No GC", 0); + return false; + } + + drawing_mode oldmode = view->DrawingMode(); + view->SetDrawingMode(B_OP_OVER); + + // XXX DrawBitmap() resamples if rect doesn't match, + // but doesn't do any filtering + // XXX: use Zeta API if available ? + + BRect rect(x, y, x + width - 1, y + height - 1); + rgb_color old = view->LowColor(); + if (bg != TRANSPARENT) { + view->SetLowColor(nsbeos_rgb_colour(bg)); + view->FillRect(rect, B_SOLID_LOW); + } + view->DrawBitmap(b, rect); + // maybe not needed? + view->SetLowColor(old); + view->SetDrawingMode(oldmode); + + //nsbeos_current_gc_unlock(); + +#if 0 /* GTK */ + /* XXX: This currently ignores the background colour supplied. + * Does this matter? + */ + + if (width == 0 || height == 0) + return true; + + if (gdk_pixbuf_get_width(pixbuf) == width && + gdk_pixbuf_get_height(pixbuf) == height) { + gdk_draw_pixbuf(current_drawable, current_gc, + pixbuf, + 0, 0, + x, y, + width, height, + GDK_RGB_DITHER_MAX, 0, 0); + + } else { + GdkPixbuf *scaled; + scaled = gdk_pixbuf_scale_simple(pixbuf, + width, height, + option_render_resample ? GDK_INTERP_BILINEAR + : GDK_INTERP_NEAREST); + if (!scaled) + return false; + + gdk_draw_pixbuf(current_drawable, current_gc, + scaled, + 0, 0, + x, y, + width, height, + GDK_RGB_DITHER_MAX, 0, 0); + + g_object_unref(scaled); + } + +#endif + return true; +} + +bool nsbeos_plot_bitmap(int x, int y, int width, int height, + struct bitmap *bitmap, colour bg) +{ + BBitmap *b = nsbeos_bitmap_get_primary(bitmap); + return nsbeos_plot_bbitmap(x, y, width, height, b, bg); +#if 0 /* GTK */ + GdkPixbuf *pixbuf = gtk_bitmap_get_primary(bitmap); + return nsbeos_plot_pixbuf(x, y, width, height, pixbuf, bg); +#endif +} + +bool nsbeos_plot_bitmap_tile(int x, int y, int width, int height, + struct bitmap *bitmap, colour bg, + bool repeat_x, bool repeat_y) +{ + int doneheight = 0, donewidth = 0; + BBitmap *primary; + BBitmap *pretiled; + + if (!(repeat_x || repeat_y)) { + /* Not repeating at all, so just pass it on */ + return nsbeos_plot_bitmap(x,y,width,height,bitmap,bg); + } + + if (repeat_x && !repeat_y) + pretiled = nsbeos_bitmap_get_pretile_x(bitmap); + if (repeat_x && repeat_y) + pretiled = nsbeos_bitmap_get_pretile_xy(bitmap); + if (!repeat_x && repeat_y) + pretiled = nsbeos_bitmap_get_pretile_y(bitmap); + primary = nsbeos_bitmap_get_primary(bitmap); + /* use the primary and pretiled widths to scale the w/h provided */ + width *= pretiled->Bounds().Width() + 1; + width /= primary->Bounds().Width() + 1; + height *= pretiled->Bounds().Height() + 1; + height /= primary->Bounds().Height() + 1; + + BView *view; + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + warn_user("No GC", 0); + return false; + } + + // XXX: do we really need to use clipping reg ? + // I guess it's faster to not draw clipped out stuff... + + BRect cliprect; + BRegion clipreg; + view->GetClippingRegion(&clipreg); + cliprect = clipreg.Frame(); + + //XXX: FIXME + + if (y > cliprect.top) + doneheight = ((int)cliprect.top - height) + ((y - (int)cliprect.top) % height); + else + doneheight = y; + + while (doneheight < ((int)cliprect.bottom)) { + if (x > cliprect.left) + donewidth = ((int)cliprect.left - width) + ((x - (int)cliprect.left) % width); + else + donewidth = x; + while (donewidth < (cliprect.right)) { + nsbeos_plot_bbitmap(donewidth, doneheight, + width, height, pretiled, bg); + donewidth += width; + if (!repeat_x) break; + } + doneheight += height; + if (!repeat_y) break; + } + +#warning WRITEME +#if 0 /* GTK */ + int doneheight = 0, donewidth = 0; + GdkPixbuf *primary; + GdkPixbuf *pretiled; + + if (!(repeat_x || repeat_y)) { + /* Not repeating at all, so just pass it on */ + return nsbeos_plot_bitmap(x,y,width,height,bitmap,bg); + } + + if (repeat_x && !repeat_y) + pretiled = gtk_bitmap_get_pretile_x(bitmap); + if (repeat_x && repeat_y) + pretiled = gtk_bitmap_get_pretile_xy(bitmap); + if (!repeat_x && repeat_y) + pretiled = gtk_bitmap_get_pretile_y(bitmap); + primary = gtk_bitmap_get_primary(bitmap); + /* use the primary and pretiled widths to scale the w/h provided */ + width *= gdk_pixbuf_get_width(pretiled); + width /= gdk_pixbuf_get_width(primary); + height *= gdk_pixbuf_get_height(pretiled); + height /= gdk_pixbuf_get_height(primary); + + if (y > cliprect.y) + doneheight = (cliprect.y - height) + ((y - cliprect.y) % height); + else + doneheight = y; + + while (doneheight < (cliprect.y + cliprect.height)) { + if (x > cliprect.x) + donewidth = (cliprect.x - width) + ((x - cliprect.x) % width); + else + donewidth = x; + while (donewidth < (cliprect.x + cliprect.width)) { + nsbeos_plot_pixbuf(donewidth, doneheight, + width, height, pretiled, bg); + donewidth += width; + if (!repeat_x) break; + } + doneheight += height; + if (!repeat_y) break; + } + + +#endif + return true; +} + +bool nsbeos_plot_path(float *p, unsigned int n, colour fill, float width, + colour c, float *transform) +{ +#warning WRITEME +#if 0 /* GTK */ + /* Only the internal SVG renderer uses this plot call currently, + * and the GTK version uses librsvg. Thus, we ignore this complexity, + * and just return true obliviously. + */ + +#endif + return true; +} + +rgb_color nsbeos_rgb_colour(colour c) +{ + rgb_color color; + if (c == TRANSPARENT) + return B_TRANSPARENT_32_BIT; + color.red = c & 0x0000ff; + color.green = (c & 0x00ff00) >> 8; + color.blue = (c & 0xff0000) >> 16; + return color; +} + +void nsbeos_set_colour(colour c) +{ + rgb_color color = nsbeos_rgb_colour(c); + BView *view = nsbeos_current_gc(); + view->SetHighColor(color); +#if 0 /* GTK */ + int r, g, b; + GdkColor colour; + + r = c & 0xff; + g = (c & 0xff00) >> 8; + b = (c & 0xff0000) >> 16; + + colour.red = r | (r << 8); + colour.green = g | (g << 8); + colour.blue = b | (b << 8); + colour.pixel = (r << 16) | (g << 8) | b; + + gdk_color_alloc(gdk_colormap_get_system(), + &colour); + gdk_gc_set_foreground(current_gc, &colour); +#ifdef CAIRO_VERSION + if (option_render_cairo) + cairo_set_source_rgba(current_cr, r / 255.0, + g / 255.0, b / 255.0, 1.0); +#endif +#endif +} + +void nsbeos_plot_set_scale(float s) +{ + nsbeos_plot_scale = s; +} + +float nsbeos_plot_get_scale(void) +{ + return nsbeos_plot_scale; +} + +/** Plot a caret. It is assumed that the plotters have been set up. */ +void nsbeos_plot_caret(int x, int y, int h) +{ + BView *view; + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) + /* TODO: report an error here */ + return; + + BPoint start(x, y); + BPoint end(x, y + h - 1); +#if defined(__HAIKU__) || defined(B_BEOS_VERSION_DANO) + view->SetHighColor(ui_color(B_DOCUMENT_TEXT_COLOR)); +#else + view->SetHighColor(kBlackColor); +#endif + view->StrokeLine(start, end); + + //nsbeos_current_gc_unlock(); + +#if 0 /* GTK */ + GdkColor colour; + + colour.red = 0; + colour.green = 0; + colour.blue = 0; + colour.pixel = 0; + gdk_color_alloc(gdk_colormap_get_system(), + &colour); + gdk_gc_set_foreground(current_gc, &colour); + + gdk_draw_line(current_drawable, current_gc, + x, y, + x, y + h - 1); +#endif +} diff --git a/beos/beos_plotters.h b/beos/beos_plotters.h new file mode 100644 index 000000000..9530c4b7e --- /dev/null +++ b/beos/beos_plotters.h @@ -0,0 +1,57 @@ +/* + * Copyright 2005 James Bursa + * + * 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 . + */ + +/** \file + * Target independent plotting (BeOS interface). + */ + +#ifndef NETSURF_BEOS_PLOTTERS_H +#define NETSURF_BEOS_PLOTTERS_H 1 + +extern "C" { + +struct plotter_table; + +extern const struct plotter_table nsbeos_plotters; + +} + +#include + +extern BView *current_view; +#if 0 /* GTK */ +extern GtkWidget *current_widget; +extern GdkDrawable *current_drawable; +extern GdkGC *current_gc; +#ifdef CAIRO_VERSION +extern cairo_t *current_cr; +#endif +#endif + +extern BView *nsbeos_current_gc(void); +extern BView *nsbeos_current_gc_lock(void); +extern void nsbeos_current_gc_unlock(void); +extern void nsbeos_current_gc_set(BView *view); + +void nsbeos_plot_set_scale(float s); +float nsbeos_plot_get_scale(void); +rgb_color nsbeos_rgb_colour(colour c); +void nsbeos_set_colour(colour c); +void nsbeos_plot_caret(int x, int y, int h); + +#endif /* NETSURF_GTK_PLOTTERS_H */ diff --git a/beos/beos_res.rdef b/beos/beos_res.rdef new file mode 100644 index 000000000..641098bb4 --- /dev/null +++ b/beos/beos_res.rdef @@ -0,0 +1,350 @@ +/* +** /boot/home/beos_res.rdef +** +** Automatically generated by BResourceParser on +** Saturday, May 17, 2008 at 23:10:33. +** +*/ + +enum { + R_ResBackNavActive = 1042, + R_ResBackNavInactive = 1043, + R_ResForwNavActive = 1044, + R_ResForwNavInactive = 1045, + R_ResUpNavActive = 1046, + R_ResUpNavInactive = 1047, + R_ResBackNavActiveSel = 1048, + R_ResForwNavActiveSel = 1049, + R_ResUpNavActiveSel = 1050 +}; + + +//resource(123, "beosdefault.css") import beos/beosdefault.css; +//resource(123, "beosdefault.css") #'PNG ' import "beos/res/beosdefault.css"; +//import(123, "beosdefault.css") "beos/beosdefault.css"; +//resource(123, "beos/beosdefault.css") #'PNG ' read("beos/beosdefault.css"); + +resource(1, "BEOS:APP_FLAGS") (#'APPF') $"01000000"; + +resource(1, "BEOS:L:STD_ICON") #'ICON' array { + $"FFFFFFFFFFFFFFFFFFFFFF0E0A00D600D6000AAF0EFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFF0E0A000001DED5D5D5DE020000090EFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFF0B0001B58D6666666C6C6C6C93B50200090EFFFFFFFFFFFFFF" + $"FFFFFFFFFF0E0000016D66666666666C6C6C6C6C6C6CB40104AFFFFFFFFFFFFF" + $"FFFFFFFF0E0001B503464666666666666C6C6C6C6C6C6C9303000DFFFFFFFFFF" + $"FFFFFF0E000267AEB5464666666666666C6C6C6C66666C7292DE000DFFFFFFFF" + $"FFFFFF070167464666464646666666666C666C6C1F1F66664092DE000EFFFFFF" + $"FFFF0B008E46464646464646666666666C403F1E3F3F3F3F6692930100FFFFFF" + $"FFFF00074646668D46464666666666666C663F3F3F3F3F3F6672927E000EFFFF" + $"FF0B006D6646670246464666666666666C663F3F3F3F3F3F3F1E6C923D00FFFF" + $"FF00D56666668E044646666666666666403F3F3F3F3F3F3F1F6692927E000EFF" + $"0E008E666666678E666666666666666C6C661E3F3F3F3F3F1D92929293000BFF" + $"0B016C66666666666666666666666C6C6C6C403F3F3F3F3F3F6C929292DE00FF" + $"08036C666666666666666666666C6C6C6C6C1E1D403F1E6C666C929292DD00FF" + $"00D56C6C66668D06666666666C6C6C6C6C6C6C6C6C1D667292929292927E03FF" + $"00D56C6C6C6C8D02666C6C6C6C6C6C6C6C6C6C6C6C6C729292929292927E03FF" + $"00D56C6C6C6C6CDE6C6C6C6C6C6C6C6C6C6C6C6C7272729292929292927E03FF" + $"00DE6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C7272729292929292925F0103FF" + $"09026C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C72727292929292929293010100FF" + $"0B008D6C6C6C6C8DD56C6C6C6C6C6C6C6C72727272929292929292927E3D29FF" + $"0E00B46C6C6C6C6C01936C6C6C6C6C6C72727292929292927E7E92925F000BFF" + $"FF00DE6C6C6C6C6CB5B46C6C6C6C727272729292929292DE297E9292DD020EFF" + $"FF0C0002B4726C6C6C6C7272727272727292B4DD7F929293929292920100FFFF" + $"FFFF00007F7272B4DDDD927293DDDEB49292DEDDB3929292929292DD000EFFFF" + $"FFFFAF00B4727293B47FDEB4937E7E93929292929292929292925F0009FFFFFF" + $"FFFFFF0A00B4929292929301939292929292929292929292925F0100FFFFFFFF" + $"FFFFFFFF0700B4929292927E9392929292929292929292925F01000EFFFFFFFF" + $"FFFFFFFFFF0700DD9292929292929292929292929292927E01000EFFFFFFFFFF" + $"FFFFFFFFFFFF0A003D7E9292927E7E9292929292925FDE00000EFFFFFFFFFFFF" + $"FFFFFFFFFFFFFF0D00003D7F5F5F017E92925F7EDE000300FFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFF0D00030000000001010000000C0EFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFF0E0B000A0A0A0D0EFFFFFFFFFFFFFFFFFFFFFFFF" +}; + +resource(101, "BEOS:M:STD_ICON") #'MICN' array { + $"FFFFFFFF0E0900020205000DFFFFFFFF" + $"FFFFFF09038E66666C6C93DD000EFFFF" + $"FFFF00B5AE4666666C6C666CB4050EFF" + $"FF098E464646666666401D4066B400FF" + $"0E05668E664666666C1E3F3F1D6CDDAF" + $"098E668E66666666661F3F3F1E729300" + $"006C66666666666C6C401E1E40729204" + $"026C6CB46C666C6C6C6C6C66929292DE" + $"026C6C8D6C6C6C6C6C6C72729292923D" + $"006C6C6C8D6C6C6C6C72729292927E04" + $"09946C6CB56C6C6C72729292DD935F00" + $"0E009492B49293B492B47E929292DE0D" + $"FF0A7F92937F939392929292927E00FF" + $"FFFF08DD92929292929292927E00FFFF" + $"FFFFFF0B017E93DD92927EDE09FFFFFF" + $"FFFFFFFF0E0B000500000A0EFFFFFFFF" +}; + +resource(1, "BEOS:APP_SIG") (#'MIMS') "application/x-vnd.NetSurf"; + +resource(1, "BEOS:FILE_TYPES") message { + "types" = "text/html", + "types" = "image/gif", + "types" = "image/jpeg", + "types" = "application/x-vnd.Be-bookmark", + "types" = "text", + "types" = "application/x-vnd.Be-doc_bookmark", + "types" = "application/x-vnd.Be.URL.file", + "types" = "application/x-vnd.Be.URL.ftp", + "types" = "application/x-vnd.Be.URL.http", + "types" = "application/x-vnd.Be.URL.https" +}; + +resource(R_ResBackNavActive) archive(, 0x00000000) BBitmap { + "_frame" = rect { 0.0, 0.0, 18.0, 16.0 }, + "_cspace" = 4, + "_bmflags" = 1, + "_rowbytes" = 20, + "_data" = array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFF3B3B18FFFF" + $"FFFFFFFFFFFFFF3FFFFFFFFFFFFF3B353B1418FFFFFFFFFFFFFFFF3FFFFFFFFF" + $"FF3B35353B1418FFFFFFFFFFFFFFFF3FFFFFFFFF3B3435353B3B3B3B3B3B3B3B" + $"18FFFF3FFFFFFF3B34343535363637373737373B1418FF3FFFFF3B3434343535" + $"363637373737373B1418FF3FFF3B343434353536363637373737373B1418FF3F" + $"FF183B3535353536363637373737373B1418FF3FFFFF183B3536363636373737" + $"3737373B1418FF3FFFFFFF183B3636373B3B3B3B3B3B3B3B1418FF3FFFFFFFFF" + $"183B37373B141414141414141418FF3FFFFFFFFFFF183B373B14181818181818" + $"18FFFF3FFFFFFFFFFFFF183B3B1418FFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFF18" + $"141418FFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFF1818FFFFFFFFFFFFFFFFFF3F" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F" + } +}; + +resource(R_ResBackNavInactive) archive(, 0x00000000) BBitmap { + "_frame" = rect { 0.0, 0.0, 18.0, 16.0 }, + "_cspace" = 4, + "_bmflags" = 1, + "_rowbytes" = 20, + "_data" = array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFF0000FFFFFF" + $"FFFFFFFFFFFFFF3FFFFFFFFFFFFF001800FFFFFFFFFFFFFFFFFFFF3FFFFFFFFF" + $"FF00181800FFFFFFFFFFFFFFFFFFFF3FFFFFFFFF001C18180000000000000000" + $"FFFFFF3FFFFFFF001C1C18181515111111111100FFFFFF3FFFFF001C1C1C1818" + $"1515111111111100FFFFFF3FFF001C1C1C1818151515111111111100FFFFFF3F" + $"FFFF0018181818151515111111111100FFFFFF3FFFFFFF001815151515111111" + $"11111100FFFFFF3FFFFFFFFF001515110000000000000000FFFFFF3FFFFFFFFF" + $"FF00111100FFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFF001100FFFFFFFFFFFFFF" + $"FFFFFF3FFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F" + } +}; + +resource(R_ResForwNavActive) archive(, 0x00000000) BBitmap { + "_frame" = rect { 0.0, 0.0, 18.0, 16.0 }, + "_cspace" = 4, + "_bmflags" = 1, + "_rowbytes" = 20, + "_data" = array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFF3B3B18FF" + $"FFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFF3B353B18FFFFFFFFFFFFFF3FFFFFFFFF" + $"FFFFFFFF3B35363B18FFFFFFFFFFFF3FFF3B3B3B3B3B3B3B3B3536363B18FFFF" + $"FFFFFF3FFF3B34343434353535363636373B18FFFFFFFF3FFF3B343434353535" + $"3536363637373B18FFFFFF3FFF3B343435353535363636373737373B18FFFF3F" + $"FF3B3535353535363636373737373B141418FF3FFF3B35353536363636373737" + $"373B141418FFFF3FFF3B3B3B3B3B3B3B3B3737373B141418FFFFFF3FFF181414" + $"141414143B37373B141418FFFFFFFF3FFFFF1818181818183B373B141418FFFF" + $"FFFFFF3FFFFFFFFFFFFFFFFF3B3B141418FFFFFFFFFFFF3FFFFFFFFFFFFFFFFF" + $"18141418FFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFF1818FFFFFFFFFFFFFFFF3F" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F" + } +}; + +resource(R_ResForwNavInactive) archive(, 0x00000000) BBitmap { + "_frame" = rect { 0.0, 0.0, 18.0, 16.0 }, + "_cspace" = 4, + "_bmflags" = 1, + "_rowbytes" = 20, + "_data" = array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFF0000FFFF" + $"FFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFF001800FFFFFFFFFFFFFFFF3FFFFFFFFF" + $"FFFFFFFF00181500FFFFFFFFFFFFFF3FFF000000000000000018151500FFFFFF" + $"FFFFFF3FFF001C1C1C1C1818181515151100FFFFFFFFFF3FFF001C1C1C181818" + $"18151515111100FFFFFFFF3FFF001C1C181818181515151111111100FFFFFF3F" + $"FF0018181818181515151111111100FFFFFFFF3FFF0018181815151515111111" + $"1100FFFFFFFFFF3FFF000000000000000011111100FFFFFFFFFFFF3FFFFFFFFF" + $"FFFFFFFF00111100FFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFF001100FFFFFFFFFF" + $"FFFFFF3FFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F" + } +}; + +resource(R_ResUpNavActive) archive(, 0x00000000) BBitmap { + "_frame" = rect { 0.0, 0.0, 17.0, 16.0 }, + "_cspace" = 4, + "_bmflags" = 1, + "_rowbytes" = 20, + "_data" = array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F3FFFFFFFFFFFFFFFFF00FFFFFF" + $"FFFFFFFFFFFF3F3FFFFFFFFFFFFFFF00E50018FFFFFFFFFFFFFF3F3FFFFFFFFF" + $"FFFF00E5BDBD0018FFFFFFFFFFFF3F3FFFFFFFFFFF00E5BDBDBDBD0018FFFFFF" + $"FFFF3F3FFFFFFFFF00E5BDBDBDBDBDBD0018FFFFFFFF3F3FFFFFFF00E5BDBDBD" + $"BDBDBDBDBD0018FFFFFF3F3FFFFF00E5E5E5BDBDBDBDBD9898980018FFFF3F3F" + $"FF00000000E5BDBDBDBDBD980000000018FF3F3FFFFF141400E5BDBDBDBDBD98" + $"00141418FFFF3F3FFFFFFF1800E5BDBDBDBDBD98001418FFFFFF3F3FFFFFFFFF" + $"00E5BDBDBDBDBD98001418FFFFFF3F3FFFFFFFFF00E5989898989898001418FF" + $"FFFF3F3FFFFFFFFF0000000000000000001418FFFFFF3F3FFFFFFFFF18141414" + $"141414141418FFFFFFFF3F3FFFFFFFFFFF181818181818181818FFFFFFFF3F3F" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F3F" + } +}; + +resource(R_ResUpNavInactive) archive(, 0x00000000) BBitmap { + "_frame" = rect { 0.0, 0.0, 17.0, 16.0 }, + "_cspace" = 4, + "_bmflags" = 1, + "_rowbytes" = 20, + "_data" = array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F3FFFFFFFFFFFFFFFFF00FFFFFF" + $"FFFFFFFFFFFF3F3FFFFFFFFFFFFFFF001C00FFFFFFFFFFFFFFFF3F3FFFFFFFFF" + $"FFFF001C171700FFFFFFFFFFFFFF3F3FFFFFFFFFFF001C1717171700FFFFFFFF" + $"FFFF3F3FFFFFFFFF001C17171717171700FFFFFFFFFF3F3FFFFFFF001C171717" + $"171717171700FFFFFFFF3F3FFFFF001C1C1C171717171712121200FFFFFF3F3F" + $"FF000000001C17171717171200000000FFFF3F3FFFFFFFFF001C171717171712" + $"00FFFFFFFFFF3F3FFFFFFFFF001C17171717171200FFFFFFFFFF3F3FFFFFFFFF" + $"001C17171717171200FFFFFFFFFF3F3FFFFFFFFF001C12121212121200FFFFFF" + $"FFFF3F3FFFFFFFFF000000000000000000FFFFFFFFFF3F3FFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFF3F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F3F" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F3F" + } +}; + +resource(R_ResBackNavActiveSel) archive(, 0x00000000) BBitmap { + "_frame" = rect { 0.0, 0.0, 18.0, 16.0 }, + "_cspace" = 4, + "_bmflags" = 1, + "_rowbytes" = 20, + "_data" = array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFF3B3BFFFFFF" + $"FFFFFFFFFFFFFF3FFFFFFFFFFFFF3B353BFFFFFFFFFFFFFFFFFFFF3FFFFFFFFF" + $"FF3B35353BFFFFFFFFFFFFFFFFFFFF3FFFFFFFFF3B3435353B3B3B3B3B3B3B3B" + $"FFFFFF3FFFFFFF3B34343535363637373737373BFFFFFF3FFFFF3B3434343535" + $"363637373737373BFFFFFF3FFF3B343434353536363637373737373BFFFFFF3F" + $"FFFF3B3535353536363637373737373BFFFFFF3FFFFFFF3B3536363636373737" + $"3737373BFFFFFF3FFFFFFFFF3B3636373B3B3B3B3B3B3B3BFFFFFF3FFFFFFFFF" + $"FF3B37373BFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFF3B373BFFFFFFFFFFFFFF" + $"FFFFFF3FFFFFFFFFFFFFFF3B3BFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F" + } +}; + +resource(R_ResForwNavActiveSel) archive(, 0x00000000) BBitmap { + "_frame" = rect { 0.0, 0.0, 18.0, 16.0 }, + "_cspace" = 4, + "_bmflags" = 1, + "_rowbytes" = 20, + "_data" = array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFF3B3BFFFF" + $"FFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFF3B353BFFFFFFFFFFFFFFFF3FFFFFFFFF" + $"FFFFFFFF3B35363BFFFFFFFFFFFFFF3FFF3B3B3B3B3B3B3B3B3536363BFFFFFF" + $"FFFFFF3FFF3B34343434353535363636373BFFFFFFFFFF3FFF3B343434353535" + $"3536363637373BFFFFFFFF3FFF3B343435353535363636373737373BFFFFFF3F" + $"FF3B3535353535363636373737373BFFFFFFFF3FFF3B35353536363636373737" + $"373BFFFFFFFFFF3FFF3B3B3B3B3B3B3B3B3737373BFFFFFFFFFFFF3FFFFFFFFF" + $"FFFFFFFF3B37373BFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFF3B373BFFFFFFFFFF" + $"FFFFFF3FFFFFFFFFFFFFFFFF3B3BFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F" + } +}; + +resource(R_ResUpNavActiveSel) archive(, 0x00000000) BBitmap { + "_frame" = rect { 0.0, 0.0, 17.0, 16.0 }, + "_cspace" = 4, + "_bmflags" = 1, + "_rowbytes" = 20, + "_data" = array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F3FFFFFFFFFFFFFFFFF00FFFFFF" + $"FFFFFFFFFFFF3F3FFFFFFFFFFFFFFF00E500FFFFFFFFFFFFFFFF3F3FFFFFFFFF" + $"FFFF00E5BDBD00FFFFFFFFFFFFFF3F3FFFFFFFFFFF00E5BDBDBDBD00FFFFFFFF" + $"FFFF3F3FFFFFFFFF00E5BDBDBDBDBDBD00FFFFFFFFFF3F3FFFFFFF00E5BDBDBD" + $"BDBDBDBDBD00FFFFFFFF3F3FFFFF00E5E5E5BDBDBDBDBD98989800FFFFFF3F3F" + $"FF00000000E5BDBDBDBDBD9800000000FFFF3F3FFFFFFFFF00E5BDBDBDBDBD98" + $"00FFFFFFFFFF3F3FFFFFFFFF00E5BDBDBDBDBD9800FFFFFFFFFF3F3FFFFFFFFF" + $"00E5BDBDBDBDBD9800FFFFFFFFFF3F3FFFFFFFFF00E598989898989800FFFFFF" + $"FFFF3F3FFFFFFFFF000000000000000000FFFFFFFFFF3F3FFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFF3F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F3F" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F3F" + } +}; + +resource(101, "BEOS:ICON") #'VICN' array { + $"6E636966060200060240CCB33B58BF3B58BFC0CCB34E598BCD1673003F6EFFFF" + $"93ADFF05FF020106023E5402000000000000BE540248497948816C00B8F5FFFF" + $"0097FF05000201060242B568000000000000C2B5684E57E54A4B53002668EEFF" + $"B8F5FF032668EE120204B685BFC2B685C434B685BB51BE90B7B7BA1EB7B7C302" + $"B7B7C69CBFC2C69CBB51C69CC434BE90C7CEC302C7CEBA1EC7CE0204B685BFC2" + $"B685C434B685BB51BE90B7B7BA1EB7B7C302B7B7C69CBFC2C69CBB51C69CC434" + $"BE90C7CEC302C7CEBA1EC7CE0204B685BFC2B685C434B685BB51BE90B7B7BA1E" + $"B7B7C302B7B7C69CBFC2C69CBB51C69CC434BE90C7CEC302C7CEBA1EC7CE0204" + $"B685BFC2B685C434B685BB51BE90B7B7BA1EB7B7C302B7B7C69CBFC2C69CBB51" + $"C69CC434BE90C7CEC302C7CEBA1EC7CE0A10C3E8BE78C367BD12C48EBC60C335" + $"BBBEC389BA6FC222BAF1C170B9C9C0CEBB22BF80BACFC001BC35BEDABCE7C033" + $"BD89BFE0BED8C146BE56C1F8BF7EC29ABE250A10C3E8BE78C367BD12C48EBC60" + $"C335BBBEC389BA6FC222BAF1C170B9C9C0CEBB22BF80BACFC001BC35BEDABCE7" + $"C033BD89BFE0BED8C146BE56C1F8BF7EC29ABE250A04BAF5B910BA97BA76B9FA" + $"BA56BA65B8D10A04BA4CBBE132BD4DB99CBD47B9BCBBC90A0432BEC6BA65C02B" + $"B9C8C04AB99CBECC0A04BABDC197BB4DC2DDBAC3C31C32C1BD0A04BBFDC429BC" + $"D2C54ABC54C5AEBB79C4750A04BDBAC677BEC8C78BBE31C7D6BD49C6D60A04B7" + $"6EC2F6B8A7C37AB882C3FEB774C3AC0A04BA0DC3C5BB85C3DEBB7FC47BB9FAC4" + $"550A04BCF7C3E5BE69C3BFBE7CC455BCFEC47B0A04BFD5C387C13BC32FC167C3" + $"C5BFF5C41D0A04C2A1C2B8C3EDC221C42BC2A5C2D9C3480A04C51AC159C615C0" + $"5DC69FC0B5C57EC1D0120A0101001240D69000000000000040D690C65277C763" + $"0301144000000000000000004000000000000000000A0101011240D690000000" + $"00000040D690C65277C7630301178403040A0201020240D69000000000000040" + $"D690C65277C763030A0301031240D69000000000000040D690C65277C7630301" + $"178103040A0101040240D69000000000000040D690C65277C763030A01010512" + $"40D69000000000000040D690C65277C7630301178003040A0301060240D69000" + $"000000000040D690C65277C763030A0301070240D69000000000000040D690C6" + $"5277C763030A0301080240D69000000000000040D690C65277C763030A030109" + $"0240D69000000000000040D690C65277C763030A03010A0240D6900000000000" + $"0040D690C65277C763030A03010B0240D69000000000000040D690C65277C763" + $"030A03010C0240D69000000000000040D690C65277C763030A03010D0240D690" + $"00000000000040D690C65277C763030A03010E0240D69000000000000040D690" + $"C65277C763030A03010F0240D69000000000000040D690C65277C763030A0301" + $"100240D69000000000000040D690C65277C763030A0301110240D69000000000" + $"000040D690C65277C76303" +}; + +resource(101, "BEOS:D:STD_ICON") (#'iICO') $"4944585A055300"; + +resource(101, "BEOS:V:STD_ICON") #'zICO' array { + $"7A10000078DAED57DD6EDB3618BDEF5310CA4D03C40C7F3E8A6466B7C002AC37" + $"2C066CCD03B8B1EC6853A44052B3644FBFF351769C7601D68B41BB5814C03AA2" + $"8EA8C3F3FD5059BE7FB86DC47DD50F75D7AE0A2D5521AAF6BADBD4ED6E555C7D" + $"FA69110A318CEB76B36EBAB65A158FD550BC7FF76639DCEFC41FF566BC591525" + $"15E2A6AA7737E384AFBBA6EB17753B56FD5DD7ACC73C7353B7D5BAFFE5C38FC5" + $"BB3762B9C38F58DEADC71B4CFED860DE6DDD341727DB7C14B8391D9B55F131C8" + $"6085355299CB0C8D92C10BEDF3AFCE231137277C494AEAC3384569F49E3FE169" + $"9A099365E6C4772633F33C195F4EF34FE3F9B513FD28E6CFA3CAB15FB7C3B6EB" + $"6F57C5ED7AECEB87B75A928E670A7F135AE08D21B8B385B6D2913FE567CF5FF6" + $"A085CD3F60A4EF7EAF0E861CAE17D9F10B92D6C5F26990ADFDADABDB8BCFD57D" + $"D5FC9FCCEBD79B7ADD7CE053D58EA2C68A77FB0BE4F1015EB5F538AC8A2F43D5" + $"FF7AB7BEAE7E6EAF860A69FAB02AC0BA7ECCA77ECADDC3339FFEA64A49174C56" + $"B598A00ED2C4F20C0E292277CA790D49C3D8DD896EBB1DAA31CFCBD78B5C11AB" + $"E2E473D83AA4F7F90B54FD0D55A9E80FD4E5F9D70B7D3971BEF4CDDB93A7E59F" + $"BE16D15311A97C7C53445A3AEBC26B117D6717262309EB0CD287449A8518278D" + $"4F445295C260529BB0923208A36524E638811229CB64BD8C41E828A34DB69486" + $"D83A054CB2746C0EE964B5B49E39A01B5912CFA875821F1E9864C03846A0A094" + $"44CCB1D92D6F9275321856468E5FE5BCE0C980A3D450869743E551FD7FD8B7D1" + $"29BCF9BEBEFD6AF73F25E954D45FBBC68BC6B2E09449C02A5B02CD30C069C604" + $"1CA42B858619E9197D5E9921DB89CA8E90C39185DFBA942E66CC30F26D45E919" + $"7566891C6E477BBB900CCAB18DE84EC0F6492E3248A70379EE5813C494B23489" + $"1B2C9A629441735029705325CBC24088313D23CF2A1281837B68DCCA2794150A" + $"8D9C8C09D54668FFA50CC05A9A4C0958C7913EAF4C98640405CE438E64291CFA" + $"0970902AF2166493C9658F7DCB43F2913E6FC8D1080D875621FF48EA2828B71E" + $"6DB3366E64893981C7C384F7FC79757AE9598ECAD1B591B1A58CF32E1EFCBE23" + $"01E7AADAB3E78DB9934AF37B89C3CC9969789730874F0DC721577EAFF7C89E55" + $"A4CD5F3F882605DE78BCE668A2E3A09235ED2D06C7E5E847979EF1E7D589E70D" + $"37206C8A6C12FACEB4115A2E20BE5BF206E9F3D75EC8F8C09F5527BA0F3666B8" + $"A774227C5F46EEE6E8F2FC3D4A025F088025F726C8D7907FA4FF2B3297E7F8C7" + $"7F793EDCE3F417BB10DA0B" +}; + diff --git a/beos/beos_res.rsrc b/beos/beos_res.rsrc new file mode 100644 index 000000000..d37e9e6ec Binary files /dev/null and b/beos/beos_res.rsrc differ diff --git a/beos/beos_scaffolding.cpp b/beos/beos_scaffolding.cpp new file mode 100644 index 000000000..7bda4e4d7 --- /dev/null +++ b/beos/beos_scaffolding.cpp @@ -0,0 +1,1607 @@ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +extern "C" { +#include "content/content.h" +#include "desktop/browser.h" +#include "desktop/history_core.h" +#include "desktop/gui.h" +#include "desktop/netsurf.h" +#include "desktop/plotters.h" +#include "desktop/options.h" +#include "desktop/textinput.h" +#include "render/box.h" +#include "render/font.h" +#include "render/form.h" +#include "render/html.h" +#include "utils/messages.h" +#include "utils/utils.h" +#undef NDEBUG +#include "utils/log.h" +} +#include "beos/beos_gui.h" +#include "beos/beos_plotters.h" +#include "beos/beos_scaffolding.h" +#include "beos/beos_options.h" +//#include "beos/beos_completion.h" +#include "beos/beos_throbber.h" +//#include "beos/beos_history.h" +#include "beos/beos_window.h" +//#include "beos/beos_schedule.h" +//#include "beos/beos_download.h" + +#define TOOLBAR_HEIGHT 32 + +struct beos_history_window; + +class NSBrowserWindow; +class NSThrobber; + +struct beos_scaffolding { + NSBrowserWindow *window; // top-level container object + + // top-level view, contains toolbar & top-level browser view + BView *top_view; + + BMenuBar *menu_bar; + + BPopUpMenu *popup_menu; + + BControl *back_button; + BControl *forward_button; + BControl *stop_button; + BControl *reload_button; + BControl *home_button; + + BTextControl *url_bar; + //BMenuField *url_bar_completion; + + NSThrobber *throbber; + + BStringView *status_bar; + + BScrollView *scroll_view; +#warning XXX +#if 0 /* GTK */ + GtkWindow *window; + GtkEntry *url_bar; + GtkEntryCompletion *url_bar_completion; + GtkLabel *status_bar; + GtkToolbar *tool_bar; + GtkToolButton *back_button; + GtkToolButton *forward_button; + GtkToolButton *stop_button; + GtkToolButton *reload_button; + GtkMenuBar *menu_bar; + GtkMenuItem *back_menu; + GtkMenuItem *forward_menu; + GtkMenuItem *stop_menu; + GtkMenuItem *reload_menu; + GtkImage *throbber; + GtkPaned *status_pane; + + GladeXML *xml; + + GladeXML *popup_xml; + GtkMenu *popup_menu; + + struct gtk_history_window *history_window; +#endif + + int throb_frame; + struct gui_window *top_level; + int being_destroyed; + + bool fullscreen; +}; + +struct beos_history_window { + struct beos_scaffolding *g; +#warning XXX +#if 0 /* GTK */ + GtkWindow *window; + GtkScrolledWindow *scrolled; + GtkDrawingArea *drawing_area; +#endif +}; + +struct menu_events { + const char *widget; +#warning XXX +#if 0 /* GTK */ + GCallback handler; +#endif +}; + + +#warning XXX: UPDATE +typedef enum { + + /* no/unknown actions */ + NO_ACTION, + + /* help actions */ + HELP_OPEN_CONTENTS, + HELP_OPEN_GUIDE, + HELP_OPEN_INFORMATION, + HELP_OPEN_ABOUT, + HELP_LAUNCH_INTERACTIVE, + + /* history actions */ + HISTORY_SHOW_LOCAL, + HISTORY_SHOW_GLOBAL, + + /* hotlist actions */ + HOTLIST_ADD_URL, + HOTLIST_SHOW, + + /* cookie actions */ + COOKIES_SHOW, + COOKIES_DELETE, + + /* page actions */ + BROWSER_PAGE, + BROWSER_PAGE_INFO, + BROWSER_PRINT, + BROWSER_NEW_WINDOW, + BROWSER_VIEW_SOURCE, + + /* object actions */ + BROWSER_OBJECT, + BROWSER_OBJECT_INFO, + BROWSER_OBJECT_RELOAD, + + /* save actions */ + BROWSER_OBJECT_SAVE, + BROWSER_OBJECT_EXPORT_SPRITE, + BROWSER_OBJECT_SAVE_URL_URI, + BROWSER_OBJECT_SAVE_URL_URL, + BROWSER_OBJECT_SAVE_URL_TEXT, + BROWSER_SAVE, + BROWSER_SAVE_COMPLETE, + BROWSER_EXPORT_DRAW, + BROWSER_EXPORT_TEXT, + BROWSER_SAVE_URL_URI, + BROWSER_SAVE_URL_URL, + BROWSER_SAVE_URL_TEXT, + HOTLIST_EXPORT, + HISTORY_EXPORT, + + /* navigation actions */ + BROWSER_NAVIGATE_HOME, + BROWSER_NAVIGATE_BACK, + BROWSER_NAVIGATE_FORWARD, + BROWSER_NAVIGATE_UP, + BROWSER_NAVIGATE_RELOAD, + BROWSER_NAVIGATE_RELOAD_ALL, + BROWSER_NAVIGATE_STOP, + BROWSER_NAVIGATE_URL, + + /* browser window/display actions */ + BROWSER_SCALE_VIEW, + BROWSER_FIND_TEXT, + BROWSER_IMAGES_FOREGROUND, + BROWSER_IMAGES_BACKGROUND, + BROWSER_BUFFER_ANIMS, + BROWSER_BUFFER_ALL, + BROWSER_SAVE_VIEW, + BROWSER_WINDOW_DEFAULT, + BROWSER_WINDOW_STAGGER, + BROWSER_WINDOW_COPY, + BROWSER_WINDOW_RESET, + + /* tree actions */ + TREE_NEW_FOLDER, + TREE_NEW_LINK, + TREE_EXPAND_ALL, + TREE_EXPAND_FOLDERS, + TREE_EXPAND_LINKS, + TREE_COLLAPSE_ALL, + TREE_COLLAPSE_FOLDERS, + TREE_COLLAPSE_LINKS, + TREE_SELECTION, + TREE_SELECTION_EDIT, + TREE_SELECTION_LAUNCH, + TREE_SELECTION_DELETE, + TREE_SELECT_ALL, + TREE_CLEAR_SELECTION, + + /* toolbar actions */ + TOOLBAR_BUTTONS, + TOOLBAR_ADDRESS_BAR, + TOOLBAR_THROBBER, + TOOLBAR_EDIT, + + /* misc actions */ + CHOICES_SHOW, + APPLICATION_QUIT, +} menu_action; + + +static int open_windows = 0; /**< current number of open browsers */ +static struct beos_scaffolding *current_model; /**< current window for model dialogue use */ +#warning XXX +#if 0 /* GTK */ +static void nsbeos_window_destroy_event(GtkWidget *, gpointer); +#endif + +static void nsbeos_window_update_back_forward(struct beos_scaffolding *); +static void nsbeos_throb(void *); +#warning XXX +#if 0 /* GTK */ +static gboolean nsbeos_window_url_activate_event(beosWidget *, gpointer); +static gboolean nsbeos_window_url_changed(beosWidget *, GdkEventKey *, gpointer); + +static gboolean nsbeos_history_expose_event(beosWidget *, GdkEventExpose *, + gpointer); +static gboolean nsbeos_history_button_press_event(beosWidget *, GdkEventButton *, + gpointer); + +static void nsbeos_attach_menu_handlers(GladeXML *, gpointer); + +gboolean nsbeos_openfile_open(beosWidget *widget, gpointer data); + +#define MENUEVENT(x) { #x, G_CALLBACK(nsbeos_on_##x##_activate) } +#define MENUPROTO(x) static gboolean nsbeos_on_##x##_activate( \ + beosMenuItem *widget, gpointer g) +/* prototypes for menu handlers */ +/* file menu */ +MENUPROTO(new_window); +MENUPROTO(open_location); +MENUPROTO(open_file); +MENUPROTO(close_window); +MENUPROTO(quit); + +/* edit menu */ +MENUPROTO(preferences); + +/* view menu */ +MENUPROTO(stop); +MENUPROTO(reload); +MENUPROTO(zoom_in); +MENUPROTO(normal_size); +MENUPROTO(zoom_out); +MENUPROTO(full_screen); +MENUPROTO(menu_bar); +MENUPROTO(tool_bar); +MENUPROTO(status_bar); +MENUPROTO(downloads); +MENUPROTO(save_window_size); +MENUPROTO(toggle_debug_rendering); +MENUPROTO(save_box_tree); + +/* navigate menu */ +MENUPROTO(back); +MENUPROTO(forward); +MENUPROTO(home); +MENUPROTO(local_history); +MENUPROTO(global_history); + +/* help menu */ +MENUPROTO(about); + +/* structure used by nsbeos_attach_menu_handlers to connect menu items to + * their handling functions. + */ +static struct menu_events menu_events[] = { + /* file menu */ + MENUEVENT(new_window), + MENUEVENT(open_location), + MENUEVENT(open_file), + MENUEVENT(close_window), + MENUEVENT(quit), + + /* edit menu */ + MENUEVENT(preferences), + + /* view menu */ + MENUEVENT(stop), + MENUEVENT(reload), + MENUEVENT(zoom_in), + MENUEVENT(normal_size), + MENUEVENT(zoom_out), + MENUEVENT(full_screen), + MENUEVENT(menu_bar), + MENUEVENT(tool_bar), + MENUEVENT(status_bar), + MENUEVENT(downloads), + MENUEVENT(save_window_size), + MENUEVENT(toggle_debug_rendering), + MENUEVENT(save_box_tree), + + /* navigate menu */ + MENUEVENT(back), + MENUEVENT(forward), + MENUEVENT(home), + MENUEVENT(local_history), + MENUEVENT(global_history), + + /* help menu */ + MENUEVENT(about), + + /* sentinel */ + { NULL, NULL } +}; + +void nsbeos_attach_menu_handlers(GladeXML *xml, gpointer g) +{ + struct menu_events *event = menu_events; + + while (event->widget != NULL) + { + beosWidget *w = glade_xml_get_widget(xml, event->widget); + g_signal_connect(G_OBJECT(w), "activate", event->handler, g); + event++; + } +} +#endif + +// #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; +} + + + +// #pragma mark - class NSBrowserWindow + + +NSBrowserWindow::NSBrowserWindow(BRect frame, struct beos_scaffolding *scaf) + : BWindow(frame, "NetSurf", B_DOCUMENT_WINDOW, 0), + fScaffolding(scaf) +{ +} + + +NSBrowserWindow::~NSBrowserWindow() +{ +} + + +void +NSBrowserWindow::MessageReceived(BMessage *message) +{ + switch (message->what) { + case B_REFS_RECEIVED: + 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 +} + + +// #pragma mark - implementation + +/* event handlers and support functions for them */ + +static void nsbeos_window_destroy_event(NSBrowserWindow *window, nsbeos_scaffolding *g, BMessage *event) +{ + LOG(("Being Destroyed = %d", g->being_destroyed)); + + if (--open_windows == 0) + netsurf_quit = true; + + window->Lock(); + window->Quit(); + + if (!g->being_destroyed) { + g->being_destroyed = 1; + nsbeos_window_destroy_browser(g->top_level); + } +} + + +void nsbeos_scaffolding_dispatch_event(nsbeos_scaffolding *scaffold, BMessage *message) +{ + int width, height; + struct browser_window *bw; + bw = nsbeos_get_browser_for_gui(scaffold->top_level); + LOG(("nsbeos_scaffolding_dispatch_event() what = 0x%08lx", message->what)); + switch (message->what) { + case B_QUIT_REQUESTED: + nsbeos_scaffolding_destroy(scaffold); + break; + case B_SIMPLE_DATA: + { + if (!message->HasRef("refs")) { + // XXX handle DnD + break; + } + // FALL THROUGH + // handle refs + } + case B_REFS_RECEIVED: + { + entry_ref ref; + + if (message->FindRef("refs", &ref) < B_OK) + break; + + BString url("file://"); + BPath path(&ref); + if (path.InitCheck() < B_OK) + break; + + BNode node(path.Path()); + if (node.InitCheck() < 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(); + browser_window_go(bw, url.String(), 0, true); + break; + } + case 'back': + if (!history_back_available(bw->history)) + break; + history_back(bw, bw->history); + nsbeos_window_update_back_forward(scaffold); + break; + case 'forw': + if (!history_back_available(bw->history)) + break; + history_forward(bw, bw->history); + nsbeos_window_update_back_forward(scaffold); + break; + case 'stop': + browser_window_stop(bw); + break; + case 'relo': + browser_window_reload(bw, true); + break; + case 'home': + { + static const char *addr = "http://netsurf-browser.org/welcome/"; + + if (option_homepage_url != NULL && option_homepage_url[0] != '\0') + addr = option_homepage_url; + + browser_window_go(bw, addr, 0, true); + break; + } + case 'urle': + { + BString text; + if (!scaffold->url_bar->LockLooper()) + break; + text = scaffold->url_bar->Text(); + scaffold->scroll_view->Target()->MakeFocus(); + scaffold->url_bar->UnlockLooper(); + browser_window_go(bw, text.String(), 0, true); + 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 '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; + } + default: + break; + } +} + +void nsbeos_scaffolding_destroy(nsbeos_scaffolding *scaffold) +{ + LOG(("Being Destroyed = %d", scaffold->being_destroyed)); + if (scaffold->being_destroyed) return; + scaffold->being_destroyed = 1; + nsbeos_window_destroy_event(scaffold->window, scaffold, NULL); +#warning XXX +#if 0 /* GTK */ + /* Our top_level has asked us to die */ + LOG(("Being Destroyed = %d", scaffold->being_destroyed)); + if (scaffold->being_destroyed) return; + scaffold->being_destroyed = 1; + nsbeos_window_destroy_event(0, scaffold); +#endif +} + + +void nsbeos_window_update_back_forward(struct beos_scaffolding *g) +{ + int width, height; + struct browser_window *bw = nsbeos_get_browser_for_gui(g->top_level); + + if (!g->top_view->LockLooper()) + return; + + g->back_button->SetEnabled(history_back_available(bw->history)); + g->forward_button->SetEnabled(history_forward_available(bw->history)); + + g->top_view->UnlockLooper(); + +#warning XXX +#if 0 /* GTK */ + beos_widget_set_sensitive(beos_WIDGET(g->back_button), + history_back_available(bw->history)); + beos_widget_set_sensitive(beos_WIDGET(g->forward_button), + history_forward_available(bw->history)); + + beos_widget_set_sensitive(beos_WIDGET(g->back_menu), + history_back_available(bw->history)); + beos_widget_set_sensitive(beos_WIDGET(g->forward_menu), + history_forward_available(bw->history)); + + /* update the local history window, as well as queuing a redraw + * for it. + */ + history_size(bw->history, &width, &height); + beos_widget_set_size_request(beos_WIDGET(g->history_window->drawing_area), + width, height); + beos_widget_queue_draw(beos_WIDGET(g->history_window->drawing_area)); +#endif +} + +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; + +#if 0 + g->throbber->SetViewBitmap(nsbeos_throbber->framedata[g->throb_frame], + B_FOLLOW_RIGHT | B_FOLLOW_TOP); +#endif + g->throbber->SetBitmap(nsbeos_throbber->framedata[g->throb_frame]); + g->throbber->Invalidate(); + + g->top_view->UnlockLooper(); + + schedule(10, nsbeos_throb, p); + +} + +#warning XXX +#if 0 /* GTK */ + +gboolean nsbeos_openfile_open(beosWidget *widget, gpointer data) +{ + struct browser_window *bw = nsbeos_get_browser_for_gui( + current_model->top_level); + char *filename = beos_file_chooser_get_filename( + beos_FILE_CHOOSER(wndOpenFile)); + char *url = malloc(strlen(filename) + strlen("file://") + 1); + + sprintf(url, "file://%s", filename); + + browser_window_go(bw, url, 0, true); + + g_free(filename); + free(url); + + return TRUE; +} +#endif + +#warning XXX +#if 0 /* GTK */ +/* signal handlers for menu entries */ +#define MENUHANDLER(x) gboolean nsbeos_on_##x##_activate(beosMenuItem *widget, \ + gpointer g) + +MENUHANDLER(new_window) +{ + struct beos_scaffolding *gw = (struct beos_scaffolding *)g; + struct browser_window *bw = nsbeos_get_browser_for_gui(gw->top_level); + const char *url = beos_entry_get_text(beos_ENTRY(gw->url_bar)); + + browser_window_create(url, bw, NULL, false); + + return TRUE; +} + +MENUHANDLER(open_location) +{ + struct beos_scaffolding *gw = (struct beos_scaffolding *)g; + + beos_widget_grab_focus(beos_WIDGET(gw->url_bar)); + + return TRUE; +} + +MENUHANDLER(open_file) +{ + current_model = (struct beos_scaffolding *)g; + beos_dialog_run(wndOpenFile); + + return TRUE; +} + +MENUHANDLER(close_window) +{ + struct beos_scaffolding *gw = (struct beos_scaffolding *)g; + + beos_widget_destroy(beos_WIDGET(gw->window)); + + return TRUE; +} + +MENUHANDLER(quit) +{ + netsurf_quit = true; + return TRUE; +} + +MENUHANDLER(preferences) +{ + beos_widget_show(beos_WIDGET(wndPreferences)); + + return TRUE; +} + +MENUHANDLER(zoom_in) +{ + struct beos_scaffolding *gw = (struct beos_scaffolding *)g; + struct browser_window *bw = nsbeos_get_browser_for_gui(gw->top_level); + float old_scale = nsbeos_get_scale_for_gui(gw->top_level); + + browser_window_set_scale(bw, old_scale + 0.05, true); + + return TRUE; +} + +MENUHANDLER(normal_size) +{ + struct beos_scaffolding *gw = (struct beos_scaffolding *)g; + struct browser_window *bw = nsbeos_get_browser_for_gui(gw->top_level); + + browser_window_set_scale(bw, 1.0, true); + + return TRUE; +} + +MENUHANDLER(zoom_out) +{ + struct beos_scaffolding *gw = (struct beos_scaffolding *)g; + struct browser_window *bw = nsbeos_get_browser_for_gui(gw->top_level); + float old_scale = nsbeos_get_scale_for_gui(gw->top_level); + + browser_window_set_scale(bw, old_scale - 0.05, true); + + return TRUE; +} + +MENUHANDLER(full_screen) +{ + struct beos_scaffolding *gw = (struct beos_scaffolding *)g; + + if (gw->fullscreen) { + beos_window_unfullscreen(gw->window); + } else { + beos_window_fullscreen(gw->window); + } + + gw->fullscreen = !gw->fullscreen; + + return TRUE; +} + +MENUHANDLER(menu_bar) +{ + struct beos_scaffolding *gw = (struct beos_scaffolding *)g; + + if (beos_check_menu_item_get_active(beos_CHECK_MENU_ITEM(widget))) { + beos_widget_show(beos_WIDGET(gw->menu_bar)); + } else { + beos_widget_hide(beos_WIDGET(gw->menu_bar)); + } + + return TRUE; +} + +MENUHANDLER(tool_bar) +{ + struct beos_scaffolding *gw = (struct beos_scaffolding *)g; + + if (beos_check_menu_item_get_active(beos_CHECK_MENU_ITEM(widget))) { + beos_widget_show(beos_WIDGET(gw->tool_bar)); + } else { + beos_widget_hide(beos_WIDGET(gw->tool_bar)); + } + + return TRUE; +} + +MENUHANDLER(status_bar) +{ + struct beos_scaffolding *gw = (struct beos_scaffolding *)g; + + if (beos_check_menu_item_get_active(beos_CHECK_MENU_ITEM(widget))) { + beos_widget_show(beos_WIDGET(gw->status_bar)); + } else { + beos_widget_hide(beos_WIDGET(gw->status_bar)); + } + + return TRUE; +} + +MENUHANDLER(downloads) +{ + nsbeos_download_show(); + + return TRUE; +} + +MENUHANDLER(save_window_size) +{ + struct beos_scaffolding *gw = (struct beos_scaffolding *)g; + + option_toolbar_status_width = beos_paned_get_position(gw->status_pane); + beos_window_get_position(gw->window, &option_window_x, &option_window_y); + beos_window_get_size(gw->window, &option_window_width, + &option_window_height); + + + options_write(options_file_location); + + return TRUE; +} + +MENUHANDLER(toggle_debug_rendering) +{ + html_redraw_debug = !html_redraw_debug; + nsbeos_reflow_all_windows(); + return TRUE; +} + +MENUHANDLER(save_box_tree) +{ + beosWidget *save_dialog; + struct beos_scaffolding *gw = (struct beos_scaffolding *)g; + + save_dialog = beos_file_chooser_dialog_new("Save File", gw->window, + beos_FILE_CHOOSER_ACTION_SAVE, + beos_STOCK_CANCEL, beos_RESPONSE_CANCEL, + beos_STOCK_SAVE, beos_RESPONSE_ACCEPT, + NULL); + + beos_file_chooser_set_current_folder(beos_FILE_CHOOSER(save_dialog), + getenv("HOME") ? getenv("HOME") : "/"); + + beos_file_chooser_set_current_name(beos_FILE_CHOOSER(save_dialog), + "boxtree.txt"); + + if (beos_dialog_run(beos_DIALOG(save_dialog)) == beos_RESPONSE_ACCEPT) { + char *filename = beos_file_chooser_get_filename( + beos_FILE_CHOOSER(save_dialog)); + FILE *fh; + LOG(("Saving box tree dump to %s...\n", filename)); + + fh = fopen(filename, "w"); + if (fh == NULL) { + warn_user("Error saving box tree dump.", + "Unable to open file for writing."); + } else { + struct browser_window *bw; + bw = nsbeos_get_browser_window(gw->top_level); + + if (bw->current_content && + bw->current_content->type == + CONTENT_HTML) { + box_dump(fh, + bw->current_content->data.html.layout, + 0); + } + + fclose(fh); + } + + g_free(filename); + } + + beos_widget_destroy(save_dialog); +} + +MENUHANDLER(stop) +{ + return nsbeos_window_stop_button_clicked(beos_WIDGET(widget), g); +} + +MENUHANDLER(reload) +{ + return nsbeos_window_reload_button_clicked(beos_WIDGET(widget), g); +} + +MENUHANDLER(back) +{ + return nsbeos_window_back_button_clicked(beos_WIDGET(widget), g); +} + +MENUHANDLER(forward) +{ + return nsbeos_window_forward_button_clicked(beos_WIDGET(widget), g); +} + +MENUHANDLER(home) +{ + return nsbeos_window_home_button_clicked(beos_WIDGET(widget), g); +} + +MENUHANDLER(local_history) +{ + struct beos_scaffolding *gw = (struct beos_scaffolding *)g; + + beos_widget_show(beos_WIDGET(gw->history_window->window)); + gdk_window_raise(beos_WIDGET(gw->history_window->window)->window); + + return TRUE; +} + +MENUHANDLER(global_history) +{ + beos_widget_show(beos_WIDGET(wndHistory)); + gdk_window_raise(beos_WIDGET(wndHistory)->window); + + return TRUE; +} + +MENUHANDLER(about) +{ + beos_widget_show(beos_WIDGET(wndAbout)); + gdk_window_raise(beos_WIDGET(wndAbout)->window); + return TRUE; +} + +/* signal handler functions for the local history window */ +gboolean nsbeos_history_expose_event(beosWidget *widget, + GdkEventExpose *event, gpointer g) +{ + struct beos_history_window *hw = (struct beos_history_window *)g; + struct browser_window *bw = nsbeos_get_browser_for_gui(hw->g->top_level); + + current_widget = widget; + current_drawable = widget->window; + current_gc = gdk_gc_new(current_drawable); +#ifdef CAIRO_VERSION + current_cr = gdk_cairo_create(current_drawable); +#endif + plot = nsbeos_plotters; + nsbeos_plot_set_scale(1.0); + + history_redraw(bw->history); + + g_object_unref(current_gc); +#ifdef CAIRO_VERSION + cairo_destroy(current_cr); +#endif + return FALSE; +} + +gboolean nsbeos_history_button_press_event(beosWidget *widget, + GdkEventButton *event, gpointer g) +{ + struct beos_history_window *hw = (struct beos_history_window *)g; + struct browser_window *bw = nsbeos_get_browser_for_gui(hw->g->top_level); + + LOG(("X=%g, Y=%g", event->x, event->y)); + + history_click(bw, bw->history, + event->x, event->y, false); + + return TRUE; +} + +#define GET_WIDGET(x) glade_xml_get_widget(g->xml, (x)) + +static gboolean do_scroll_event(beosWidget *widget, GdkEvent *ev, + gpointer data) +{ + switch (((GdkEventScroll *)ev)->direction) + { + case GDK_SCROLL_UP: + case GDK_SCROLL_DOWN: + beos_widget_event(g_object_get_data( + G_OBJECT(widget), "vScroll"), ev); + break; + default: + beos_widget_event(g_object_get_data( + G_OBJECT(widget), "hScroll"), ev); + } + + return TRUE; +} +#endif + +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; +} + +void nsbeos_attach_toplevel_view(nsbeos_scaffolding *g, BView *view) +{ + LOG(("Attaching view to scaffolding %p", g)); + + BRect rect(g->top_view->Bounds()); + rect.top += TOOLBAR_HEIGHT; + rect.right -= B_H_SCROLL_BAR_HEIGHT; + 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); + + 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); + */ + + BString status("NetSurf"); + status << " " << netsurf_version; + g->status_bar = new BStringView(rect, "StatusBar", status.String(), + B_FOLLOW_LEFT/*_RIGHT*/ | B_FOLLOW_BOTTOM); + 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 ?) + 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); + + + if (g->window) + g->window->Show(); + +#warning XXX +#if 0 /* GTK */ + beosWidget *scrollbar; + + /* Insert the viewport into the right part of our table */ + beosTable *table = beos_TABLE(GET_WIDGET("centreTable")); + LOG(("Attaching viewport to scaffolding %p", g)); + beos_table_attach_defaults(table, beos_WIDGET(vp), 0, 1, 0, 1); + + /* connect our scrollbars to the viewport */ + scrollbar = GET_WIDGET("coreScrollHorizontal"); + beos_viewport_set_hadjustment(vp, + beos_range_get_adjustment(beos_RANGE(scrollbar))); + g_object_set_data(G_OBJECT(vp), "hScroll", scrollbar); + scrollbar = GET_WIDGET("coreScrollVertical"); + beos_viewport_set_vadjustment(vp, + beos_range_get_adjustment(beos_RANGE(scrollbar))); + g_object_set_data(G_OBJECT(vp), "vScroll", scrollbar); + g_signal_connect(G_OBJECT(vp), "scroll_event", + G_CALLBACK(do_scroll_event), NULL); + + gdk_window_set_accept_focus (beos_WIDGET(vp)->window, TRUE); + + /* And set the size-request to zero to cause it to get its act together */ + beos_widget_set_size_request(beos_WIDGET(vp), 0, 0); + +#endif +} + +nsbeos_scaffolding *nsbeos_new_scaffolding(struct gui_window *toplevel) +{ + struct beos_scaffolding *g = (struct beos_scaffolding *)malloc(sizeof(*g)); + + LOG(("Constructing a scaffold of %p for gui_window %p", g, toplevel)); + + g->top_level = toplevel; + + open_windows++; + + BRect frame(0, 0, 600-1, 500-1); + if (option_window_width > 0) { + frame.Set(0, 0, option_window_width - 1, option_window_height - 1); + frame.OffsetToSelf(option_window_x, option_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->Unlock(); + } + 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); + + g->being_destroyed = 0; + + g->fullscreen = false; + + + BMessage *message; + + // build popup menu + g->popup_menu = new BPopUpMenu(""); + + + + + BRect rect; + 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; + + menu = new BMenu("File"); + g->menu_bar->AddItem(menu); + + menu = new BMenu("Edit"); + g->menu_bar->AddItem(menu); + + menu = new BMenu("View"); + g->menu_bar->AddItem(menu); + + menu = new BMenu("Navigate"); + g->menu_bar->AddItem(menu); + + menu = new BMenu("Help"); + g->menu_bar->AddItem(menu); + + // 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 BView(rect, "NetSurfBrowser", + B_FOLLOW_ALL_SIDES, 0); + g->top_view->SetViewColor(0, 255, 0); + g->window->AddChild(g->top_view); + + // toolbar + rect = g->top_view->Bounds(); + rect.bottom = rect.top + TOOLBAR_HEIGHT; + BView *toolbar = new BView(rect, "Toolbar", + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 0); + toolbar->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + toolbar->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)) ; +#if defined(__HAIKU__) || defined(B_DANO_VERSION) + toolbar->SetHighColor(ui_color(B_PANEL_TEXT_COLOR)); +#endif + g->top_view->AddChild(toolbar); + + // buttons +#warning use BPictureButton + rect = toolbar->Bounds(); + rect.right = TOOLBAR_HEIGHT; + rect.InsetBySelf(5, 5); + + message = new BMessage('back'); + message->AddPointer("scaffolding", g); + + g->back_button = new BButton(rect, "back_button", "<", message); + toolbar->AddChild(g->back_button); + + rect.OffsetBySelf(TOOLBAR_HEIGHT, 0); + message = new BMessage('forw'); + message->AddPointer("scaffolding", g); + g->forward_button = new BButton(rect, "forward_button", ">", message); + toolbar->AddChild(g->forward_button); + + rect.OffsetBySelf(TOOLBAR_HEIGHT, 0); + message = new BMessage('stop'); + message->AddPointer("scaffolding", g); + g->stop_button = new BButton(rect, "stop_button", "S", message); + toolbar->AddChild(g->stop_button); + + rect.OffsetBySelf(TOOLBAR_HEIGHT, 0); + message = new BMessage('relo'); + message->AddPointer("scaffolding", g); + g->reload_button = new BButton(rect, "reload_button", "R", message); + toolbar->AddChild(g->reload_button); + + rect.OffsetBySelf(TOOLBAR_HEIGHT, 0); + message = new BMessage('home'); + message->AddPointer("scaffolding", g); + g->home_button = new BButton(rect, "home_button", "H", message); + toolbar->AddChild(g->home_button); + + + // url bar + rect = toolbar->Bounds(); + rect.left += TOOLBAR_HEIGHT * 5; + rect.right -= TOOLBAR_HEIGHT * 1; + rect.InsetBySelf(5, 5); + message = new BMessage('urle'); + message->AddPointer("scaffolding", g); + g->url_bar = new BTextControl(rect, "url_bar", "url", "", message, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + g->url_bar->SetDivider(g->url_bar->StringWidth("url ")); + toolbar->AddChild(g->url_bar); + + + // throbber + rect.Set(0, 0, 24, 24); + rect.OffsetTo(toolbar->Bounds().right - 24 - (TOOLBAR_HEIGHT - 24) / 2, + (TOOLBAR_HEIGHT - 24) / 2); + g->throbber = new NSThrobber(rect); + toolbar->AddChild(g->throbber); + g->throbber->SetViewColor(toolbar->ViewColor()); + g->throbber->SetLowColor(toolbar->ViewColor()); + g->throbber->SetDrawingMode(B_OP_OVER); + /* set up the throbber. */ + g->throbber->SetBitmap(nsbeos_throbber->framedata[0]); + g->throb_frame = 0; + + + // the status bar at the bottom + // will be constructed when adding the top view. + +#warning XXX +#if 0 /* GTK */ + /* load the window template from the glade xml file, and extract + * widget references from it for later use. + */ + g->xml = glade_xml_new(glade_file_location, "wndBrowser", NULL); + glade_xml_signal_autoconnect(g->xml); + g->window = beos_WINDOW(GET_WIDGET("wndBrowser")); + g->url_bar = beos_ENTRY(GET_WIDGET("URLBar")); + g->menu_bar = beos_MENU_BAR(GET_WIDGET("menubar")); + g->status_bar = beos_LABEL(GET_WIDGET("statusBar")); + g->tool_bar = beos_TOOLBAR(GET_WIDGET("toolbar")); + g->back_button = beos_TOOL_BUTTON(GET_WIDGET("toolBack")); + g->forward_button = beos_TOOL_BUTTON(GET_WIDGET("toolForward")); + g->stop_button = beos_TOOL_BUTTON(GET_WIDGET("toolStop")); + g->reload_button = beos_TOOL_BUTTON(GET_WIDGET("toolReload")); + g->back_menu = beos_MENU_ITEM(GET_WIDGET("back")); + g->forward_menu = beos_MENU_ITEM(GET_WIDGET("forward")); + g->stop_menu = beos_MENU_ITEM(GET_WIDGET("stop")); + g->reload_menu = beos_MENU_ITEM(GET_WIDGET("reload")); + g->throbber = beos_IMAGE(GET_WIDGET("throbber")); + g->status_pane = beos_PANED(GET_WIDGET("hpaned1")); + + /* set this window's size and position to what's in the options, or + * or some sensible default if they're not set yet. + */ + if (option_window_width > 0) { + beos_window_move(g->window, option_window_x, option_window_y); + beos_window_resize(g->window, option_window_width, + option_window_height); + } else { + beos_window_set_default_size(g->window, 600, 600); + } + + /* set the size of the hpane with status bar and h scrollbar */ + beos_paned_set_position(g->status_pane, option_toolbar_status_width); + + /* set the URL entry box to expand, as we can't do this from within + * glade because of the way it emulates toolbars. + */ + beos_tool_item_set_expand(beos_TOOL_ITEM(GET_WIDGET("toolURLBar")), TRUE); + + /* disable toolbar buttons that make no sense initially. */ + beos_widget_set_sensitive(beos_WIDGET(g->back_button), FALSE); + beos_widget_set_sensitive(beos_WIDGET(g->forward_button), FALSE); + beos_widget_set_sensitive(beos_WIDGET(g->stop_button), FALSE); + + /* create the local history window to be assoicated with this browser */ + g->history_window = malloc(sizeof(struct beos_history_window)); + g->history_window->g = g; + g->history_window->window = beos_WINDOW( + beos_window_new(beos_WINDOW_TOPLEVEL)); + beos_window_set_transient_for(g->history_window->window, g->window); + beos_window_set_default_size(g->history_window->window, 400, 400); + beos_window_set_title(g->history_window->window, "NetSurf History"); + beos_window_set_type_hint(g->history_window->window, + GDK_WINDOW_TYPE_HINT_UTILITY); + g->history_window->scrolled = beos_SCROLLED_WINDOW( + beos_scrolled_window_new(0, 0)); + beos_container_add(beos_CONTAINER(g->history_window->window), + beos_WIDGET(g->history_window->scrolled)); + + beos_widget_show(beos_WIDGET(g->history_window->scrolled)); + g->history_window->drawing_area = beos_DRAWING_AREA( + beos_drawing_area_new()); + + beos_widget_set_events(beos_WIDGET(g->history_window->drawing_area), + GDK_EXPOSURE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_PRESS_MASK); + beos_widget_modify_bg(beos_WIDGET(g->history_window->drawing_area), + beos_STATE_NORMAL, + &((GdkColor) { 0, 0xffff, 0xffff, 0xffff } )); + beos_scrolled_window_add_with_viewport(g->history_window->scrolled, + beos_WIDGET(g->history_window->drawing_area)); + beos_widget_show(beos_WIDGET(g->history_window->drawing_area)); + + /* set up URL bar completion */ + g->url_bar_completion = beos_entry_completion_new(); + beos_entry_set_completion(g->url_bar, g->url_bar_completion); + beos_entry_completion_set_match_func(g->url_bar_completion, + nsbeos_completion_match, NULL, NULL); + beos_entry_completion_set_model(g->url_bar_completion, + beos_TREE_MODEL(nsbeos_completion_list)); + beos_entry_completion_set_text_column(g->url_bar_completion, 0); + beos_entry_completion_set_minimum_key_length(g->url_bar_completion, 1); + beos_entry_completion_set_popup_completion(g->url_bar_completion, TRUE); + g_object_set(G_OBJECT(g->url_bar_completion), + "popup-set-width", TRUE, + "popup-single-match", TRUE, + NULL); + + /* set up the throbber. */ + beos_image_set_from_pixbuf(g->throbber, nsbeos_throbber->framedata[0]); + g->throb_frame = 0; + +#define CONNECT(obj, sig, callback, ptr) \ + g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) + + /* connect history window signals to their handlers */ + CONNECT(g->history_window->drawing_area, "expose_event", + nsbeos_history_expose_event, g->history_window); +// CONNECT(g->history_window->drawing_area, "motion_notify_event", +// nsbeos_history_motion_notify_event, g->history_window); + CONNECT(g->history_window->drawing_area, "button_press_event", + nsbeos_history_button_press_event, g->history_window); + CONNECT(g->history_window->window, "delete_event", + beos_widget_hide_on_delete, NULL); + + /* connect signals to handlers. */ + CONNECT(g->window, "destroy", nsbeos_window_destroy_event, g); + + /* toolbar and URL bar signal handlers */ + CONNECT(g->back_button, "clicked", nsbeos_window_back_button_clicked, g); + CONNECT(g->forward_button, "clicked", + nsbeos_window_forward_button_clicked, g); + CONNECT(g->stop_button, "clicked", nsbeos_window_stop_button_clicked, g); + CONNECT(g->reload_button, "clicked", + nsbeos_window_reload_button_clicked, g); + CONNECT(GET_WIDGET("toolHome"), "clicked", + nsbeos_window_home_button_clicked, g); + CONNECT(g->url_bar, "activate", nsbeos_window_url_activate_event, g); + CONNECT(g->url_bar, "changed", nsbeos_window_url_changed, g); + + /* set up the menu signal handlers */ + nsbeos_attach_menu_handlers(g->xml, g); + + g->being_destroyed = 0; + + g->fullscreen = false; + + /* create the popup version of the menu */ + g->popup_xml = glade_xml_new(glade_file_location, "menuPopup", NULL); + g->popup_menu = beos_MENU(glade_xml_get_widget(g->popup_xml, "menuPopup")); + +#define POPUP_ATTACH(x, y) beos_menu_item_set_submenu( \ + beos_MENU_ITEM(glade_xml_get_widget(g->popup_xml, x)),\ + beos_WIDGET(glade_xml_get_widget(g->xml, y))) + + POPUP_ATTACH("menupopup_file", "menumain_file"); + POPUP_ATTACH("menupopup_edit", "menumain_edit"); + POPUP_ATTACH("menupopup_view", "menumain_view"); + POPUP_ATTACH("menupopup_navigate", "menumain_navigate"); + POPUP_ATTACH("menupopup_help", "menumain_help"); + +#undef POPUP_ATTACH + + /* finally, show the window. */ + beos_widget_show(beos_WIDGET(g->window)); + +#endif + 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(); +} + +void gui_window_set_url(struct gui_window *_g, const char *url) +{ + struct beos_scaffolding *g = nsbeos_get_scaffold(_g); + if (g->top_level != _g) return; + assert(g->status_bar); + + if (!g->top_view->LockLooper()) + return; + + g->url_bar->SetText(url); + + g->top_view->UnlockLooper(); +#warning XXX +#if 0 /* GTK */ + beos_entry_set_text(g->url_bar, url); + beos_editable_set_position(beos_EDITABLE(g->url_bar), -1); +#endif +} + +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); + + schedule(10, nsbeos_throb, g); + +#warning XXX +#if 0 /* GTK */ + beos_widget_set_sensitive(beos_WIDGET(g->stop_button), TRUE); + beos_widget_set_sensitive(beos_WIDGET(g->reload_button), FALSE); + beos_widget_set_sensitive(beos_WIDGET(g->stop_menu), TRUE); + beos_widget_set_sensitive(beos_WIDGET(g->reload_button), FALSE); + + nsbeos_window_update_back_forward(g); + + schedule(10, nsbeos_throb, g); +#endif +} + +void gui_window_stop_throbber(struct gui_window* _g) +{ + struct beos_scaffolding *g = nsbeos_get_scaffold(_g); + + nsbeos_window_update_back_forward(g); + + schedule_remove(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(); + +#warning XXX +#if 0 /* GTK */ + beos_widget_set_sensitive(beos_WIDGET(g->stop_button), FALSE); + beos_widget_set_sensitive(beos_WIDGET(g->reload_button), TRUE); + beos_widget_set_sensitive(beos_WIDGET(g->stop_menu), FALSE); + beos_widget_set_sensitive(beos_WIDGET(g->reload_menu), TRUE); + + nsbeos_window_update_back_forward(g); + + schedule_remove(nsbeos_throb, g); + + beos_image_set_from_pixbuf(g->throbber, nsbeos_throbber->framedata[0]); +#endif +} + +#warning XXX +#if 0 /* GTK */ +gboolean nsbeos_scaffolding_is_busy(nsbeos_scaffolding *scaffold) +{ + /* We are considered "busy" if the stop button is sensitive */ + return beos_WIDGET_SENSITIVE((beos_WIDGET(scaffold->stop_button))); +} +#endif + +void nsbeos_scaffolding_popup_menu(nsbeos_scaffolding *g, BPoint where) +{ + g->popup_menu->Go(where); +} diff --git a/beos/beos_scaffolding.h b/beos/beos_scaffolding.h new file mode 100644 index 000000000..2fcc7280e --- /dev/null +++ b/beos/beos_scaffolding.h @@ -0,0 +1,71 @@ +/* + * Copyright 2005 James Bursa + * + * 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 . + */ + +#ifndef NETSURF_BEOS_SCAFFOLDING_H +#define NETSURF_BEOS_SCAFFOLDING_H 1 + +#include +#include +extern "C" { +#include "desktop/gui.h" +#include "desktop/plotters.h" +} + +typedef struct beos_scaffolding nsbeos_scaffolding; + +class NSBrowserWindow : public BWindow { +public: + NSBrowserWindow(BRect frame, struct beos_scaffolding *scaf); +virtual ~NSBrowserWindow(); + +virtual void MessageReceived(BMessage *message); +virtual bool QuitRequested(void); + +struct beos_scaffolding *Scaffolding() const { return fScaffolding; }; + +private: + struct beos_scaffolding *fScaffolding; +}; + + +NSBrowserWindow *nsbeos_find_last_window(void); + +nsbeos_scaffolding *nsbeos_new_scaffolding(struct gui_window *toplevel); + +bool nsbeos_scaffolding_is_busy(nsbeos_scaffolding *scaffold); + +void nsbeos_attach_toplevel_view(nsbeos_scaffolding *g, BView *view); + +#if 0 /* GTK */ +void nsbeos_attach_toplevel_viewport(nsbeos_scaffolding *g, GtkViewport *vp); +#endif + +void nsbeos_scaffolding_dispatch_event(nsbeos_scaffolding *scaffold, BMessage *message); + +void nsbeos_scaffolding_destroy(nsbeos_scaffolding *scaffold); + +//void nsbeos_window_destroy_event(NSBrowserWindow *window, nsbeos_scaffolding *g, BMessage *event); + + +void nsbeos_scaffolding_popup_menu(nsbeos_scaffolding *g, BPoint where); + +#if 0 /* GTK */ +void nsbeos_scaffolding_popup_menu(nsbeos_scaffolding *g, guint button); +#endif + +#endif /* NETSURF_BEOS_SCAFFOLDING_H */ diff --git a/beos/beos_schedule.cpp b/beos/beos_schedule.cpp new file mode 100644 index 000000000..b91c26b49 --- /dev/null +++ b/beos/beos_schedule.cpp @@ -0,0 +1,209 @@ +/* + * Copyright 2006-2007 Daniel Silverstone + * + * 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 . + */ + +#include +#include +#include +#include + +extern "C" { +#include "desktop/browser.h" + +#ifdef DEBUG_BEOS_SCHEDULE +#include "utils/log.h" +#else +#define LOG(X) +#endif +} + +/** Killable callback closure embodiment. */ +typedef struct { + void (*callback)(void *); /**< The callback function. */ + void *context; /**< The context for the callback. */ + bool callback_killed; /**< Whether or not this was killed. */ + bool callback_fired; /**< Whether or not this has fired yet. */ + bigtime_t timeout; +} _nsbeos_callback_t; + +/** List of all callbacks. */ +static BList *callbacks = NULL; + +/** earliest deadline. It's used for select() in gui_poll() */ +bigtime_t earliest_callback_timeout = B_INFINITE_TIMEOUT; + +#warning XXX +#if 0 /* GTK */ +/** List of callbacks which have occurred and are pending running. */ +static GList *pending_callbacks = NULL; +/** List of callbacks which are queued to occur in the future. */ +static GList *queued_callbacks = NULL; +/** List of callbacks which are about to be run in this ::schedule_run. */ +static GList *this_run = NULL; + +static gboolean +nsbeos_schedule_generic_callback(gpointer data) +{ + _nsbeos_callback_t *cb = (_nsbeos_callback_t *)(data); + if (cb->callback_killed) { + /* This callback instance has been killed. */ + LOG(("CB at %p already dead.", cb)); + free(cb); + return FALSE; + } + LOG(("CB for %p(%p) set pending.", cb->callback, cb->context)); + /* The callback is alive, so move it to pending. */ + cb->callback_fired = true; + queued_callbacks = g_list_remove(queued_callbacks, cb); + pending_callbacks = g_list_append(pending_callbacks, cb); + return FALSE; +} +#endif + +static bool +nsbeos_schedule_kill_callback(void *_target, void *_match) +{ + _nsbeos_callback_t *target = (_nsbeos_callback_t *)_target; + _nsbeos_callback_t *match = (_nsbeos_callback_t *)_match; + if ((target->callback == match->callback) && + (target->context == match->context)) { + LOG(("Found match for %p(%p), killing.", + target->callback, target->context)); + target->callback = NULL; + target->context = NULL; + target->callback_killed = true; + } + return false; +} + +void +schedule_remove(void (*callback)(void *p), void *p) +{ + LOG(("schedule_remove() for %p(%p)", cb->callback, cb->context)); + if (callbacks == NULL) + return; + _nsbeos_callback_t cb_match; + cb_match.callback = callback; + cb_match.context = p; + + + callbacks->DoForEach(nsbeos_schedule_kill_callback, &cb_match); + +#warning XXX +#if 0 /* GTK */ + _nsbeos_callback_t cb_match = { + .callback = callback, + .context = p, + }; + + g_list_foreach(queued_callbacks, + nsbeos_schedule_kill_callback, &cb_match); + g_list_foreach(pending_callbacks, + nsbeos_schedule_kill_callback, &cb_match); + g_list_foreach(this_run, + nsbeos_schedule_kill_callback, &cb_match); +#endif +} + +void +schedule(int t, void (*callback)(void *p), void *p) +{ + LOG(("schedule(%d, %p, %p)", t, cb->callback, cb->context)); + if (callbacks == NULL) + callbacks = new BList; + + bigtime_t timeout = system_time() + t * 10 * 1000LL; + const int msec_timeout = t * 10; + _nsbeos_callback_t *cb = (_nsbeos_callback_t *)malloc(sizeof(_nsbeos_callback_t)); + /* Kill any pending schedule of this kind. */ + schedule_remove(callback, p); + cb->callback = callback; + cb->context = p; + cb->callback_killed = cb->callback_fired = false; + cb->timeout = timeout; + if (earliest_callback_timeout > timeout) + earliest_callback_timeout = timeout; + callbacks->AddItem(cb); + +#warning XXX +#if 0 /* GTK */ + const int msec_timeout = t * 10; + _nsbeos_callback_t *cb = malloc(sizeof(_nsbeos_callback_t)); + /* Kill any pending schedule of this kind. */ + schedule_remove(callback, p); + cb->callback = callback; + cb->context = p; + cb->callback_killed = cb->callback_fired = false; + /* Prepend is faster right now. */ + queued_callbacks = g_list_prepend(queued_callbacks, cb); + g_timeout_add(msec_timeout, nsbeos_schedule_generic_callback, cb); +#endif +} + +void +schedule_run(void) +{ + LOG(("schedule_run()")); + if (callbacks == NULL) + return; /* Nothing to do */ + + bigtime_t now = system_time(); + earliest_callback_timeout = B_INFINITE_TIMEOUT; + int32 i; + + LOG(("Checking %ld callbacks to for deadline.", this_run->CountItems())); + + /* Run all the callbacks which made it this far. */ + for (i = 0; i < callbacks->CountItems(); ) { + _nsbeos_callback_t *cb = (_nsbeos_callback_t *)(callbacks->ItemAt(i)); + if (cb->timeout > now) { + // update next deadline + if (earliest_callback_timeout > cb->timeout) + earliest_callback_timeout = cb->timeout; + i++; + continue; + } + LOG(("Running callbacks %p(%p).", cb->callback, cb->context)); + if (!cb->callback_killed) + cb->callback(cb->context); + callbacks->RemoveItem(cb); + free(cb); + } + +#warning XXX +#if 0 /* GTK */ + /* Capture this run of pending callbacks into the list. */ + this_run = pending_callbacks; + + if (this_run == NULL) + return; /* Nothing to do */ + + /* Clear the pending list. */ + pending_callbacks = NULL; + + LOG(("Captured a run of %d callbacks to fire.", g_list_length(this_run))); + + /* Run all the callbacks which made it this far. */ + while (this_run != NULL) { + _nsbeos_callback_t *cb = (_nsbeos_callback_t *)(this_run->data); + this_run = g_list_remove(this_run, this_run->data); + if (!cb->callback_killed) + cb->callback(cb->context); + free(cb); + } +#endif +} diff --git a/beos/beos_schedule.h b/beos/beos_schedule.h new file mode 100644 index 000000000..b7ffd074d --- /dev/null +++ b/beos/beos_schedule.h @@ -0,0 +1,26 @@ +/* + * Copyright 2006 Daniel Silverstone + * + * 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 . + */ + +#ifndef NETSURF_BEOS_CALLBACK_H +#define NETSURF_BEOS_CALLBACK_H 1 + +typedef void (*beos_callback)(void *p); + +extern bigtime_t earliest_callback_timeout; + +#endif /* NETSURF_BEOS_CALLBACK_H */ diff --git a/beos/beos_throbber.cpp b/beos/beos_throbber.cpp new file mode 100644 index 000000000..69cc09076 --- /dev/null +++ b/beos/beos_throbber.cpp @@ -0,0 +1,144 @@ +/* + * 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 . + */ + +#include +#include +extern "C" { +#include "utils/log.h" +#include "image/gifread.h" +} +#include "beos/beos_throbber.h" +#include "beos/beos_bitmap.h" + +struct nsbeos_throbber *nsbeos_throbber = NULL; + +bool nsbeos_throbber_initialise(const char *fn) +{ + /* disect the GIF provided by filename in *fn into a series of + * BBitmap for use later. + */ + struct gif_animation *gif; /**< structure for gifread.c */ + struct nsbeos_throbber *throb; /**< structure we generate */ + int i; + + FILE *fh = fopen(fn, "rb"); + + if (fh == NULL) { + LOG(("Unable to open throbber image '%s' for reading!", fn)); + return false; + } + + gif = (struct gif_animation *)malloc(sizeof(struct gif_animation)); + throb = (struct nsbeos_throbber *)malloc(sizeof(struct nsbeos_throbber)); + + /* discover the size of the data file. */ + fseek(fh, 0, SEEK_END); + gif->buffer_size = ftell(fh); + fseek(fh, 0, SEEK_SET); + + /* allocate a block of sufficient size, and load the data in. */ + gif->gif_data = (unsigned char *)malloc(gif->buffer_size); + fread(gif->gif_data, gif->buffer_size, 1, fh); + fclose(fh); + + /* set current position within GIF file to beginning, in order to + * signal to gifread that we're brand new. + */ + gif->buffer_position = 0; + + /* initialise the gif_animation structure. */ + switch (gif_initialise(gif)) + { + case GIF_INSUFFICIENT_FRAME_DATA: + case GIF_FRAME_DATA_ERROR: + case GIF_INSUFFICIENT_DATA: + case GIF_DATA_ERROR: + LOG(("GIF image '%s' appears invalid!", fn)); + free(gif->gif_data); + free(gif); + free(throb); + return false; + break; + case GIF_INSUFFICIENT_MEMORY: + LOG(("Ran out of memory decoding GIF image '%s'!", fn)); + free(gif->gif_data); + free(gif); + free(throb); + return false; + break; + } + + throb->nframes = gif->frame_count; + + if (throb->nframes < 2) + { + /* we need at least two frames - one for idle, one for active */ + LOG(("Insufficent number of frames in throbber image '%s'!", + fn)); + LOG(("(GIF contains %d frames, where 2 is a minimum.)", + throb->nframes)); + free(gif->gif_data); + free(gif); + free(throb); + return false; + } + + throb->framedata = (BBitmap **)malloc(sizeof(BBitmap *) + * throb->nframes); + + /* decode each frame in turn, extracting the struct bitmap * for each, + * and put that in our array of frames. + */ + for (i = 0; i < throb->nframes; i++) + { + gif_decode_frame(gif, i); + throb->framedata[i] = new BBitmap( + nsbeos_bitmap_get_primary(gif->frame_image)); + } + + gif_finalise(gif); + free(gif->gif_data); + free(gif); + + /* debug code: save out each frame as a PNG to make sure decoding is + * working correctly. + + for (i = 0; i < throb->nframes; i++) { + char fname[20]; + sprintf(fname, "frame%d.png", i); + gdk_pixbuf_save(throb->framedata[i], fname, "png", NULL, NULL); + } + */ + + nsbeos_throbber = throb; + + return true; +} + +void nsbeos_throbber_finalise(void) +{ + int i; + + for (i = 0; i < nsbeos_throbber->nframes; i++) + delete nsbeos_throbber->framedata[i]; + + free(nsbeos_throbber->framedata); + free(nsbeos_throbber); + + nsbeos_throbber = NULL; +} diff --git a/beos/beos_throbber.h b/beos/beos_throbber.h new file mode 100644 index 000000000..47f8249e6 --- /dev/null +++ b/beos/beos_throbber.h @@ -0,0 +1,35 @@ +/* + * 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 . + */ + +#ifndef __BEOS_THROBBER_H__ +#define __BEOS_THROBBER_H__ + +#include + +struct nsbeos_throbber +{ + int nframes; /**< Number of frames in the throbber */ + BBitmap **framedata; +}; + +extern struct nsbeos_throbber *nsbeos_throbber; + +bool nsbeos_throbber_initialise(const char *fn); +void nsbeos_throbber_finalise(void); + +#endif /* __BEOS_THROBBER_H__ */ diff --git a/beos/beos_thumbnail.cpp b/beos/beos_thumbnail.cpp new file mode 100644 index 000000000..7860e386e --- /dev/null +++ b/beos/beos_thumbnail.cpp @@ -0,0 +1,133 @@ +/* + * 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 . + */ + +/** \file + * Page thumbnail creation (implementation). + * + * Thumbnails are created by setting the current drawing contexts to a BView + * attached to the BBitmap we are passed, and plotting the page at a small + * scale. + */ + +#include +#include +#include +extern "C" { +#include "content/content.h" +#include "content/urldb.h" +#include "desktop/plotters.h" +#include "desktop/browser.h" +#include "image/bitmap.h" +#include "render/font.h" +#include "utils/log.h" +} +#include "beos/beos_scaffolding.h" +#include "beos/beos_plotters.h" +#include "beos/beos_bitmap.h" + +/** + * Create a thumbnail of a page. + * + * \param content content structure to thumbnail + * \param bitmap the bitmap to draw to + * \param url the URL the thumnail belongs to, or NULL + */ +bool thumbnail_create(struct content *content, struct bitmap *bitmap, + const char *url) +{ +#warning WRITEME +#if 0 /* GTK */ + GdkPixbuf *pixbuf; + gint width; + gint height; + gint depth; + GdkPixmap *pixmap; + GdkPixbuf *big; + + assert(content); + assert(bitmap); + + pixbuf = beos_bitmap_get_primary(bitmap); + width = gdk_pixbuf_get_width(pixbuf); + height = gdk_pixbuf_get_height(pixbuf); + depth = (gdk_screen_get_system_visual(gdk_screen_get_default()))->depth; + + LOG(("Trying to create a thumbnail pixmap for a content of %dx%d@%d", + content->width, content->width, depth)); + + pixmap = gdk_pixmap_new(NULL, content->width, content->width, depth); + + if (pixmap == NULL) { + /* the creation failed for some reason: most likely because + * we've been asked to create with with at least one dimention + * as zero. The RISC OS thumbnail generator returns false + * from here when it can't create a bitmap, so we assume it's + * safe to do so here too. + */ + return false; + } + + gdk_drawable_set_colormap(pixmap, gdk_colormap_get_system()); + + /* set the plotting functions up */ + plot = nsbeos_plotters; + + nsbeos_plot_set_scale(1.0); + + /* set to plot to pixmap */ + current_drawable = pixmap; + current_gc = gdk_gc_new(current_drawable); +#ifdef CAIRO_VERSION + current_cr = gdk_cairo_create(current_drawable); +#endif + plot.fill(0, 0, content->width, content->width, 0xffffffff); + + /* render the content */ + content_redraw(content, 0, 0, content->width, content->width, + 0, 0, content->width, content->width, 1.0, 0xFFFFFF); + + /* resample the large plot down to the size of our thumbnail */ + big = gdk_pixbuf_get_from_drawable(NULL, pixmap, NULL, 0, 0, 0, 0, + content->width, content->width); + + gdk_pixbuf_scale(big, pixbuf, 0, 0, width, height, 0, 0, + (double)width / (double)content->width, + (double)height / (double)content->width, + GDK_INTERP_TILES); + + /* As a debugging aid, try this to dump out a copy of the thumbnail as + * a PNG: gdk_pixbuf_save(pixbuf, "thumbnail.png", "png", NULL, NULL); + */ + + /* register the thumbnail with the URL */ + if (url) + urldb_set_thumbnail(url, bitmap); + + bitmap_modified(bitmap); + + g_object_unref(current_gc); +#ifdef CAIRO_VERSION + cairo_destroy(current_cr); +#endif + g_object_unref(pixmap); + g_object_unref(big); + + return true; +#endif + return false; +} diff --git a/beos/beos_treeview.cpp b/beos/beos_treeview.cpp new file mode 100644 index 000000000..965501892 --- /dev/null +++ b/beos/beos_treeview.cpp @@ -0,0 +1,130 @@ +/* + * Copyright 2004 Richard Wilson + * + * 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 . + */ + +/** \file + * Generic tree handling (implementation). + */ + + +extern "C" { +#include "utils/config.h" +#include "desktop/tree.h" +} + + +/** + * Sets the origin variables to the correct values for a specified tree + * + * \param tree the tree to set the origin for + */ +void tree_initialise_redraw(struct tree *tree) { +} + + +/** + * Informs the current window manager that an area requires updating. + * + * \param tree the tree that is requesting a redraw + * \param x the x co-ordinate of the redraw area + * \param y the y co-ordinate of the redraw area + * \param width the width of the redraw area + * \param height the height of the redraw area + */ +void tree_redraw_area(struct tree *tree, int x, int y, int width, int height) { +} + + +/** + * Draws a line. + * + * \param x the x co-ordinate + * \param x the y co-ordinate + * \param x the width of the line + * \param x the height of the line + */ +void tree_draw_line(int x, int y, int width, int height) { +} + + +/** + * Draws an element, including any expansion icons + * + * \param tree the tree to draw an element for + * \param element the element to draw + */ +void tree_draw_node_element(struct tree *tree, struct node_element *element) { +} + + +/** + * Draws an elements expansion icon + * + * \param tree the tree to draw the expansion for + * \param element the element to draw the expansion for + */ +void tree_draw_node_expansion(struct tree *tree, struct node *node) { +} + + +/** + * Recalculates the dimensions of a node element. + * + * \param element the element to recalculate + */ +void tree_recalculate_node_element(struct node_element *element) { +} + +/** + * Sets a node element as having a specific sprite. + * + * \param node the node to update + * \param sprite the sprite to use + * \param selected the expanded sprite name to use + */ +void tree_set_node_sprite(struct node *node, const char *sprite, + const char *expanded) { + +} + +/** + * Sets a node element as having a folder sprite + * + * \param node the node to update + */ +void tree_set_node_sprite_folder(struct node *node) { + +} + +/** + * Updates the node details for a URL node. + * The internal node dimensions are not updated. + * + * \param node the node to update + */ +void tree_update_URL_node(struct node *node, const char *url, + const struct url_data *data) { +} + + +/** + * Updates the tree owner following a tree resize + * + * \param tree the tree to update the owner of + */ +void tree_resized(struct tree *tree) { +} diff --git a/beos/beos_window.cpp b/beos/beos_window.cpp new file mode 100644 index 000000000..36b01acc5 --- /dev/null +++ b/beos/beos_window.cpp @@ -0,0 +1,1570 @@ +/* + * 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 . + */ + +#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), + 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) +{ + 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; +} diff --git a/beos/beos_window.h b/beos/beos_window.h new file mode 100644 index 000000000..6dd3ecdd7 --- /dev/null +++ b/beos/beos_window.h @@ -0,0 +1,64 @@ +/* + * Copyright 2006 Daniel Silverstone + * + * 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 . + */ + +#ifndef NETSURF_BEOS_WINDOW_H +#define NETSURF_BEOS_WINDOW_H 1 + +extern "C" { +#include "desktop/gui.h" +#include "desktop/browser.h" +} +#include "beos/beos_scaffolding.h" + +class NSBrowserFrameView : public BView { +public: + NSBrowserFrameView(BRect frame, struct gui_window *gui); +virtual ~NSBrowserFrameView(); + +virtual void MessageReceived(BMessage *message); +virtual void Draw(BRect updateRect); + +//virtual void FrameMoved(BPoint new_location); +virtual void FrameResized(float new_width, float new_height); + +virtual void KeyDown(const char *bytes, int32 numBytes); +virtual void MouseDown(BPoint where); +virtual void MouseUp(BPoint where); +virtual void MouseMoved(BPoint where, uint32 transit, const BMessage *msg); + +private: + struct gui_window *fGuiWindow; +}; + +void nsbeos_dispatch_event(BMessage *message); + + + +void nsbeos_reflow_all_windows(void); +void nsbeos_window_process_reformats(void); + +nsbeos_scaffolding *nsbeos_get_scaffold(struct gui_window *g); +struct browser_window *nsbeos_get_browser_for_gui(struct gui_window *g); + +float nsbeos_get_scale_for_gui(struct gui_window *g); +int nsbeos_gui_window_update_targets(struct gui_window *g); +void nsbeos_window_destroy_browser(struct gui_window *g); + +struct browser_window *nsbeos_get_browser_window(struct gui_window *g); + +#endif /* NETSURF_BEOS_WINDOW_H */ diff --git a/beos/options.h b/beos/options.h new file mode 100644 index 000000000..f98d2a467 --- /dev/null +++ b/beos/options.h @@ -0,0 +1,37 @@ +/* + * 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 . + */ + +#ifndef _NETSURF_BEOS_OPTIONS_H_ +#define _NETSURF_BEOS_OPTIONS_H_ + +#include "desktop/options.h" + +extern bool option_render_cairo; +extern bool option_render_resample; +extern char *option_url_file; + +#define EXTRA_OPTION_DEFINE \ +bool option_render_cairo = true; \ +bool option_render_resample = false; \ +char *option_url_file = 0; + +#define EXTRA_OPTION_TABLE \ +{ "render_cairo", OPTION_BOOL, &option_render_cairo }, \ +{ "render_resample", OPTION_BOOL, &option_render_resample }, \ +{ "url_file", OPTION_STRING, &option_url_file }, +#endif diff --git a/beos/res/adblock.css b/beos/res/adblock.css new file mode 120000 index 000000000..e3811f62b --- /dev/null +++ b/beos/res/adblock.css @@ -0,0 +1 @@ +../../!NetSurf/Resources/AdBlock,f79 \ No newline at end of file diff --git a/beos/res/beosdefault.css b/beos/res/beosdefault.css new file mode 100644 index 000000000..9021eedd9 --- /dev/null +++ b/beos/res/beosdefault.css @@ -0,0 +1,21 @@ +/* + * This file is part of NetSurf, http://netsurf-browser.org/ + */ + +/* Load base stylesheet. */ + +@import "default.css"; + +/* Apply GTK specific rules. */ + +input { font-size: 95%; border: medium inset #ddd; } +input[type=button], input[type=reset], input[type=submit], button { + background-color: #ddd; border: medium outset #ddd; } +input[type=checkbox], input[type=radio] { font-size: 105%; } +input[type=file] { background-color: #ddd; border: medium inset #ddd; } + +select { background-color: #ddd; border: medium inset #ddd; font-size: 95%; } +select:after { border-left:4px ridge #ddd; } + +textarea { font-size: 95%; border: medium inset #ddd; } + diff --git a/beos/res/ca-bundle.txt b/beos/res/ca-bundle.txt new file mode 120000 index 000000000..ad2dd6b55 --- /dev/null +++ b/beos/res/ca-bundle.txt @@ -0,0 +1 @@ +../../!NetSurf/Resources/ca-bundle \ No newline at end of file diff --git a/beos/res/default.css b/beos/res/default.css new file mode 120000 index 000000000..6d2d4da5b --- /dev/null +++ b/beos/res/default.css @@ -0,0 +1 @@ +../../!NetSurf/Resources/CSS,f79 \ No newline at end of file diff --git a/beos/res/messages b/beos/res/messages new file mode 120000 index 000000000..f4a4d2bba --- /dev/null +++ b/beos/res/messages @@ -0,0 +1 @@ +../../!NetSurf/Resources/en/Messages \ No newline at end of file diff --git a/beos/res/netsurf.xpm b/beos/res/netsurf.xpm new file mode 100644 index 000000000..7061727d6 --- /dev/null +++ b/beos/res/netsurf.xpm @@ -0,0 +1,317 @@ +/* XPM */ +static char *netsurf[] = { +/* columns rows colors chars-per-pixel */ +"132 135 176 2", +" c black", +". c #010101", +"X c #010202", +"o c #030406", +"O c #040A0D", +"+ c #060E14", +"@ c #08141A", +"# c #081720", +"$ c #091B27", +"% c #0F2430", +"& c #142E3D", +"* c #143548", +"= c #153C53", +"- c #194662", +"; c #1E516E", +": c #1D577A", +"> c #175B87", +", c #1A6595", +"< c #1E6B9C", +"1 c #26709C", +"2 c #33789E", +"3 c #3188BD", +"4 c #3E89B3", +"5 c #1F92DD", +"6 c #0E9CFD", +"7 c #0E9DFF", +"8 c #0F9EFF", +"9 c #1A95E7", +"0 c #1898ED", +"q c #1299F4", +"w c #119BF9", +"e c #119FFF", +"r c #14A0FF", +"t c #15A1FF", +"y c #17A2FF", +"u c #18A3FF", +"i c #1AA3FE", +"p c #1BA4FE", +"a c #1CA5FE", +"s c #1EA5FE", +"d c #1FA6FE", +"f c #268AC9", +"g c #218ED3", +"h c #20A6FE", +"j c #21A7FE", +"k c #23A8FE", +"l c #24A8FE", +"z c #25A8FE", +"x c #26A9FE", +"c c #27AAFE", +"v c #28AAFE", +"b c #2AABFF", +"n c #2BACFF", +"m c #2CADFF", +"M c #2EAEFF", +"N c #2FAEFF", +"B c #31AFFE", +"V c #31AFFF", +"C c #32B0FF", +"Z c #34B1FF", +"A c #35B2FF", +"S c #36B2FF", +"D c #37B2FF", +"F c #3AB2FB", +"G c #38B3FE", +"H c #39B3FE", +"J c #3AB3FC", +"K c #3BB4FE", +"L c #3CB5FE", +"P c #3DB5FE", +"I c #3EB6FF", +"U c #3FB7FF", +"Y c #4182A4", +"T c #4789AB", +"R c #43B7FB", +"E c #40B7FF", +"W c #44B6FA", +"Q c #42B8FE", +"! c #44B9FE", +"~ c #46BAFF", +"^ c #47BAFF", +"/ c #48BBFF", +"( c #49BCFF", +") c #4ABCFF", +"_ c #4CBDFF", +"` c #4EBEFF", +"' c #50BFFE", +"] c #50BFFF", +"[ c #51BFFF", +"{ c #5ABFF7", +"} c #52C0FE", +"| c #54C1FE", +" . c #56C2FF", +".. c #57C3FF", +"X. c #58C3FE", +"o. c #58C3FF", +"O. c #5CC1F8", +"+. c #5DC4FD", +"@. c #5CC5FE", +"#. c #5DC5FE", +"$. c #5DC6FF", +"%. c #5EC6FF", +"&. c #5FC7FF", +"*. c #61C8FF", +"=. c #62C8FF", +"-. c #63C9FF", +";. c #65CAFF", +":. c #66CBFF", +">. c #67CBFF", +",. c #68CCFF", +"<. c #69CDFF", +"1. c #6BCDFF", +"2. c #6CCEFF", +"3. c #6DCEFF", +"4. c #6FCFFF", +"5. c #70D0FF", +"6. c #72D1FF", +"7. c #73D1FF", +"8. c #74D2FF", +"9. c #76D3FF", +"0. c #77D3FF", +"q. c #78D4FF", +"w. c #79D5FF", +"e. c #7AD5FF", +"r. c #7CD6FF", +"t. c #7ED7FF", +"y. c #7FD8FF", +"u. c #81CBE7", +"i. c #82CBE7", +"p. c #83CEEB", +"a. c #81D4F7", +"s. c #84D3F4", +"d. c #80D7FE", +"f. c #80D8FF", +"g. c #84DAFF", +"h. c #85DAFF", +"j. c #86DBFF", +"k. c #87DBFF", +"l. c #89DCFF", +"z. c #8ADDFF", +"x. c #8BDEFF", +"c. c #8DDEFF", +"v. c #8EDEFF", +"b. c #8FDFFF", +"n. c #91E0FF", +"m. c #92E1FF", +"M. c #93E2FF", +"N. c #95E3FF", +"B. c #97E3FF", +"V. c #98E4FF", +"C. c #99E4FE", +"Z. c #9BE5FE", +"A. c #9CE6FE", +"S. c #9EE6FF", +"D. c #9FE7FF", +"F. c #A1E8FF", +"G. c #A3E9FF", +"H. c #A5EBFF", +"J. c #A6ECFF", +"K. c #A8EDFF", +"L. c #ABEEFF", +"P. c #ADEFFF", +"I. c #B0F0FF", +"U. c #B3F1FF", +"Y. c #B7F2FF", +"T. c #C7F3FF", +"R. c #DCF6FF", +"E. c #EAF8FF", +"W. c #F1FAFF", +"Q. c #F8FCFF", +"!. c #FCFEFF", +"~. c #FDFEFF", +"^. c #FEFEFF", +"/. c #FEFFFF", +"(. c gray100", +"). c None", +/* pixels */ +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). % ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). O & ; 2 T O.O.a.r.e.e.e.q.9.9.4.{ { T 2 ; % O ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). @ - T r.l.k.k.k.y.t.t.t.t.r.e.e.q.9.8.8.8.8.4.4.1.1.1.{ T ; # ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). = Y p.v.x.x.s.v.k.k.k.a.g.t.y.t.r.e.e.q.9.8.8.8.2.4.4.4.4.,.,.;.;.;.O.4 = o ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). % 2 u.m.m.v.v.c.x.x.l.k.k.k.k.g.t.y.t.t.r.e.e.q.9.8.8.8.8.4.4.1.1.,.,.;.;.-.-.-.{ 2 & ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). O ; u.B.m.m.m.m.m.v.c.c.x.x.x.k.k.k.g.g.g.t.t.r.e.e.q.9.9.8.8.2.2.8.2.1.1.,.,.;.;.-.*.*.$.$.! : + ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). O : p.C.C.B.B.B.m.m.m.m.c.c.c.c.x.k.l.k.k.g.y.g.t.t.r.e.e.q.q.8.9.2.2.4.2.1.1.1.,.;.;.-.-.-.&.$.$.+.O.2 @ ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).). + 2 s.A.A.C.C.C.B.m.N.m.M.m.m.m.c.l.x.x.l.k.k.g.g.t.f.t.r.r.e.q.9.9.8.8.8.8.8.1.2.,.,.,.;.-.-.&.&.&.$.+... .| 2 @ ).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).). = p.F.F.A.A.A.C.C.C.C.N.N.m.m.m.m.v.v.c.x.l.l.g.k.g.t.f.f.t.r.e.e.q.9.8.8.8.2.8.2.2.1.,.,.,.;.-.&.-.&.+.+....... .` 1 O ).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).). ; A.F.F.A.A.A.A.C.C.C.N.N.N.m.m.m.v.c.x.x.l.k.k.g.g.f.f.t.r.e.e.q.9.q.8.8.8.2.2.2.1.,.,.;.;.-.-.&.&.$.+.$..... .| | W = ).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).). o T F.F.F.A.F.S.A.A.C.C.C.N.M.M.m.m.c.c.c.x.l.k.k.g.g.f.f.f.t.t.e.e.q.9.9.8.5.5.4.1.1.1.;.,.-.-.-.-.$.*.$.+.o. . . .| | ` T # ).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).). * & p.F.F.F.A.F.F.A.A.A.C.C.N.N.M.M.m.m.c.c.x.x.k.k.k.g.h.f.f.t.r.r.e.q.9.9.8.5.5.4.4.4.1.1.;.,.;.-.-.&.$.$.+. . . . .| | ` ` W ; ).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).). 2 A. % J.J.F.J.F.F.S.F.F.A.A.C.C.C.N.M.m.m.c.c.c.x.x.l.k.k.f.t.t.t.t.r.e.q.0.9.9.8.5.4.4.1.1.,.,.;.-.-.&.-.$.$.$.o.+... .| | ` ) ) ) 2 O ).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).). @ u.J.T ; J.J.J.F.J.F.F.F.A.A.D.C.N.C.N.M.M.m.m.m.x.x.x.l.k.k.k.k.f.f.t.r.r.q.0.9.5.5.5.5.4.4.1.,.,.;.;.-.-.&.$.$.+.o. ... .| | ` | [ ) ( 5 $ ).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).). & p.K.K.: T J.J.J.J.F.G.F.F.F.F.A.A.N.C.C.N.M.m.m.c.c.c.x.x.l.k.g.g.t.t.t.r.r.q.0.0.9.8.5.5.4.3.1.,.,.,.;.-.-.&.h.k.+.$.o. . . .| ` ` ` | ( ( W - ).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).). = F.K.P.K.& p.K.J.J.J.J.F.F.F.A.F.D.A.A.C.C.N.M.M.m.m.c.c.x.l.l.k.k.g.g.g.t.r.r.r.e.0.9.9.5.5.4.4.1.1.,.;.,.-.-.,.Q./.8.o.o.o. .[ ` | | ` ) ) ( ( ( ; ).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).). ; J.K.P.P.F. % K.P.K.J.J.J.G.G.G.F.A.D.A.A.C.C.N.N.M.m.m.m.v.x.x.l.k.g.g.t.y.t.t.r.q.0.0.9.7.9.5.4.4.2.1.,.,.;.;.-.F././.T.$.o.o. . .| ) ` ) ) ) ( ( ! ! , ).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).). : K.K.P.P.P.u. ; P.K.P.K.K.J.J.J.G.F.F.D.D.D.C.C.N.N.M.m.m.c.v.c.x.l.k.k.g.k.y.t.r.r.r.0.0.9.9.5.5.4.4.2.1.,.;.,.;.,.W./././.l.o. . . . .| | ` ) ) ( ( ^ ! Q 1 ).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).). Y K.K.P.P.P.I.Y T P.P.P.K.K.J.J.J.F.G.F.D.D.A.A.N.N.N.N.M.m.m.c.c.c.x.l.k.g.g.y.t.t.t.r.w.q.q.8.7.5.5.4.2.1.,.,.;.;.F././././.E.+. . . .| | ) ` ) ) ) ( / ! ! W 2 ).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).). 2 K.P.P.P.P.P.I.P.u.T ; % i.I.I.P.P.P.K.J.J.J.G.F.D.D.D.A.C.C.N.N.m.m.m.c.c.x.l.l.g.k.g.y.t.t.r.r.w.q.8.8.7.5.5.5.2.1.,.,.;.;.E./././././.P. . . .| | | ) ) ` ( 1.K.0.! E Q 1 ).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).). ; J.K.P.P.P.I.I.U.U.U.U.U.U.U.I.I.P.P.P.K.J.J.J.G.G.D.D.D.A.D.C.C.N.N.m.N.c.c.x.l.l.g.k.g.y.g.t.r.r.r.q.q.8.7.5.5.5.2.2.,.,.;.C./././././././.4.o.o.| | ) | $.C.R././.U.! ! U L > ).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).). * F.J.K.K.P.I.I.U.U.U.U.U.U.U.U.U.I.I.P.K.K.J.J.J.G.G.D.D.D.D.C.N.C.N.m.m.m.c.c.x.x.l.k.k.k.y.t.t.r.r.q.q.8.8.9.5.5.5.2.2.,.,.;.E./././././././.T.o.[ | .v.T./.!././.!.k.! E Q L L - ).).).).).).).).).).).).).).", +").).).).).).).).).).).).).). & C.J.K.K.P.P.I.I.U.U.U.Y.Y.Y.U.U.U.I.I.P.P.P.K.J.G.J.F.D.D.D.A.C.C.N.N.M.m.m.m.c.x.l.l.k.k.g.y.y.y.r.r.r.M.R.U.C.9.5.5.2.2.1.,.v.!././././././././.k.d.T././././././././.+.! ! E E L G * ).).).).).).).).).).).).).", +").).).).).).).).).).).).). + p.J.J.K.P.P.P.I.I.U.U.Y.Y.Y.Y.Y.U.U.U.I.P.P.K.K.J.J.J.F.F.D.D.A.D.N.C.N.M.m.m.c.c.x.x.l.z.g.g.y.g.y.r.r.r.L./.!././.R.U.m.2.1.>.R./././././././././././././././././././.W.! ! E E E L L F $ ).).).).).).).).).).).).", +").).).).).).).).).).).).). T G.J.J.K.K.P.P.I.I.U.U.Y.Y.Y.Y.Y.U.U.I.I.P.P.P.K.J.J.J.G.F.D.D.A.D.C.C.N.M.m.M.c.c.x.x.l.k.k.g.y.t.y.t.r.q.r.!./././././././.R.T././././././././././././././././././././.Y.! ! ! E L L L K g o ).).).).).).).).).).).).", +").).).).).).).).).).).). ; J.G.J.J.K.K.P.P.I.I.U.U.U.Y.Y.Y.U.U.U.I.I.P.P.P.K.J.G.J.G.F.D.D.D.C.N.C.N.M.m.M.c.c.x.l.l.k.g.g.y.t.y.r.r.r.q.T.!././././././././.!././././././././././././././././././.Q.v.! ! E E E L L K G , ).).).).).).).).).).).", +").).).).).).).).).).). & A.J.F.J.J.J.J.L.P.P.I.U.U.U.U.U.U.U.U.U.I.I.P.P.P.K.J.J.F.F.F.D.D.A.A.N.C.N.M.m.m.c.c.x.l.l.k.k.h.f.f.f.r.r.r.0.A.^././././././././././././././././././././././././././././.*.! ! E E E L L L G D * ).).).).).).).).).).", +").).).).).).).).).).). O u.A.F.F.J.J.J.K.K.P.P.I.I.U.U.U.U.U.U.U.I.I.P.P.K.K.J.J.J.F.J.D.D.D.A.A.C.N.N.M.m.m.m.c.x.x.l.k.k.f.f.f.r.r.r.0.0.0.Q./././././././././././././././././././././././././././.W.! ! ! E E L L L P G D B @ ).).).).).).).).).).", +").).).).).).).).).). Y F.D.F.J.J.J.J.K.L.P.P.P.I.I.I.U.U.U.U.I.I.I.P.P.K.K.J.J.J.G.F.D.D.D.A.C.C.C.N.m.m.m.c.c.x.l.l.k.k.h.f.f.r.r.r.e.0.9.T.^././././././././././././././././././././././././././.T./ ! ! ! E E L L G G D D 1 ).).).).).).).).).", +").).).).).).).).).). $ N.D.D.F.F.G.J.J.K.K.L.L.P.P.I.I.I.I.I.I.I.I.P.P.P.K.J.J.J.G.G.F.D.D.A.D.C.N.N.M.N.m.m.c.c.x.x.l.k.f.h.f.f.f.r.e.e.e.9.n.^./././././././././././././././././././././././././.Q.K.! ! ! E E L L L G D D B V & ).).).).).).).).).", +").).).).).).).).). T A.F.D.D.F.F.J.J.J.J.K.L.L.T : T i.J.I.I.P.P.P.K.K.K.J.J.G.G.G.F.D.D.A.C.C.N.N.M.m.m.m.v.v.l.x.k.k.g.g.t.f.f.r.e.e.e.9.9.W./././././././././././././././././././././././././.^.^.R.g.W E E P P P G G D D V g ).).).).).).).).", +").).).).).).).).). ; C.A.A.D.D.F.F.F.J.J.J.K.K.L.& K.P.P.P.P.K.K.J.J.J.F.G.F.A.D.D.A.C.C.C.N.M.m.m.c.c.x.x.k.k.k.g.f.f.f.r.r.e.0.0.9.8.Y./././././././././././././././././././././././././././././.E.v.W P P G G G D V V N - ).).).).).).).).", +").).).).).).).). o u.C.C.A.D.D.F.F.F.J.G.J.J.J.K.+ % P.K.K.P.K.K.K.J.J.G.F.F.F.F.D.A.D.C.C.N.M.M.m.m.m.l.x.x.l.k.k.g.f.f.f.r.r.e.9.9.9.8.h./././././././././././././././././././././././././././././././.W.n.^ P G G D D V V b + ).).).).).).).", +").).).).).).).). ; B.C.C.A.A.D.D.D.F.F.G.J.G.K.A. = K.K.K.K.J.J.K.G.J.G.G.F.F.A.A.A.C.C.N.N.M.m.m.c.v.v.x.l.l.k.k.k.f.f.r.r.r.e.0.9.8.8.B.^./././././././././././././././././././././././././././././././.!.Q.F./ G D V V V N : ).).).).).).).", +").).).).).).). p.B.N.C.C.D.A.D.D.F.F.G.G.G.J.r. ; J.J.J.J.J.J.J.F.G.G.F.F.S.F.A.C.C.C.N.N.M.m.N.c.x.x.z.z.z.g.g.g.g.t.t.r.r.q.0.0.h.R./././././././././././././././././././././././././././././././././././.Q./.2.A C C V N 0 O ).).).).).).", +").).).).).).). ; N.N.N.N.C.C.D.D.D.D.F.F.G.G.K.i. 2 J.J.G.J.J.J.G.G.F.F.F.A.A.A.A.C.C.N.N.N.M.m.m.c.c.x.z.z.g.k.g.t.y.y.t.r.r.q.0.Y./././././././././././././././././././././././././././././././././././././.Q.E.&.A C C N N m ; ).).).).).).", +").).).).).). r.m.B.B.N.C.C.A.A.D.D.D.F.F.G.G.Y X Y J.G.J.J.G.G.G.F.F.S.F.S.A.A.C.C.C.N.M.M.m.M.c.c.x.x.z.k.k.g.g.g.t.t.r.r.q.D.W././././././././././././././././././././././././././././././././././././.^./.G.U A A C C V N m 9 o ).).).).).", +").).).).).). = n.m.m.m.N.C.C.C.A.A.D.D.A.F.G.G.Y X T G.G.G.F.G.F.F.F.A.F.S.A.A.A.C.C.N.N.M.m.m.c.c.c.x.z.z.k.g.g.g.t.t.t.r.k.R././././././././././././././././././././././././././././././././././././././.T.o.G K A C C V V N m N - ).).).).).", +").).).).).). X X T n.n.n.n.N.N.C.C.C.A.A.A.F.A.F.A.: u.F.F.F.F.F.A.F.A.A.F.A.A.C.C.N.C.N.M.M.m.m.c.c.x.x.x.k.k.k.g.f.f.t.t.N./.!./././././././././././././././././././././././././././././././././././.Q.W.r.P G G A A D V V V N m b f ).).).).).", +").).).).). X @ s.n.n.C.n.m.B.N.N.C.C.A.A.Z.F.S.F.; u.F.F.F.F.A.F.F.F.A.A.A.C.C.C.C.N.m.M.m.M.c.c.c.x.l.l.k.k.g.g.f.f.t.r.m.W././././././././././././././././././././././././././././././././././.^.^.G./ L P P G A A D V V N m m b b # ).).).).", +").).).).). - n.b.M.n.n.m.m.B.m.C.B.C.C.A.A.A.F.= B.A.F.F.A.A.F.A.A.A.C.C.B.C.B.N.M.M.m.m.c.c.c.x.l.l.k.k.g.g.g.f.f.t.r.e.e.J.E././././././././././././././././././././././././././././././././.^.*.E E L L P G A A V V V N m N N b : ).).).).", +").).).).). e.b.b.s.n.n.m.m.m.B.B.B.C.C.C.C.A.A.* F.F.A.A.A.A.A.A.C.C.B.C.C.m.B.M.M.m.m.c.m.c.x.x.x.l.k.k.g.t.t.f.t.e.e.e.e.9.9.A.R././././././././././././././././././././././././././././././.Q.r.E L L L P G K A A V N N m b b b g ).).).).", +").).).). % x.l.x.c.c.c.M.m.m.M.M.N.N.C.C.C.C.C.C.D.D.A.A.A.A.A.A.C.A.C.C.C.N.C.N.N.M.M.M.m.m.c.m.l.c.x.x.k.k.k.g.g.g.t.t.t.r.e.e.q.9.8.8.8.m.R./././././././././././././././././././././././././././././.T.Q L L L K K D V V C V N m m b c c % ).).).", +").).).). 2 l.x.x.x.c.c.c.m.m.m.M.M.N.N.N.C.N.C.N.C.C.C.C.C.C.C.C.C.C.C.C.C.C.N.N.M.m.m.m.m.m.c.v.v.c.l.k.k.k.g.g.y.y.t.t.r.e.e.q.9.9.8.8.4.2.4.l.T././././././././././././././././././././././././././././.) E L J A A D V C V N N m m b c c > ).).).", +").).).). T k.k.x.x.x.c.c.c.m.m.m.M.M.M.N.N.N.N.C.C.C.C.C.N.C.C.N.C.N.C.N.N.N.M.M.M.m.m.m.c.m.c.c.x.x.l.k.k.k.g.y.g.t.t.r.e.e.e.q.9.8.8.2.8.4.4.1.1.J.!./././././././././././././././././././././././././.!.N.L L L J D A A C V N m m m b c c f ).).).", +").).).). O a.k.k.l.l.x.x.c.c.c.m.m.m.m.M.N.m.N.N.N.N.N.N.B.B.N.C.N.N.N.N.M.M.M.M.m.m.m.m.c.v.v.l.x.l.l.k.k.g.g.g.y.y.t.t.r.e.e.q.8.8.8.8.8.2.4.1.1.,.T./././././././././././././././././././././././././././.R.L L L A D A C C V N m b b b c c k + ).).", +").).). * g.k.g.k.l.x.l.x.c.c.c.c.m.m.m.m.m.m.M.M.M.M.M.N.N.N.m.B.M.M.M.M.M.m.m.m.m.c.c.c.x.x.x.x.l.k.k.k.g.g.g.f.t.t.r.r.e.q.9.9.8.8.8.2.4.4.4.1.,.W././././././././././././././././././././././././././././.;.K K A D A V V V N N b m b c c k * ).).", +").).). 2 k.g.k.k.k.l.l.l.x.x.c.c.m.v.m.m.m.m.m.m.M.M.M.M.M.m.m.m.m.m.m.m.M.m.m.c.m.c.c.c.x.x.x.l.k.k.k.g.k.t.y.t.t.r.r.e.e.q.9.8.8.8.2.8.4.1.1.1.e././././././././././././././././././././././././././././.W.P.K A G D A V V V N m m b c c c k > ).).", +").).). O.t.g.g.k.k.k.l.l.x.x.x.c.c.v.c.c.m.m.m.m.m.M.M.m.m.m.m.m.m.m.m.m.c.m.c.c.c.c.x.x.l.x.k.k.k.k.g.g.t.f.t.t.t.e.e.e.q.9.9.8.8.4.2.4.4.1.1.;.A.!./././././././././././././././././././.Q././././././././.Q.U K A A A V V V m m m b c c k k g ).).", +").).). X a.f.t.t.g.g.k.k.k.l.x.l.x.l.v.v.c.c.c.c.m.c.c.M.m.m.m.m.m.c.m.c.c.c.c.c.c.x.x.x.x.l.k.g.k.g.g.g.t.g.t.t.r.r.e.e.q.q.9.8.8.8.4.4.4.1.4.;.1.T././././././././././././././././././././.C.U.W./.W././././.Q.g.K A A V V V N m b b b c c k k k o ).).", +").).). $ d.f.f.f.f.h.h.k.k.k.k.l.x.z.x.x.x.x.x.c.c.c.c.c.c.c.c.m.c.c.c.c.c.c.x.x.x.x.x.k.l.k.k.k.g.g.g.g.t.y.t.r.e.e.e.q.9.9.8.8.8.8.2.8.1.1.,.,.,.W./././././././././.W.^./././././././.^.T./ ! ! *.C.T./.Q.E.!.T.D A A V V V N b N v v c c k k j $ ).).", +").). = r.r.f.f.f.f.h.f.k.k.k.k.z.k.z.z.z.x.x.x.x.c.c.c.v.v.v.v.c.c.c.x.x.x.l.x.x.k.k.k.k.k.g.g.k.t.t.y.t.t.r.r.e.q.q.q.9.8.8.8.4.2.8.2.4.1.,.,.9./././././././.E.K.1.8.^./././././././.^.9./ / ! ! ! L Q 8.F.R.R.A A A V V N b N v N v c j k j j * ).", +").). : r.r.t.t.f.f.f.f.g.g.k.k.k.k.x.k.l.x.x.l.x.x.x.x.x.x.l.x.x.x.x.l.l.x.l.l.z.k.g.k.k.g.g.g.g.t.t.t.r.r.r.r.q.q.9.q.8.8.8.4.2.2.2.2.1.,.,.,.A./././.!.Q.U.w.$. .o. .P./././././././.R./ / ! ! E E E U K K K J D V C C V N b b b v v c j k j d ; ).", +").). Y e.r.r.t.t.f.f.f.t.g.g.g.k.g.k.k.k.l.l.l.Y ; ; = & s.x.l.l.l.l.l.l.l.k.k.g.k.k.g.g.k.t.t.y.y.t.t.r.r.r.w.q.q.8.8.8.8.8.2.4.8.1.1.,.,.,.;.T././.T.x.&.&.+.+. .o. .+.W././././././.d.! / W ! ! E L U K K A D D C V V V N N b b v c c j k j d , ).", +").). T e.e.e.e.r.r.t.f.t.g.t.k.g.g.g.k.k.k.k.g.; r.l.l.l.h.k.k.k.k.k.k.k.g.g.g.t.y.y.g.t.t.r.r.r.r.q.q.q.8.8.8.8.4.2.8.4.4.1.,.>.1.;.;.9.A.;.*.&.$.$.$.o.o. . .[ k./././././.E.( / ! ! ! ! L E L L K K A A C C V N N m v v v v j c j d d f ).", +").). { q.e.e.e.r.r.t.r.t.t.t.g.t.g.g.g.g.g.k.k.; i.h.h.k.k.k.k.k.g.g.g.g.g.g.y.t.g.y.t.t.r.r.w.w.w.q.q.q.8.8.8.4.4.4.4.4.1.1.,.1.>.;.;.*.*.*.*.$.$.+...o. . . . .[ T././././.v./ / ! ! E E E L K K K A A C C V V N m b N v v c z j j d d g ).", +").). { 9.9.e.e.e.r.r.r.t.t.y.y.y.g.t.t.g.k.g.k.2 T h.h.h.h.f.k.g.g.g.t.t.y.g.t.t.t.t.r.r.r.r.w.q.q.q.8.8.8.8.8.2.4.4.1.1.1.,.,.;.;.;.-.-.*.$.$.+.+.+.o. . . . .[ [ ;./././.Q.) / / ! Q ! L L L U K K A A A C V V m m m v v c c j c j d d 9 ).", +").). 5.8.9.9.q.e.e.e.r.r.r.t.t.y.y.t.g.t.t.t.t.T Y h.h.f.k.f.f.t.t.y.g.y.y.t.t.t.r.r.r.r.w.q.q.q.8.q.8.8.8.2.2.8.4.4.1.1.,.,.1.;.;.-.-.*.*.*.$.+.+.+.o. . . .[ [ [ [ K.!.!.B./ ! ! ! Q E E E L K A K A A V C V N m m b v c c z j j d d d 0 ).", +").). 8.8.8.9.8.q.q.q.e.e.r.r.r.r.t.r.f.f.f.f.f.{ ; f.f.f.f.f.f.f.f.t.f.t.t.r.r.r.e.e.e.e.q.q.9.q.8.8.8.8.2.5.5.4.4.1.1.,.,.,.,.-.-.-.-.&.&.$.$.+....... . .| | ) | ) | E.!.[ / / ! Q Q E L L L K A K A A V V V N m b m v c c k k j d d p p ).", +").). O 8.8.8.8.8.9.9.q.q.e.e.e.e.r.r.r.r.t.t.t.t.u. = f.f.f.t.f.f.t.t.t.t.r.r.r.e.e.e.e.q.q.9.9.8.8.8.8.8.8.8.2.2.1.1.1.,.,.;.;.;.-.-.&.-.&.$.$.$.+. ..... .| | | | ) ) ( ;.-.! ! ! ! Q E L E L L K A A C C V N N m m b b c c c k j d d d i i O ).", +").). @ 2.4.8.8.8.8.9.9.9.q.q.e.e.e.e.e.r.r.r.r.r.r.O % t.t.t.t.r.r.r.r.r.r.r.e.e.e.e.q.q.9.9.9.8.8.8.8.8.2.2.2.5.2.1.1.,.,.;.,.;.-.-.-.&.&.$.$.$.+...+. . .| ` | ` ` | ) ) ( / / ! ! Q Q E E L L L A K A A C V V N m m m b c c k k j j d p p y + ).", +").). @ 4.4.4.8.8.8.8.8.8.9.q.q.q.e.e.e.e.e.e.r.r.r.% + r.r.r.r.r.e.r.e.e.e.e.e.q.q.e.9.9.9.8.8.8.8.8.2.8.2.2.8.2.2.1.,.1.;.,.;.-.-.-.&.&.$.$.+.$. ... . . .| | ` ` ) ` ) ) / ( ! ! ! Q E L L L L G K A C C C V V N m b b c c c k k j d d p p i @ ).", +").). O 4.4.4.2.8.8.8.8.8.8.9.9.9.9.q.q.q.e.e.e.e.e.* r.e.e.e.e.e.e.e.q.q.q.q.9.9.9.9.8.8.9.8.8.8.2.2.8.2.2.2.2.2.,.,.,.;.-.-.-.&.&.&.$.$.+.+..... . . .| | | | ) ) ` ( ( ( ! ! ! W E E E L L P G K A C C V N N m b m b c c k k d d d d p p y O ).", +").). 4.1.4.8.2.2.8.8.8.8.8.8.8.9.8.9.9.q.q.q.q.e.: Y e.q.e.q.q.e.e.q.q.9.9.9.8.8.8.8.8.8.2.4.2.2.8.2.4.2.2.:.:.,.,.,.;.-.-.-.-.&.&.$.+.+....... . . .| [ ) | [ ) ) ( ( / / ! Q Q E L L L P G G A C C C V N m m b b c c c k k k d d p p y y ).", +").). O.1.4.4.4.2.8.2.8.8.8.8.8.8.8.8.9.9.9.9.9.9.T O * : Y O.e.9.9.9.9.9.9.9.9.8.8.8.9.8.8.8.4.2.8.2.8.2.2.4.1.:.2.:.:.;.,.-.-.-.-.&.&.&.$.+.+......... .| | | ) | | ) ` ) ( ( ! ! ! Q E L L L P G G G A A C V V N m b m b c c k k k d d d p p p q ).", +").). { 1.1.1.4.2.8.2.8.2.2.4.8.8.8.8.8.8.8.8.8.9.9.9.9.e.q.q.q.9.9.9.8.8.8.8.8.8.8.8.8.8.8.2.4.4.8.2.2.2.1.1.1.2.:.:.;.-.;.-.-.-.&.&.$.$.$.+...+... ... .| ) [ | ) ) ) ) ( ( ! ! ! ! Q E E P P G G D D C C C V N m m m b c c c k k d d d p p y 9 9 ).", +").). { ,.,.1.1.2.2.2.2.2.8.2.8.2.8.8.2.9.8.8.8.8.8.8.8.9.9.9.6.9.6.6.9.8.8.8.8.2.8.8.2.4.4.8.2.2.2.2.2.2.,.,.,.,.;.;.;.;.;.;.&.&.&.$.$.$.$...........| | | ` | ) ) ) ) ( ^ ^ ! Q Q Q Q L E L L K A A V V V V V N m b b v c c c j j d d d i p w $ % ).", +").). T ,.,.,.1.1.2.2.2.4.4.4.8.2.8.2.8.2.8.8.8.8.2.8.8.7.7.6.9.7.7.6.6.8.8.4.4.8.2.2.8.4.4.2.2.2.2.4.1.,.,.,.,.;.;.;.;.-.;.&.&.&.$.$.+.+...........| | ` | ` ` ` ` ( ( ( ( ^ ! ! Q Q L L L L L K A A D V V V V m m m b v c z j j j d d p p y = ).", +").). Y ,.;.,.,.,.1.1.2.1.1.4.2.4.4.2.8.8.2.2.8.2.2.8.2.7.7.3.3.3.7.3.6.8.2.8.2.4.4.4.2.1.1.4.1.1.1.,.,.,.,.;.;.;.;.&.;.&.&.&.&.&.$.+.+......... .| | | | ` ` ` ) ( ( ( ^ ^ ! ! Q Q Q L L L G G K A V D V V V N N b b b c c j z j j d d p i - ).", +").). : -.,.;.,.,.,.,.,.1.1.1.1.1.1.4.4.2.8.2.2.8.4.4.4.3.3.3.7.3.3.7.3.2.8.2.2.4.1.1.1.1.1.1.,.,.,.,.,.;.,.;.;.;.;.;.&.-.&.&.$.$.$.+. .......| | | | ` ` | ` ( ` ( ( ( ^ Q Q Q Q U U L L L G G A A A V V V N b b b b c c c c j j d d p p : ).", +").). = -.;.;.,.,.,.,.,.,.,.,.,.1.1.4.1.2.2.2.2.2.8.2.2.4.4.4.4.7.3.6.3.2.2.2.2.2.1.1.1.,.,.,.,.,.;.,.-.;.;.-.;.;.&.&.&.&.&.$.$.$.+...+... . .| | | ` ` ` ` ` ` ( ( ^ ^ ! ! Q Q Q L U L P P D D D V V V V N m m b b c c z z j j d d d p - ).", +").).). % -.-.-.;.-.-.,.,.,.,.,.,.,.,.1.1.2.2.2.2.2.2.2.2.2.2.2.1.1.1.3.1.2.1.1.1.1.,.,.,.,.,.,.;.;.,.;.;.-.;.-.&.&.;.&.&.$.$.$.+......... . .| | | ` ` | ` _ _ ( ( ^ ^ ^ ! Q Q Q L U L L P G D D D V V V V N m m m b c c z j c j d d i = ).).", +").).). o $.&.-.-.-.-.;.;.,.-.,.,.,.,.,.,.,.,.2.:.2.,.:.2.1.1.1.1.,.1.1.,.,.,.,.,.,.,.,.,.,.-.,.,.;.-.-.-.;.&.-.&.&.&.$.$.$.+.+......... . .| | ` ` | ) ` _ _ ( ( ( ^ ^ Q Q Q U U U L K K G G D D V V V V N m m b b c c c z j j d d 0 & O o ).).", +").).). g -.&.-.-.-.-.-.;.;.-.,.-.,.;.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.;.,.,.-.,.,.;.;.-.-.-.-.-.-.&.&.&.&.$.$.$.$.$....... . . .| | | ` | ) | ) ` ( ( ^ ^ ^ ! Q Q Q U L L K K K G D D B V V V V m m m b b c c k j j d d d - O , ).).", +").).). 2 $.*.*.*.*.*.;.;.-.-.;.;.;.;.;.,.;.;.,.,.;.,.,.,.,.,.;.;.1.;.;.,.;.;.,.;.;.;.;.;.;.&.;.&.&.&.&.&.&.&.$.$.+.+.$........... .| | | [ [ | ) ) ) ) ) ) / / / ! ! E Q U U U K K K A A A C C V V N N N n N v c c c k c j d d p 0 $ + g , ).).", +").).). * $.$.$.$.*.*.*.-.&.-.-.-.-.;.;.;.;.;.;.;.;.;.;.,.;.T : # 2 ;.;.;.;.;.;.-.-.-.-.&.;.&.;.&.;.&.&.&.&.$.+.+.+.| ........| .| | | | ) ) [ [ ) ( ( ) ( ! / ! ! E ! U U K K K K K A A A C C V N N m v n v v c c j k j d d p p i g O # 5 e = ).).", +").).). + $.$.$.$.$.$.*.&.-.-.&.&.;.-.;.;.;.;.&.;.;.;.;.O.O $ -.-.-.-.-.-.-.-.-.&.&.;.&.&.&.&.&.$.$.$.+.$...+...........| | ` ` ` | | ) [ ) ) ) ( ( / ! ! ! Q ! E U L L L K A K A A V C V V N N b N v v v c j k j j d d p i y y < * 0 y e O ).).", +").).).). T $.$.$.$.$.$.&.&.&.&.&.-.&.&.&.&.&.;.&.;.;.;.-.$ T -.-.-.-.&.&.-.&.-.&.&.&.$.$.$.$.$.+.+........... ...| | | | | ` | ) | ) ) ) ) ( ( / ! ! ! Q Q E L U L L K A K A A A C V V N m b N N v c c c j k j d d d i i y y y y e 8 g ).).).", +").).).). > o.$.$.+.$.$.$.$.$.$.&.&.&.&.&.;.&.&.;.&.&.&.-.2 - -.&.-.&.&.&.&.&.$.$.$.$.$.$.+.+.+.| ............ .| | ) | ` | ` ) [ ) ) ) ( / ( ! ! ! ! Q Q Q L L L L K K K A A C V C V V N b b b v v c c k k j j d p p i y y y y y e e > ).).).", +").).).). & o.o.o.o.$.+.+.$.$.$.$.$.$.&.$.&.$.$.&.&.&.&.$.{ o O.&.&.&.$.$.$.$.$.$.+.$.+.+.............| ....| | | | | | | ) | ) ) ) ) ) / ( ! ! ! Q Q Q E L E L L K A J A A A C C V N N b N b b v c z > 5 j d d p d p y y y y e e e 8 & ).).).", +").).).).). W .o.o. .o...+.$.+.+.+.+.$.$.$.$.$.$.$.&.$.$.$.= 2 &.$.$.$.$.+.$.+.+.$.+.............| ....| | | | ) | | ` ) | ( ) ) ) / ( / ! ! ! Q Q Q L L L L L K K K A A C C C V V N m N b v c c , @ = j d d d i i i y y e y e e 5 ).).).", +").).).).). : . . .o. ...........$.+.+.$.$.+.$.$.$.+.$.$.$.4 % $.+.+.+.+.$................. . .....| | ` | ` ` | ) ) | ) ` ) ( ( / / ! / ! ! Q Q Q Q L E L L L K A A A A C C V V N m m v v c > + g d d i i i y y y e e e 8 > ).).).).", +").).).).). # | . . . . . .....+. ......... .$.+.$.+.$.+.+.+.@ 4 ....+...............| ...... .| | | | ` } } ` ) | ) ) ) ) ) / / / / ! ! ! Q Q Q L Q L K K K A K D V C C C V V N m m m 5 ; + * d p i y i i y y e e 8 8 $ ).).).).", +").).).).).). 4 .| | . . . . .........+. .+............... .: * ..............| ......| | | | | | ` ` } ` ` _ ) ) ) ) ( ( ( / / ! ! ! Q Q Q E L L L L K K A K D D A V C V V N m m 3 = $ 0 p i i y e e e e e 8 g ).).).).).", +").).).).).). - | | | | | | . . . . . .| .......... . ..... .W o 4 .. . . . . ...| | | | | ` ` ` ` ` } ` ` _ _ ) ) ) ) / / ( ! ! ! ! E W E E L L L L L L K A D A A V C N V N m m b % @ , i p i y y i y e e 8 8 8 - ).).).).).", +").).).).).). W | ) [ [ | | | | | | . . . . . . . .| ... . .; O : R . . .| | | | | ` | ` | ` | | ` ` ` _ _ _ _ ) ( ( ( / / ! ! ! ! E ! E L E E L L L G A D D D A C C V N N m m b m , $ < d d p i y y y e i e e 8 7 9 O ).).).).).", +").).).).).).). + 4 ) | | [ [ | | | | | | | | | | | | | | | | | W + : W | .| | | | | | | | ` | | ` ` _ ` ` _ _ _ ( _ ( ( ( ( ! / ! ! ! E ! E E L L L L L L G G G D D V V V V V N m m m b b 0 & < d d d p i y y y y e y e e 8 7 : ).).).).).).", +").).).).).).). % 2 ( [ ) | ) | ) | | ` | | | | [ | | ` | | .) | | | | ) | ) | | ) ` ` ` ` ` ` ` _ _ _ _ _ _ _ ^ ^ ( / ! ! ! ! Q Q E E E E E L L G P G G G D B 1 3 C V V N m m b m b c c * o - g k d d d p p y y y y e e e 8 8 8 q O ).).).).).).", +").).).).).).).). + ; 4 | | ) | ` ` ` ) | ) | [ | ) | ` | | [ | ) ) | | | ) | ) | ` ` ` _ _ _ _ _ ( _ ^ _ ^ ^ ^ ^ ! ! ! ! Q Q Q Q E E L L L L P G G G 3 : % * V V N m m m b b b c c 5 0 k k d d d p p i y y y y e e e 8 8 8 > ).).).).).).).", +").).).).).).).). $ : W ` ` ` | ` ` | | ) ` | ` | ) | ) [ | | ) ) | ) | ) ) _ _ _ _ _ _ _ ( ( ( ^ ^ ^ ^ ^ ! ! ! ! Q Q E E L E L L L P 5 1 ; & o + N N m m m b b c c c k k k k d d d p p i i y i y e e e 8 8 8 w + ).).).).).).).", +").).).).).).).).). o W ) ) [ ) [ [ ) ) | ) [ ) | [ ) | | ) | [ ) ) ) ) [ ) ) ) ( ( ) ( / / ^ ( ^ ^ ^ ! ^ Q Q Q Q Q Q L L U L K U K , f b N v n v c c c k k k k d d d d i i i y y y e e e e e 8 8 : ).).).).).).).", +").).).).).).).).). * ( ) ) [ ) ) ) ) [ ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ( ( ) ) ) ( / / / / / ^ ^ ^ Q ! ! Q Q Q G U L L U L L L K K A f > N v N v c c c k k k k d d d p i i y y y y y e e e 8 7 8 5 o ).).).).).).).).", +").).).).).).).).).). O 1 ( ( ( ( ) ) ) ) ) ) W $ % - ; 1 1 2 f f f W ( ( / / ( / / / ! / 5 f 1 1 > - - % % # : L Q L L K K K K K K V X # - < v b v n v v z z k k d d d d p p i y y y e y e e e 8 7 7 8 * ).).).).).).).).", +").).).).).).).).).). > : % F / / / / / / / ( ) ) g P / / / ( / / ! / ! ! - - L L L L K J K A A A A % X # = < 5 N N b N b v c c c c j k k d d d p p i i y y i y e e e 8 7 7 7 < ).).).).).).).).).", +").).).).).).).).).).). O G ! F ! / ! / ! / / ( ( ( ( 3 W / / ! ! ! ! ! ! ! ! ; % L L L K A A A D V A C < > 3 v V N b b N b b v v c c c z j z k d d d p p i y y y e e e e 8 8 7 7 8 q # ).).).).).).).).).).", +").).).).).).).).).).). & ! ! ! ! ! ! ! ! / ! / ! ! , W ! 2 # 3 ! ! Q Q ! E ; + L G A K K D A D A V C V V V N N b N N b b b v c c c j z j j d d d p p i y y i y e y e e 8 7 7 7 8 - ).).).).).).).).).).", +").).).).).).).).).).).). : ! Q Q Q ! ! ! ! ! ! ! ! 2 % @ g & @ G ! Q E E E ; % % - F G A A A A A C V V V V V N m N N b N v v c c c j j j j j d d d p p p y y y y e e e e 8 7 7 7 7 , ).).).).).).).).).).).", +").).).).).).).).).).).).). 3 E Q Q Q Q ! Q Q Q Q Q ! Q Q Q G f 2 1 1 : - - O = E Q L L E 2 : 1 1 f f 9 L J A G G D D A A A C V V V V V N N m m b b b v v c c z z j c j j d j d p p p y y y y e y e e 8 8 7 7 7 g O ).).).).).).).).).).).", +").).).).).).).).).).).).). + F E L E L Q E E E E ! Q Q Q Q Q Q Q Q Q U Q U 1 1 L L L L L L L K K K K A K K D D A D D V V V V V V N N m m m b m b b b c c c c j j j j d d p p p i y y y e e i e e e 7 7 7 7 w $ ).).).).).).).).).).).).", +").).).).).).).).).).).).).). & F E E E L L E E L E L U L L Q L L L L L L U U * + G L L L L L K K K D K A A A V D A V V V V V V N N b m m m b b b c c c c k k j j j j j p d i p y y y y y y e e e 7 7 7 7 7 7 - ).).).).).).).).).).).).).", +").).).).).).).).).).).).).).). * G L L L E L E L L E L U U L Q L L Q U L L L J + * L L K K A A K D D A A A C D V V V V V V V N b N b b m b b b c c c c k k k d j d d p p p i y y y y y e e e e 8 7 7 8 8 8 > ).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).). - L L L L L L L L L L L L K L L L L L L K U K 1 < A K A K A A V D A A C C V V V V V N N N N b b N b b b b c c c k k k k d d d d d d p i i y y y y e y e e 8 7 7 7 8 8 , ).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).). : K K K K L G L P K K K K K K K L L K K K K K = o g D A A A D A A V V V C V V N N N m m m N b N v v v c c c c k k k d k d d d p p i i y i y y y e y e 8 8 7 7 7 7 7 < ).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).). , G G G G G G G K K K D K A K A K D A D A K N @ $ V V D V V V V A V V V V N N m m m b m v N v v v v z c j k k k k d d d d d p p y i y i y e e y e e 8 7 7 7 8 8 f o ).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).). : G D D D G D A A K A D D A K A K D D A A A 3 > D V V V V V V V V N N N m N m m b m b v v v v c c c j j c j j d d d d p p i y y y i e e e e e 8 8 7 7 7 7 7 < o ).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).). - V D V D D A A A A V D A V D V D V A C A C : + 3 V V V V V V V V N N N b m m b m b b b c v c c z c j j j j j d d d d p i p p y y y y i e y 8 e e 8 8 7 7 7 7 , ).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).). = B D V D A C A A A C A V C C C C C C C C V ; 5 N V N V V N N N b b N N v m b m b v c c c c z c z j j j j d d d d d i p p y y y y i y e e e 8 8 7 7 7 8 8 8 > ).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).). & N V V C V V C C V C V C C C V V V V V V V V N N N N N m N b N b b b N b b b c c c c c z j j j c j j d d d d i p p y p y y y y e e e e e 8 7 7 7 7 7 8 - ).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).). + 3 V V V V V V V V V V V V V N V N N N N N m b N N b m b b b N b v v c c c c c c k k j c j j j j d d d p p i i y y y y y e y e e e 8 8 8 7 7 7 7 9 % ).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).). > N N N N V N N N N N N N N m m m m m m m m b b b m b b b b c c c c k c c k k k k j j j j d d d p p p i i i y y y y e y e e e 8 8 7 7 7 7 7 < + ).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).). * 0 N m b N N b m m m m m m N m m b m b b N v b b b c c c c c c c k k k k k d k d d d d p j p p i y y y y i e i e y e e e 8 7 7 7 7 7 7 : ).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).). O , m b b b N b m m b m b b b b m b b v v v v c c c c c c j k k k k k k d d d d d d d p p p i i y y y e i e e e 8 e 8 8 7 7 7 7 7 f $ ).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).). % g b b b m b m b b b b b b c c c c c c c c c c k g k k k k k d k d d d d p d i p i i i i y y y i e y e e e 8 8 7 7 7 7 7 q - ).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).). X ; c v b b c c c b c c c c c c c c c k k k d = o f j k k d d d d d d p i i i i i y y y y i e e e e e e e 8 8 8 7 7 7 , + ).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).). O : 0 c c c c c c c c c c k k k k k k 0 & + 5 d d d p d d d p i i y y y y y y e y e e e e e 8 8 7 7 8 8 8 , $ ).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). O ; 0 c z j j c k k k k k k k k d @ # 9 d d p p i p i y i y y y y y e y y e e e 8 e 7 7 7 8 7 , $ ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). o - f j k k k k d d j k d d d : % 0 i p p y y i y y y y y y e y e e e e 8 8 7 7 7 9 > # ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). $ > 9 k d d k d d d d d d = % w y p y y y y y e e y e y e e e 8 8 8 7 w < * ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). & > g d d d d p d p i & * w y y y y y y e y e e e e 8 8 8 0 < - O ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). + = , 5 i p p i 6 % * w y e e e e e 8 e e 8 q < : % ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). % = : < f # = y e y g f < , - & @ ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). o ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).)." +}; diff --git a/beos/res/throbber.gif b/beos/res/throbber.gif new file mode 100644 index 000000000..f9d0c152d Binary files /dev/null and b/beos/res/throbber.gif differ -- cgit v1.2.3