summaryrefslogtreecommitdiff
path: root/desktop
diff options
context:
space:
mode:
Diffstat (limited to 'desktop')
-rw-r--r--desktop/browser.c113
-rw-r--r--desktop/browser_history.c257
-rw-r--r--desktop/browser_history.h26
-rw-r--r--desktop/browser_private.h17
-rw-r--r--desktop/cookie_manager.c19
-rw-r--r--desktop/font_haru.c24
-rw-r--r--desktop/frames.c6
-rw-r--r--desktop/global_history.c22
-rw-r--r--desktop/hotlist.c35
-rw-r--r--desktop/knockout.c8
-rw-r--r--desktop/local_history.c4
-rw-r--r--desktop/mouse.c2
-rw-r--r--desktop/netsurf.c30
-rw-r--r--desktop/options.h5
-rw-r--r--desktop/print.c43
-rw-r--r--desktop/save_complete.c26
-rw-r--r--desktop/save_pdf.c43
-rw-r--r--desktop/save_text.c8
-rw-r--r--desktop/searchweb.c20
-rw-r--r--desktop/selection.c67
-rw-r--r--desktop/selection.h7
-rw-r--r--desktop/sslcert_viewer.c8
-rw-r--r--desktop/textarea.c88
-rw-r--r--desktop/textarea.h18
-rw-r--r--desktop/treeview.c1274
-rw-r--r--desktop/treeview.h14
-rw-r--r--desktop/version.c4
27 files changed, 1645 insertions, 543 deletions
diff --git a/desktop/browser.c b/desktop/browser.c
index e7ff158f9..19cfebb99 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -171,7 +171,7 @@ browser_window_redraw(struct browser_window *bw,
nserror res;
if (bw == NULL) {
- LOG("NULL browser window");
+ NSLOG(netsurf, INFO, "NULL browser window");
return false;
}
@@ -336,7 +336,7 @@ browser_window_redraw(struct browser_window *bw,
bool browser_window_redraw_ready(struct browser_window *bw)
{
if (bw == NULL) {
- LOG("NULL browser window");
+ NSLOG(netsurf, INFO, "NULL browser window");
return false;
} else if (bw->current_content != NULL) {
/* Can't render locked contents */
@@ -415,7 +415,8 @@ void browser_window_set_position(struct browser_window *bw, int x, int y)
bw->x = x;
bw->y = y;
} else {
- LOG("Asked to set position of front end window.");
+ NSLOG(netsurf, INFO,
+ "Asked to set position of front end window.");
assert(0);
}
}
@@ -811,7 +812,7 @@ nserror browser_window_debug(struct browser_window *bw, enum content_debug op)
static bool slow_script(void *ctx)
{
static int count = 0;
- LOG("Continuing execution %d", count);
+ NSLOG(netsurf, INFO, "Continuing execution %d", count);
count++;
if (count > 1) {
count = 0;
@@ -886,7 +887,7 @@ nserror browser_window_create(enum browser_window_create_flags flags,
}
if (url != NULL) {
- enum browser_window_nav_flags nav_flags = BW_NAVIGATE_NONE;
+ enum browser_window_nav_flags nav_flags = BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE;
if (flags & BW_CREATE_UNVERIFIABLE)
nav_flags |= BW_NAVIGATE_UNVERIFIABLE;
if (flags & BW_CREATE_HISTORY)
@@ -982,11 +983,12 @@ browser_window_download(struct browser_window *bw,
/* no internal handler for this type, call out to frontend */
error = guit->misc->launch_url(url);
} else if (error != NSERROR_OK) {
- LOG("Failed to fetch download: %d", error);
+ NSLOG(netsurf, INFO, "Failed to fetch download: %d", error);
} else {
error = download_context_create(l, root->window);
if (error != NSERROR_OK) {
- LOG("Failed creating download context: %d", error);
+ NSLOG(netsurf, INFO,
+ "Failed creating download context: %d", error);
llcache_handle_abort(l);
llcache_handle_release(l);
}
@@ -1094,6 +1096,7 @@ browser_window_favicon_callback(hlcache_handle *c,
break;
case CONTENT_MSG_ERROR:
+ case CONTENT_MSG_ERRORCODE:
/* clean up after ourselves */
if (c == bw->favicon.loading) {
@@ -1113,7 +1116,8 @@ browser_window_favicon_callback(hlcache_handle *c,
error = nsurl_create("resource:favicon.ico", &nsurl);
if (error != NSERROR_OK) {
- LOG("Unable to create default location url");
+ NSLOG(netsurf, INFO,
+ "Unable to create default location url");
} else {
hlcache_handle_retrieve(nsurl,
HLCACHE_RETRIEVE_SNIFF_TYPE,
@@ -1203,7 +1207,8 @@ browser_window_update_favicon(hlcache_handle *c,
error = nsurl_create("resource:favicon.ico", &nsurl);
}
if (error != NSERROR_OK) {
- LOG("Unable to create default location url");
+ NSLOG(netsurf, INFO,
+ "Unable to create default location url");
return;
}
} else {
@@ -1211,9 +1216,11 @@ browser_window_update_favicon(hlcache_handle *c,
}
if (link == NULL) {
- LOG("fetching general favicon from '%s'", nsurl_access(nsurl));
+ NSLOG(netsurf, INFO, "fetching general favicon from '%s'",
+ nsurl_access(nsurl));
} else {
- LOG("fetching favicon rel:%s '%s'", lwc_string_data(link->rel), nsurl_access(nsurl));
+ NSLOG(netsurf, INFO, "fetching favicon rel:%s '%s'",
+ lwc_string_data(link->rel), nsurl_access(nsurl));
}
hlcache_handle_retrieve(nsurl, HLCACHE_RETRIEVE_SNIFF_TYPE,
@@ -1348,6 +1355,7 @@ browser_window_callback(hlcache_handle *c,
{
struct browser_window *bw = pw;
nserror res = NSERROR_OK;
+ float sx, sy;
switch (event->type) {
case CONTENT_MSG_DOWNLOAD:
@@ -1397,23 +1405,6 @@ browser_window_callback(hlcache_handle *c,
bw->current_content = c;
bw->loading_content = NULL;
- /* Format the new content to the correct dimensions */
- browser_window_get_dimensions(bw, &width, &height, true);
- content_reformat(c, false, width, height);
-
- browser_window_remove_caret(bw, false);
-
- if (bw->window != NULL) {
- guit->window->new_content(bw->window);
-
- browser_window_refresh_url_bar(bw);
- }
-
- /* new content; set scroll_to_top */
- browser_window_update(bw, true);
- content_open(c, bw, 0, 0);
- browser_window_set_status(bw, content_get_status_message(c));
-
/* history */
if (bw->history_add && bw->history) {
nsurl *url = hlcache_handle_get_url(c);
@@ -1450,6 +1441,23 @@ browser_window_callback(hlcache_handle *c,
browser_window_history_add(bw, c, bw->frag_id);
}
+ /* Format the new content to the correct dimensions */
+ browser_window_get_dimensions(bw, &width, &height, true);
+ content_reformat(c, false, width, height);
+
+ browser_window_remove_caret(bw, false);
+
+ if (bw->window != NULL) {
+ guit->window->new_content(bw->window);
+
+ browser_window_refresh_url_bar(bw);
+ }
+
+ /* new content; set scroll_to_top */
+ browser_window_update(bw, true);
+ content_open(c, bw, 0, 0);
+ browser_window_set_status(bw, content_get_status_message(c));
+
/* frames */
if ((content_get_type(c) == CONTENT_HTML) &&
(html_get_frameset(c) != NULL)) {
@@ -1478,6 +1486,19 @@ browser_window_callback(hlcache_handle *c,
browser_window_stop_throbber(bw);
browser_window_update_favicon(c, bw, NULL);
+ if (browser_window_history_get_scroll(bw, &sx, &sy) == NSERROR_OK) {
+ int scrollx = (int)((float)content_get_width(bw->current_content) * sx);
+ int scrolly = (int)((float)content_get_height(bw->current_content) * sy);
+ struct rect rect;
+ rect.x0 = rect.x1 = scrollx;
+ rect.y0 = rect.y1 = scrolly;
+ if (browser_window_set_scroll(bw, &rect) != NSERROR_OK) {
+ NSLOG(netsurf, WARNING,
+ "Unable to set browser scroll offsets to %d by %d",
+ scrollx, scrolly);
+ }
+ }
+
browser_window_history_update(bw, c);
hotlist_update_url(hlcache_handle_get_url(c));
@@ -1810,7 +1831,7 @@ static void browser_window_destroy_internal(struct browser_window *bw)
{
assert(bw);
- LOG("Destroying window");
+ NSLOG(netsurf, INFO, "Destroying window");
if (bw->children != NULL || bw->iframes != NULL) {
browser_window_destroy_children(bw);
@@ -1830,7 +1851,8 @@ static void browser_window_destroy_internal(struct browser_window *bw)
/* The ugly cast here is so the reformat function can be
* passed a gui window pointer in its API rather than void*
*/
- LOG("Clearing reformat schedule for browser window %p", bw);
+ NSLOG(netsurf, INFO,
+ "Clearing reformat schedule for browser window %p", bw);
guit->misc->schedule(-1, scheduled_reformat, bw);
/* If this brower window is not the root window, and has focus, unset
@@ -1910,7 +1932,8 @@ static void browser_window_destroy_internal(struct browser_window *bw)
free(bw->name);
free(bw->status.text);
bw->status.text = NULL;
- LOG("Status text cache match:miss %d:%d", bw->status.match, bw->status.miss);
+ NSLOG(netsurf, INFO, "Status text cache match:miss %d:%d",
+ bw->status.match, bw->status.miss);
}
/**
@@ -2003,14 +2026,28 @@ browser_window_navigate(struct browser_window *bw,
assert(bw);
assert(url);
- LOG("bw %p, url %s", bw, nsurl_access(url));
+ NSLOG(netsurf, INFO, "bw %p, url %s", bw, nsurl_access(url));
+
+ /* If we're navigating and we have a history entry and a content
+ * then update the history entry before we navigate to save our
+ * current state. However since history navigation pre-moves
+ * the history state, we ensure that we only do this if we've not
+ * been suppressed. In the suppressed case, the history code
+ * updates the history itself before navigating.
+ */
+ if (bw->current_content != NULL &&
+ bw->history != NULL &&
+ bw->history->current != NULL &&
+ !(flags & BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE)) {
+ browser_window_history_update(bw, bw->current_content);
+ }
/* don't allow massively nested framesets */
for (cur = bw; cur->parent; cur = cur->parent) {
depth++;
}
if (depth > FRAME_DEPTH) {
- LOG("frame depth too high.");
+ NSLOG(netsurf, INFO, "frame depth too high.");
return NSERROR_FRAME_DEPTH;
}
@@ -2102,7 +2139,7 @@ browser_window_navigate(struct browser_window *bw,
browser_window_remove_caret(bw, false);
browser_window_destroy_children(bw);
- LOG("Loading '%s'", nsurl_access(url));
+ NSLOG(netsurf, INFO, "Loading '%s'", nsurl_access(url));
browser_window_set_status(bw, messages_get("Loading"));
bw->history_add = (flags & BW_NAVIGATE_HISTORY);
@@ -2318,7 +2355,8 @@ void browser_window_set_dimensions(struct browser_window *bw,
bw->width = width;
bw->height = height;
} else {
- LOG("Asked to set dimensions of front end window.");
+ NSLOG(netsurf, INFO,
+ "Asked to set dimensions of front end window.");
assert(0);
}
}
@@ -2348,6 +2386,11 @@ static bool frag_scroll(struct browser_window *bw)
rect.x1 = rect.x0;
rect.y1 = rect.y0;
if (browser_window_set_scroll(bw, &rect) == NSERROR_OK) {
+ if (bw->current_content != NULL &&
+ bw->history != NULL &&
+ bw->history->current != NULL) {
+ browser_window_history_update(bw, bw->current_content);
+ }
return true;
}
return false;
diff --git a/desktop/browser_history.c b/desktop/browser_history.c
index dbbc67daf..d9db0eb18 100644
--- a/desktop/browser_history.c
+++ b/desktop/browser_history.c
@@ -32,6 +32,7 @@
#include "utils/utils.h"
#include "netsurf/layout.h"
#include "netsurf/content.h"
+#include "netsurf/window.h"
#include "content/hlcache.h"
#include "content/urldb.h"
#include "netsurf/bitmap.h"
@@ -50,7 +51,7 @@
* Clone a history entry
*
* \param history opaque history structure, as returned by history_create()
- * \param entry entry to clone
+ * \param entry entry to clone
* \return A cloned history entry or NULL on error
*/
static struct history_entry *
@@ -62,47 +63,85 @@ browser_window_history__clone_entry(struct history *history,
struct history_entry *prev = NULL;
struct history_entry *new_entry;
+ assert(entry);
assert(entry->page.url);
assert(entry->page.title);
/* clone the entry */
- new_entry = malloc(sizeof *entry);
- if (!new_entry)
+ new_entry = calloc(1, sizeof *entry);
+ if (!new_entry) {
return NULL;
+ }
- memcpy(new_entry, entry, sizeof *entry);
- new_entry->page.url = nsurl_ref(entry->page.url);
- if (entry->page.frag_id)
- new_entry->page.frag_id = lwc_string_ref(entry->page.frag_id);
-
+ /* copy page information */
new_entry->page.title = strdup(entry->page.title);
- if (!new_entry->page.url || !new_entry->page.title ||
- ((entry->page.frag_id) && (!new_entry->page.frag_id))) {
- nsurl_unref(new_entry->page.url);
- if (new_entry->page.frag_id)
- lwc_string_unref(new_entry->page.frag_id);
+ if (new_entry->page.title == NULL) {
+ free(new_entry);
+ return NULL;
+ }
+
+ new_entry->page.url = nsurl_ref(entry->page.url);
+ if (new_entry->page.url == NULL) {
free(new_entry->page.title);
free(new_entry);
return NULL;
}
- /* update references */
- if (history->current == entry)
- history->current = new_entry;
+ if (entry->page.frag_id == NULL) {
+ new_entry->page.frag_id = NULL;
+ } else {
+ new_entry->page.frag_id = lwc_string_ref(entry->page.frag_id);
+ if (new_entry->page.frag_id == NULL) {
+ nsurl_unref(new_entry->page.url);
+ free(new_entry);
+ return NULL;
+ }
+ }
+
+ if (entry->page.bitmap == NULL) {
+ new_entry->page.bitmap = NULL;
+ } else {
+ /* create a new bitmap and copy original into it */
+ unsigned char *bmsrc_data;
+ unsigned char *bmdst_data;
+ size_t bmsize;
+
+ new_entry->page.bitmap = guit->bitmap->create(WIDTH, HEIGHT,
+ BITMAP_NEW | BITMAP_OPAQUE);
+
+ if (new_entry->page.bitmap != NULL) {
+ bmsrc_data = guit->bitmap->get_buffer(entry->page.bitmap);
+ bmdst_data = guit->bitmap->get_buffer(new_entry->page.bitmap);
+ bmsize = guit->bitmap->get_rowstride(new_entry->page.bitmap) *
+ guit->bitmap->get_height(new_entry->page.bitmap);
+ memcpy(bmdst_data, bmsrc_data, bmsize);
+ }
+ }
+
+ /* copy tree values */
+ new_entry->back = entry->back;
+ new_entry->next = entry->next;
+ new_entry->forward = entry->forward;
+ new_entry->forward_pref = entry->forward_pref;
+ new_entry->forward_last = entry->forward_last;
/* recurse for all children */
- for (child = new_entry->forward; child; child = child->next) {
+ for (child = new_entry->forward; child != NULL; child = child->next) {
new_child = browser_window_history__clone_entry(history, child);
- if (new_child) {
- new_child->back = new_entry;
- } else {
+ if (new_child == NULL) {
nsurl_unref(new_entry->page.url);
- if (new_entry->page.frag_id)
+ if (new_entry->page.frag_id) {
lwc_string_unref(new_entry->page.frag_id);
+ }
free(new_entry->page.title);
+ if (entry->page.bitmap != NULL) {
+ guit->bitmap->destroy(entry->page.bitmap);
+ }
free(new_entry);
return NULL;
}
+
+ new_child->back = new_entry;
if (prev)
prev->next = new_child;
if (new_entry->forward == child)
@@ -113,6 +152,12 @@ browser_window_history__clone_entry(struct history *history,
new_entry->forward_last = new_child;
prev = new_child;
}
+
+ /* update references */
+ if (history->current == entry) {
+ history->current = new_entry;
+ }
+
return new_entry;
}
@@ -123,15 +168,20 @@ browser_window_history__clone_entry(struct history *history,
static void browser_window_history__free_entry(struct history_entry *entry)
{
- if (!entry)
- return;
- browser_window_history__free_entry(entry->forward);
- browser_window_history__free_entry(entry->next);
- nsurl_unref(entry->page.url);
- if (entry->page.frag_id)
- lwc_string_unref(entry->page.frag_id);
- free(entry->page.title);
- free(entry);
+ if (entry != NULL) {
+ browser_window_history__free_entry(entry->forward);
+ browser_window_history__free_entry(entry->next);
+
+ nsurl_unref(entry->page.url);
+ if (entry->page.frag_id) {
+ lwc_string_unref(entry->page.frag_id);
+ }
+ free(entry->page.title);
+ if (entry->page.bitmap != NULL) {
+ guit->bitmap->destroy(entry->page.bitmap);
+ }
+ free(entry);
+ }
}
@@ -286,7 +336,7 @@ nserror browser_window_history_clone(const struct browser_window *existing,
new_history->start = browser_window_history__clone_entry(new_history,
new_history->start);
if (!new_history->start) {
- LOG("Insufficient memory to clone history");
+ NSLOG(netsurf, INFO, "Insufficient memory to clone history");
browser_window_history_destroy(clone);
clone->history = NULL;
return NSERROR_NOMEM;
@@ -297,14 +347,14 @@ nserror browser_window_history_clone(const struct browser_window *existing,
/* exported interface documented in desktop/browser_history.h */
-nserror browser_window_history_add(struct browser_window *bw,
- struct hlcache_handle *content, lwc_string *frag_id)
+nserror
+browser_window_history_add(struct browser_window *bw,
+ struct hlcache_handle *content,
+ lwc_string *frag_id)
{
struct history *history;
struct history_entry *entry;
- nsurl *nsurl = hlcache_handle_get_url(content);
char *title;
- struct bitmap *bitmap;
nserror ret;
assert(bw);
@@ -313,32 +363,50 @@ nserror browser_window_history_add(struct browser_window *bw,
history = bw->history;
- /* allocate space */
entry = malloc(sizeof *entry);
if (entry == NULL) {
return NSERROR_NOMEM;
}
+ /* page information */
title = strdup(content_get_title(content));
if (title == NULL) {
free(entry);
return NSERROR_NOMEM;
}
- entry->page.url = nsurl_ref(nsurl);
- entry->page.frag_id = frag_id ? lwc_string_ref(frag_id) : 0;
-
+ entry->page.url = nsurl_ref(hlcache_handle_get_url(content));
+ entry->page.frag_id = frag_id ? lwc_string_ref(frag_id) : NULL;
entry->page.title = title;
+ entry->page.scroll_x = 0.0f;
+ entry->page.scroll_y = 0.0f;
+
+ /* create thumbnail for localhistory view */
+ NSLOG(netsurf, DEBUG,
+ "Creating thumbnail for %s", nsurl_access(entry->page.url));
+
+ entry->page.bitmap = guit->bitmap->create(WIDTH, HEIGHT,
+ BITMAP_NEW | BITMAP_CLEAR_MEMORY | BITMAP_OPAQUE);
+ if (entry->page.bitmap != NULL) {
+ ret = guit->bitmap->render(entry->page.bitmap, content);
+ if (ret != NSERROR_OK) {
+ /* Thumbnail render failed */
+ NSLOG(netsurf, WARNING, "Thumbnail render failed");
+ }
+ }
+
+ /* insert into tree */
entry->back = history->current;
- entry->next = 0;
- entry->forward = entry->forward_pref = entry->forward_last = 0;
+ entry->next = NULL;
+ entry->forward = entry->forward_pref = entry->forward_last = NULL;
entry->children = 0;
- entry->bitmap = 0;
+
if (history->current) {
- if (history->current->forward_last)
+ if (history->current->forward_last) {
history->current->forward_last->next = entry;
- else
+ } else {
history->current->forward = entry;
+ }
history->current->forward_pref = entry;
history->current->forward_last = entry;
history->current->children++;
@@ -347,33 +415,6 @@ nserror browser_window_history_add(struct browser_window *bw,
}
history->current = entry;
- /* if we have a thumbnail, don't update until the page has finished
- * loading */
- bitmap = urldb_get_thumbnail(nsurl);
- if (bitmap == NULL) {
- LOG("Creating thumbnail for %s", nsurl_access(nsurl));
- bitmap = guit->bitmap->create(WIDTH, HEIGHT,
- BITMAP_NEW | BITMAP_CLEAR_MEMORY |
- BITMAP_OPAQUE);
- if (bitmap != NULL) {
- ret = guit->bitmap->render(bitmap, content);
- if (ret == NSERROR_OK) {
- /* Successful thumbnail so register it
- * with the url.
- */
- urldb_set_thumbnail(nsurl, bitmap);
- } else {
- /* Thumbnailing failed. Ignore it
- * silently but clean up bitmap.
- */
- LOG("Thumbnail renderfailed");
- guit->bitmap->destroy(bitmap);
- bitmap = NULL;
- }
- }
- }
- entry->bitmap = bitmap;
-
browser_window_history__layout(history);
return NSERROR_OK;
@@ -386,12 +427,15 @@ nserror browser_window_history_update(struct browser_window *bw,
{
struct history *history;
char *title;
+ int sx, sy;
assert(bw != NULL);
history = bw->history;
- if (!history || !history->current || !history->current->bitmap) {
+ if (!history ||
+ !history->current ||
+ !history->current->page.bitmap) {
return NSERROR_INVALID;
}
@@ -402,16 +446,50 @@ nserror browser_window_history_update(struct browser_window *bw,
if (title == NULL) {
return NSERROR_NOMEM;
}
-
+ NSLOG(netsurf, INFO, "Updating history entry for %s", title);
free(history->current->page.title);
history->current->page.title = title;
- guit->bitmap->render(history->current->bitmap, content);
+ if (history->current->page.bitmap != NULL) {
+ guit->bitmap->render(history->current->page.bitmap, content);
+ }
+ if (bw->window != NULL &&
+ guit->window->get_scroll(bw->window, &sx, &sy)) {
+ /* Successfully got scroll offsets, update the entry */
+ history->current->page.scroll_x = \
+ (float)sx / (float)content_get_width(content);
+ history->current->page.scroll_y = \
+ (float)sy / (float)content_get_height(content);
+ NSLOG(netsurf, INFO, "Updated scroll offsets to %g by %g",
+ history->current->page.scroll_x,
+ history->current->page.scroll_y);
+ }
return NSERROR_OK;
}
+/* exported interface documented in desktop/browser_private.h */
+nserror
+browser_window_history_get_scroll(struct browser_window *bw,
+ float *sx, float *sy)
+{
+ struct history *history;
+
+ assert(bw != NULL);
+ history = bw->history;
+
+ if (!history ||
+ !history->current ||
+ !history->current->page.bitmap) {
+ return NSERROR_INVALID;
+ }
+
+ *sx = history->current->page.scroll_x;
+ *sy = history->current->page.scroll_y;
+
+ return NSERROR_OK;
+}
/* exported interface documented in desktop/browser_history.h */
void browser_window_history_destroy(struct browser_window *bw)
@@ -470,6 +548,27 @@ bool browser_window_history_forward_available(struct browser_window *bw)
bw->history->current->forward_pref);
}
+/* exported interface documented in desktop/browser_history.h */
+nserror
+browser_window_history_get_thumbnail(struct browser_window *bw,
+ struct bitmap **bitmap_out)
+{
+ struct bitmap *bitmap;
+
+ if (!bw || !bw->history || !bw->history->current) {
+ return NSERROR_INVALID;
+ }
+
+ if (bw->history->current->page.bitmap == NULL) {
+ bitmap = content_get_bitmap(bw->current_content);
+ } else {
+ bitmap = bw->history->current->page.bitmap;
+ }
+
+ *bitmap_out = bitmap;
+
+ return NSERROR_OK;
+}
/* exported interface documented in desktop/browser_history.h */
nserror browser_window_history_go(struct browser_window *bw,
@@ -502,9 +601,13 @@ nserror browser_window_history_go(struct browser_window *bw,
url, NULL, bw, NULL);
history->current = current;
} else {
+ if (bw->current_content != NULL) {
+ browser_window_history_update(bw, bw->current_content);
+ }
history->current = entry;
error = browser_window_navigate(bw, url, NULL,
- BW_NAVIGATE_NONE, NULL, NULL, NULL);
+ BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE,
+ NULL, NULL, NULL);
}
nsurl_unref(url);
@@ -514,7 +617,7 @@ nserror browser_window_history_go(struct browser_window *bw,
/* exported interface documented in desktop/browser_history.h */
-void browser_window_history_enumerate_forward(const struct browser_window *bw,
+void browser_window_history_enumerate_forward(const struct browser_window *bw,
browser_window_history_enumerate_cb cb, void *user_data)
{
struct history_entry *e;
@@ -532,7 +635,7 @@ void browser_window_history_enumerate_forward(const struct browser_window *bw,
/* exported interface documented in desktop/browser_history.h */
-void browser_window_history_enumerate_back(const struct browser_window *bw,
+void browser_window_history_enumerate_back(const struct browser_window *bw,
browser_window_history_enumerate_cb cb, void *user_data)
{
struct history_entry *e;
diff --git a/desktop/browser_history.h b/desktop/browser_history.h
index 9140e2ce0..9b6f1fd42 100644
--- a/desktop/browser_history.h
+++ b/desktop/browser_history.h
@@ -37,6 +37,7 @@
struct browser_window;
struct history_entry;
+struct bitmap;
/**
* Go back in the history.
@@ -75,6 +76,14 @@ bool browser_window_history_back_available(struct browser_window *bw);
*/
bool browser_window_history_forward_available(struct browser_window *bw);
+/**
+ * Get the thumbnail bitmap for the current history entry
+ *
+ * \param bw The browser window
+ * \param bitmap The bitmat for the current history entry.
+ * \return NSERROR_OK or error code on faliure.
+ */
+nserror browser_window_history_get_thumbnail(struct browser_window *bw, struct bitmap **bitmap_out);
/**
* Callback function type for history enumeration
@@ -136,21 +145,19 @@ struct nsurl *browser_window_history_entry_get_url(const struct history_entry *e
/**
* Returns the URL to a history entry
*
- * \param entry the history entry to retrieve the fragment id from
- * \return the fragment id
+ * \param entry the history entry to retrieve the fragment id from
+ * \return the fragment id
*/
-const char *browser_window_history_entry_get_fragment_id(
- const struct history_entry *entry);
+const char *browser_window_history_entry_get_fragment_id(const struct history_entry *entry);
/**
* Returns the title of a history entry
*
- * \param entry the history entry to retrieve the title from
- * \return the title
+ * \param entry The history entry to retrieve the title from
+ * \return the title
*/
-const char *browser_window_history_entry_get_title(
- const struct history_entry *entry);
+const char *browser_window_history_entry_get_title(const struct history_entry *entry);
/**
@@ -161,7 +168,6 @@ const char *browser_window_history_entry_get_title(
* \param new_window open entry in new window
* \return NSERROR_OK or error code on faliure.
*/
-nserror browser_window_history_go(struct browser_window *bw,
- struct history_entry *entry, bool new_window);
+nserror browser_window_history_go(struct browser_window *bw, struct history_entry *entry, bool new_window);
#endif
diff --git a/desktop/browser_private.h b/desktop/browser_private.h
index 8bbc573eb..192d22bf0 100644
--- a/desktop/browser_private.h
+++ b/desktop/browser_private.h
@@ -45,6 +45,9 @@ struct history_page {
struct nsurl *url; /**< Page URL, never NULL. */
lwc_string *frag_id; /** Fragment identifier, or NULL. */
char *title; /**< Page title, never NULL. */
+ struct bitmap *bitmap; /**< Thumbnail bitmap, or NULL. */
+ float scroll_x; /**< Scroll X offset when visited */
+ float scroll_y; /**< Scroll Y offset when visited */
};
/**
@@ -61,7 +64,6 @@ struct history_entry {
unsigned int children; /**< Number of children. */
int x; /**< Position of node. */
int y; /**< Position of node. */
- struct bitmap *bitmap; /**< Thumbnail bitmap, or 0. */
};
/**
@@ -325,7 +327,7 @@ nserror browser_window_history_add(struct browser_window *bw,
struct hlcache_handle *content, lwc_string *frag_id);
/**
- * Update the thumbnail for the current entry.
+ * Update the thumbnail and scroll offsets for the current entry.
*
* \param bw The browser window to update the history within.
* \param content content for current entry
@@ -335,6 +337,17 @@ nserror browser_window_history_update(struct browser_window *bw,
struct hlcache_handle *content);
/**
+ * Retrieve the stored scroll offsets for the current history entry
+ *
+ * \param bw The browser window to retrieve scroll offsets for.
+ * \param sx Pointer to a float for the X scroll offset
+ * \param sy Pointer to a float for the Y scroll offset
+ * \return NSERROR_OK or error code on failure.
+ */
+nserror browser_window_history_get_scroll(struct browser_window *bw,
+ float *sx, float *sy);
+
+/**
* Free a history structure.
*
* \param bw The browser window to destroy the history within.
diff --git a/desktop/cookie_manager.c b/desktop/cookie_manager.c
index 5429f6864..a2aab8e9f 100644
--- a/desktop/cookie_manager.c
+++ b/desktop/cookie_manager.c
@@ -576,7 +576,9 @@ static nserror cookie_manager_init_entry_fields(void)
goto error;
}
- cm_ctx.fields[COOKIE_M_DOMAIN].flags = TREE_FLAG_SHOW_NAME;
+ cm_ctx.fields[COOKIE_M_DOMAIN].flags =
+ TREE_FLAG_SHOW_NAME |
+ TREE_FLAG_SEARCHABLE;
label = "TreeviewLabelDomain";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
@@ -718,7 +720,8 @@ static void cookie_manager_delete_entry(struct cookie_manager_entry *e)
urldb_delete_cookie(domain, path, name);
} else {
- LOG("Delete cookie fail: ""need domain, path, and name.");
+ NSLOG(netsurf, INFO,
+ "Delete cookie fail: ""need domain, path, and name.");
}
}
@@ -788,7 +791,7 @@ nserror cookie_manager_init(struct core_window_callback_table *cw_t,
return err;
}
- LOG("Generating cookie manager data");
+ NSLOG(netsurf, INFO, "Generating cookie manager data");
/* Init. cookie manager treeview entry fields */
err = cookie_manager_init_entry_fields();
@@ -808,7 +811,9 @@ nserror cookie_manager_init(struct core_window_callback_table *cw_t,
err = treeview_create(&cm_ctx.tree, &cm_tree_cb_t,
COOKIE_M_N_FIELDS, cm_ctx.fields,
cw_t, core_window_handle,
- TREEVIEW_NO_MOVES | TREEVIEW_DEL_EMPTY_DIRS);
+ TREEVIEW_NO_MOVES |
+ TREEVIEW_DEL_EMPTY_DIRS |
+ TREEVIEW_SEARCHABLE);
if (err != NSERROR_OK) {
cm_ctx.tree = NULL;
return err;
@@ -825,7 +830,7 @@ nserror cookie_manager_init(struct core_window_callback_table *cw_t,
/* Inform client of window height */
treeview_get_height(cm_ctx.tree);
- LOG("Generated cookie manager data");
+ NSLOG(netsurf, INFO, "Generated cookie manager data");
return NSERROR_OK;
}
@@ -837,7 +842,7 @@ nserror cookie_manager_fini(void)
int i;
nserror err;
- LOG("Finalising cookie manager");
+ NSLOG(netsurf, INFO, "Finalising cookie manager");
cm_ctx.built = false;
@@ -860,7 +865,7 @@ nserror cookie_manager_fini(void)
return err;
}
- LOG("Finalised cookie manager");
+ NSLOG(netsurf, INFO, "Finalised cookie manager");
return err;
}
diff --git a/desktop/font_haru.c b/desktop/font_haru.c
index caa751bcb..f92d89197 100644
--- a/desktop/font_haru.c
+++ b/desktop/font_haru.c
@@ -74,7 +74,10 @@ const struct font_functions haru_nsfont = {
static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no,
void *user_data)
{
- LOG("ERROR: in font_haru \n\terror_no=%x\n\tdetail_no=%d\n", (HPDF_UINT)error_no, (HPDF_UINT)detail_no);
+ NSLOG(netsurf, INFO,
+ "ERROR: in font_haru \n\terror_no=%x\n\tdetail_no=%d\n",
+ (HPDF_UINT)error_no,
+ (HPDF_UINT)detail_no);
#ifdef FONT_HARU_DEBUG
exit(1);
#endif
@@ -143,7 +146,9 @@ bool haru_nsfont_width(const plot_font_style_t *fstyle,
*width = width_real;
#ifdef FONT_HARU_DEBUG
- LOG("Measuring string: %s ; Calculated width: %f %i", string_nt, width_real, *width);
+ NSLOG(netsurf, INFO,
+ "Measuring string: %s ; Calculated width: %f %i", string_nt,
+ width_real, *width);
#endif
free(string_nt);
HPDF_Free(pdf);
@@ -201,7 +206,11 @@ bool haru_nsfont_position_in_string(const plot_font_style_t *fstyle,
*actual_x = real_width;
#ifdef FONT_HARU_DEBUG
- LOG("Position in string: %s at x: %i; Calculated position: %i", string_nt, x, *char_offset);
+ NSLOG(netsurf, INFO,
+ "Position in string: %s at x: %i; Calculated position: %i",
+ string_nt,
+ x,
+ *char_offset);
#endif
free(string_nt);
HPDF_Free(pdf);
@@ -246,7 +255,12 @@ bool haru_nsfont_split(const plot_font_style_t *fstyle,
HPDF_TRUE, &real_width);
#ifdef FONT_HARU_DEBUG
- LOG("Splitting string: %s for width: %i ; Calculated position: %i Calculated real_width: %f", string_nt, x, *char_offset, real_width);
+ NSLOG(netsurf, INFO,
+ "Splitting string: %s for width: %i ; Calculated position: %i Calculated real_width: %f",
+ string_nt,
+ x,
+ *char_offset,
+ real_width);
#endif
*char_offset = offset - 1;
@@ -327,7 +341,7 @@ bool haru_nsfont_apply_style(const plot_font_style_t *fstyle,
strcat(font_name, "-Roman");
#ifdef FONT_HARU_DEBUG
- LOG("Setting font: %s", font_name);
+ NSLOG(netsurf, INFO, "Setting font: %s", font_name);
#endif
size = fstyle->size;
diff --git a/desktop/frames.c b/desktop/frames.c
index 9eefefe02..e22287630 100644
--- a/desktop/frames.c
+++ b/desktop/frames.c
@@ -354,9 +354,11 @@ nserror browser_window_create_frameset(struct browser_window *bw,
window->parent = bw;
if (window->name)
- LOG("Created frame '%s'", window->name);
+ NSLOG(netsurf, INFO, "Created frame '%s'",
+ window->name);
else
- LOG("Created frame (unnamed)");
+ NSLOG(netsurf, INFO,
+ "Created frame (unnamed)");
}
}
diff --git a/desktop/global_history.c b/desktop/global_history.c
index a19349f51..ad39a3e41 100644
--- a/desktop/global_history.c
+++ b/desktop/global_history.c
@@ -536,7 +536,9 @@ static nserror global_history_initialise_entry_fields(void)
goto error;
}
- gh_ctx.fields[GH_URL].flags = TREE_FLAG_COPY_TEXT;
+ gh_ctx.fields[GH_URL].flags =
+ TREE_FLAG_COPY_TEXT |
+ TREE_FLAG_SEARCHABLE;
label = "TreeviewLabelURL";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
@@ -596,7 +598,7 @@ static nserror global_history_initialise_time(void)
/* get the current time */
t = time(NULL);
if (t == -1) {
- LOG("time info unaviable");
+ NSLOG(netsurf, INFO, "time info unaviable");
return NSERROR_UNKNOWN;
}
@@ -607,7 +609,7 @@ static nserror global_history_initialise_time(void)
full_time->tm_hour = 0;
t = mktime(full_time);
if (t == -1) {
- LOG("mktime failed");
+ NSLOG(netsurf, INFO, "mktime failed");
return NSERROR_UNKNOWN;
}
@@ -729,7 +731,7 @@ nserror global_history_init(struct core_window_callback_table *cw_t,
return err;
}
- LOG("Loading global history");
+ NSLOG(netsurf, INFO, "Loading global history");
/* Init. global history treeview time */
err = global_history_initialise_time();
@@ -752,7 +754,8 @@ nserror global_history_init(struct core_window_callback_table *cw_t,
err = treeview_create(&gh_ctx.tree, &gh_tree_cb_t,
N_FIELDS, gh_ctx.fields,
cw_t, core_window_handle,
- TREEVIEW_NO_MOVES | TREEVIEW_DEL_EMPTY_DIRS);
+ TREEVIEW_NO_MOVES | TREEVIEW_DEL_EMPTY_DIRS |
+ TREEVIEW_SEARCHABLE);
if (err != NSERROR_OK) {
gh_ctx.tree = NULL;
return err;
@@ -785,7 +788,7 @@ nserror global_history_init(struct core_window_callback_table *cw_t,
/* Inform client of window height */
treeview_get_height(gh_ctx.tree);
- LOG("Loaded global history");
+ NSLOG(netsurf, INFO, "Loaded global history");
return NSERROR_OK;
}
@@ -797,7 +800,7 @@ nserror global_history_fini(void)
int i;
nserror err;
- LOG("Finalising global history");
+ NSLOG(netsurf, INFO, "Finalising global history");
gh_ctx.built = false;
@@ -815,7 +818,7 @@ nserror global_history_fini(void)
return err;
}
- LOG("Finalised global history");
+ NSLOG(netsurf, INFO, "Finalised global history");
return err;
}
@@ -832,7 +835,8 @@ nserror global_history_add(nsurl *url)
data = urldb_get_url_data(url);
if (data == NULL) {
- LOG("Can't add URL to history that's not present in urldb.");
+ NSLOG(netsurf, INFO,
+ "Can't add URL to history that's not present in urldb.");
return NSERROR_BAD_PARAMETER;
}
diff --git a/desktop/hotlist.c b/desktop/hotlist.c
index 0f5be77c9..4bdd7c8cb 100644
--- a/desktop/hotlist.c
+++ b/desktop/hotlist.c
@@ -138,7 +138,8 @@ static nserror hotlist_save(const char *path)
/* Replace any old hotlist file with the one we just saved */
if (rename(temp_path, path) != 0) {
res = NSERROR_SAVE_FAILED;
- LOG("Error renaming hotlist: %s.", strerror(errno));
+ NSLOG(netsurf, INFO, "Error renaming hotlist: %s.",
+ strerror(errno));
goto cleanup;
}
@@ -652,20 +653,20 @@ static nserror hotlist_load_entry(dom_node *li, hotlist_load_ctx *ctx)
/* The li must contain an "a" element */
a = libdom_find_first_element(li, corestring_lwc_a);
if (a == NULL) {
- LOG("Missing <a> in <li>");
+ NSLOG(netsurf, INFO, "Missing <a> in <li>");
return NSERROR_INVALID;
}
derror = dom_node_get_text_content(a, &title1);
if (derror != DOM_NO_ERR) {
- LOG("No title");
+ NSLOG(netsurf, INFO, "No title");
dom_node_unref(a);
return NSERROR_INVALID;
}
derror = dom_element_get_attribute(a, corestring_dom_href, &url1);
if (derror != DOM_NO_ERR || url1 == NULL) {
- LOG("No URL");
+ NSLOG(netsurf, INFO, "No URL");
dom_string_unref(title1);
dom_node_unref(a);
return NSERROR_INVALID;
@@ -683,7 +684,8 @@ static nserror hotlist_load_entry(dom_node *li, hotlist_load_ctx *ctx)
dom_string_unref(url1);
if (err != NSERROR_OK) {
- LOG("Failed normalising '%s'", dom_string_data(url1));
+ NSLOG(netsurf, INFO, "Failed normalising '%s'",
+ dom_string_data(url1));
if (title1 != NULL) {
dom_string_unref(title1);
@@ -763,7 +765,8 @@ nserror hotlist_load_directory_cb(dom_node *node, void *ctx)
error = dom_node_get_text_content(node, &title);
if (error != DOM_NO_ERR || title == NULL) {
- LOG("Empty <h4> or memory exhausted.");
+ NSLOG(netsurf, INFO,
+ "Empty <h4> or memory exhausted.");
dom_string_unref(name);
return NSERROR_DOM;
}
@@ -861,7 +864,7 @@ static nserror hotlist_load(const char *path, bool *loaded)
/* Handle no path */
if (path == NULL) {
- LOG("No hotlist file path provided.");
+ NSLOG(netsurf, INFO, "No hotlist file path provided.");
return NSERROR_OK;
}
@@ -1195,8 +1198,10 @@ static nserror hotlist_initialise_entry_fields(void)
goto error;
}
- hl_ctx.fields[HL_URL].flags = TREE_FLAG_ALLOW_EDIT |
- TREE_FLAG_COPY_TEXT;
+ hl_ctx.fields[HL_URL].flags =
+ TREE_FLAG_ALLOW_EDIT |
+ TREE_FLAG_COPY_TEXT |
+ TREE_FLAG_SEARCHABLE;
label = "TreeviewLabelURL";
label = messages_get(label);
if (lwc_intern_string(label, strlen(label),
@@ -1283,7 +1288,7 @@ nserror hotlist_init(
return err;
}
- LOG("Loading hotlist");
+ NSLOG(netsurf, INFO, "Loading hotlist");
hl_ctx.tree = NULL;
hl_ctx.built = false;
@@ -1310,7 +1315,7 @@ nserror hotlist_init(
/* Create the hotlist treeview */
err = treeview_create(&hl_ctx.tree, &hl_tree_cb_t,
HL_N_FIELDS, hl_ctx.fields, NULL, NULL,
- TREEVIEW_NO_FLAGS);
+ TREEVIEW_SEARCHABLE);
if (err != NSERROR_OK) {
free(hl_ctx.save_path);
hl_ctx.tree = NULL;
@@ -1329,7 +1334,7 @@ nserror hotlist_init(
* the treeview is built. */
hl_ctx.built = true;
- LOG("Loaded hotlist");
+ NSLOG(netsurf, INFO, "Loaded hotlist");
return NSERROR_OK;
}
@@ -1375,7 +1380,7 @@ nserror hotlist_fini(void)
int i;
nserror err;
- LOG("Finalising hotlist");
+ NSLOG(netsurf, INFO, "Finalising hotlist");
/* Remove any existing scheduled save callback */
guit->misc->schedule(-1, hotlist_schedule_save_cb, NULL);
@@ -1384,7 +1389,7 @@ nserror hotlist_fini(void)
/* Save the hotlist */
err = hotlist_save(hl_ctx.save_path);
if (err != NSERROR_OK) {
- LOG("Problem saving the hotlist.");
+ NSLOG(netsurf, INFO, "Problem saving the hotlist.");
}
free(hl_ctx.save_path);
@@ -1403,7 +1408,7 @@ nserror hotlist_fini(void)
return err;
}
- LOG("Finalised hotlist");
+ NSLOG(netsurf, INFO, "Finalised hotlist");
return err;
}
diff --git a/desktop/knockout.c b/desktop/knockout.c
index 7e964fc84..6dbf4ebcf 100644
--- a/desktop/knockout.c
+++ b/desktop/knockout.c
@@ -267,7 +267,9 @@ static nserror knockout_plot_flush(const struct redraw_context *ctx)
/* debugging information */
#ifdef KNOCKOUT_DEBUG
- LOG("Entries are %i/%i, %i/%i, %i/%i", knockout_entry_cur, KNOCKOUT_ENTRIES, knockout_box_cur, KNOCKOUT_BOXES, knockout_polygon_cur, KNOCKOUT_POLYGONS);
+ NSLOG(netsurf, INFO, "Entries are %i/%i, %i/%i, %i/%i",
+ knockout_entry_cur, KNOCKOUT_ENTRIES, knockout_box_cur,
+ KNOCKOUT_BOXES, knockout_polygon_cur, KNOCKOUT_POLYGONS);
#endif
for (i = 0; i < knockout_entry_cur; i++) {
@@ -702,8 +704,8 @@ knockout_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
if (clip->x1 < clip->x0 || clip->y0 > clip->y1) {
#ifdef KNOCKOUT_DEBUG
- LOG("bad clip rectangle %i %i %i %i",
- clip->x0, clip->y0, clip->x1, clip->y1);
+ NSLOG(netsurf, INFO, "bad clip rectangle %i %i %i %i",
+ clip->x0, clip->y0, clip->x1, clip->y1);
#endif
return NSERROR_BAD_SIZE;
}
diff --git a/desktop/local_history.c b/desktop/local_history.c
index 01222e204..3219de90c 100644
--- a/desktop/local_history.c
+++ b/desktop/local_history.c
@@ -144,9 +144,9 @@ redraw_entry(struct history *history,
}
/* Only attempt to plot bitmap if it is present */
- if (entry->bitmap != NULL) {
+ if (entry->page.bitmap != NULL) {
res = ctx->plot->bitmap(ctx,
- entry->bitmap,
+ entry->page.bitmap,
entry->x + x,
entry->y + y,
WIDTH, HEIGHT,
diff --git a/desktop/mouse.c b/desktop/mouse.c
index 6d22fd461..d22910582 100644
--- a/desktop/mouse.c
+++ b/desktop/mouse.c
@@ -30,5 +30,5 @@
*/
void browser_mouse_state_dump(browser_mouse_state mouse)
{
- LOG("mouse state: %s %s %s %s %s %s %s %s %s %s %s %s %s %s", mouse & BROWSER_MOUSE_PRESS_1 ? "P1" : " ", mouse & BROWSER_MOUSE_PRESS_2 ? "P2" : " ", mouse & BROWSER_MOUSE_CLICK_1 ? "C1" : " ", mouse & BROWSER_MOUSE_CLICK_2 ? "C2" : " ", mouse & BROWSER_MOUSE_DOUBLE_CLICK ? "DC" : " ", mouse & BROWSER_MOUSE_TRIPLE_CLICK ? "TC" : " ", mouse & BROWSER_MOUSE_DRAG_1 ? "D1" : " ", mouse & BROWSER_MOUSE_DRAG_2 ? "D2" : " ", mouse & BROWSER_MOUSE_DRAG_ON ? "DO" : " ", mouse & BROWSER_MOUSE_HOLDING_1 ? "H1" : " ", mouse & BROWSER_MOUSE_HOLDING_2 ? "H2" : " ", mouse & BROWSER_MOUSE_MOD_1 ? "M1" : " ", mouse & BROWSER_MOUSE_MOD_2 ? "M2" : " ", mouse & BROWSER_MOUSE_MOD_3 ? "M3" : " ");
+ NSLOG(netsurf, INFO, "mouse state: %s %s %s %s %s %s %s %s %s %s %s %s %s %s", mouse & BROWSER_MOUSE_PRESS_1 ? "P1" : " ", mouse & BROWSER_MOUSE_PRESS_2 ? "P2" : " ", mouse & BROWSER_MOUSE_CLICK_1 ? "C1" : " ", mouse & BROWSER_MOUSE_CLICK_2 ? "C2" : " ", mouse & BROWSER_MOUSE_DOUBLE_CLICK ? "DC" : " ", mouse & BROWSER_MOUSE_TRIPLE_CLICK ? "TC" : " ", mouse & BROWSER_MOUSE_DRAG_1 ? "D1" : " ", mouse & BROWSER_MOUSE_DRAG_2 ? "D2" : " ", mouse & BROWSER_MOUSE_DRAG_ON ? "DO" : " ", mouse & BROWSER_MOUSE_HOLDING_1 ? "H1" : " ", mouse & BROWSER_MOUSE_HOLDING_2 ? "H2" : " ", mouse & BROWSER_MOUSE_MOD_1 ? "M1" : " ", mouse & BROWSER_MOUSE_MOD_2 ? "M2" : " ", mouse & BROWSER_MOUSE_MOD_3 ? "M3" : " ");
}
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index 3baa936f3..8aa949a5a 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -89,7 +89,8 @@
static void netsurf_lwc_iterator(lwc_string *str, void *pw)
{
- LOG("[%3u] %.*s", str->refcnt, (int)lwc_string_length(str), lwc_string_data(str));
+ NSLOG(netsurf, INFO, "[%3u] %.*s", str->refcnt,
+ (int)lwc_string_length(str), lwc_string_data(str));
}
/**
@@ -165,8 +166,9 @@ nserror netsurf_init(const char *store_path)
if (hlcache_parameters.llcache.limit < MINIMUM_MEMORY_CACHE_SIZE) {
hlcache_parameters.llcache.limit = MINIMUM_MEMORY_CACHE_SIZE;
- LOG("Setting minimum memory cache size %" PRIsizet,
- hlcache_parameters.llcache.limit);
+ NSLOG(netsurf, INFO,
+ "Setting minimum memory cache size %"PRIsizet,
+ hlcache_parameters.llcache.limit);
}
/* Set up the max attempts made to fetch a timing out resource */
@@ -243,19 +245,19 @@ void netsurf_exit(void)
{
hlcache_stop();
- LOG("Closing GUI");
+ NSLOG(netsurf, INFO, "Closing GUI");
guit->misc->quit();
- LOG("Finalising JavaScript");
+ NSLOG(netsurf, INFO, "Finalising JavaScript");
js_finalise();
- LOG("Finalising Web Search");
+ NSLOG(netsurf, INFO, "Finalising Web Search");
search_web_finalise();
- LOG("Finalising high-level cache");
+ NSLOG(netsurf, INFO, "Finalising high-level cache");
hlcache_finalise();
- LOG("Closing fetches");
+ NSLOG(netsurf, INFO, "Closing fetches");
fetcher_quit();
/* dump any remaining cache entries */
@@ -264,21 +266,21 @@ void netsurf_exit(void)
/* Clean up after content handlers */
content_factory_fini();
- LOG("Closing utf8");
+ NSLOG(netsurf, INFO, "Closing utf8");
utf8_finalise();
- LOG("Destroying URLdb");
+ NSLOG(netsurf, INFO, "Destroying URLdb");
urldb_destroy();
- LOG("Destroying System colours");
+ NSLOG(netsurf, INFO, "Destroying System colours");
ns_system_colour_finalize();
- LOG("Destroying Messages");
+ NSLOG(netsurf, INFO, "Destroying Messages");
messages_destroy();
corestrings_fini();
- LOG("Remaining lwc strings:");
+ NSLOG(netsurf, INFO, "Remaining lwc strings:");
lwc_iterate_strings(netsurf_lwc_iterator, NULL);
- LOG("Exited successfully");
+ NSLOG(netsurf, INFO, "Exited successfully");
}
diff --git a/desktop/options.h b/desktop/options.h
index d91898c6e..9b7064efa 100644
--- a/desktop/options.h
+++ b/desktop/options.h
@@ -289,3 +289,8 @@ NSOPTION_COLOUR(sys_colour_ThreeDShadow, 0x00d5d5d5)
NSOPTION_COLOUR(sys_colour_Window, 0x00f1f1f1)
NSOPTION_COLOUR(sys_colour_WindowFrame, 0x004e4e4e)
NSOPTION_COLOUR(sys_colour_WindowText, 0x00000000)
+
+/** Filter for non-verbose logging */
+NSOPTION_STRING(log_filter, "level:WARNING")
+/** Filter for verbose logging */
+NSOPTION_STRING(verbose_filter, "level:VERBOSE")
diff --git a/desktop/print.c b/desktop/print.c
index 37172b7c1..5c0333a96 100644
--- a/desktop/print.c
+++ b/desktop/print.c
@@ -126,8 +126,10 @@ print_apply_settings(hlcache_handle *content, struct print_settings *settings)
content_reformat(content, false, page_content_width, 0);
- LOG("New layout applied.New height = %d ; New width = %d ",
- content_get_height(content), content_get_width(content));
+ NSLOG(netsurf, INFO,
+ "New layout applied.New height = %d ; New width = %d ",
+ content_get_height(content),
+ content_get_width(content));
return true;
}
@@ -255,6 +257,11 @@ struct print_settings *print_make_settings(print_configuration configuration,
struct print_settings *settings;
css_fixed length = 0;
css_unit unit = CSS_UNIT_MM;
+ nscss_len_ctx len_ctx = {
+ .vw = DEFAULT_PAGE_WIDTH,
+ .vh = DEFAULT_PAGE_HEIGHT,
+ .root_style = NULL,
+ };
switch (configuration){
case PRINT_DEFAULT:
@@ -270,17 +277,17 @@ struct print_settings *print_make_settings(print_configuration configuration,
settings->scale = DEFAULT_EXPORT_SCALE;
length = INTTOFIX(DEFAULT_MARGIN_LEFT_MM);
- settings->margins[MARGINLEFT] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINLEFT] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(DEFAULT_MARGIN_RIGHT_MM);
- settings->margins[MARGINRIGHT] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINRIGHT] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(DEFAULT_MARGIN_TOP_MM);
- settings->margins[MARGINTOP] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINTOP] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(DEFAULT_MARGIN_BOTTOM_MM);
- settings->margins[MARGINBOTTOM] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINBOTTOM] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
break;
/* use settings from the Export options tab */
case PRINT_OPTIONS:
@@ -296,17 +303,17 @@ struct print_settings *print_make_settings(print_configuration configuration,
settings->scale = (float)nsoption_int(export_scale) / 100;
length = INTTOFIX(nsoption_int(margin_left));
- settings->margins[MARGINLEFT] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINLEFT] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(nsoption_int(margin_right));
- settings->margins[MARGINRIGHT] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINRIGHT] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(nsoption_int(margin_top));
- settings->margins[MARGINTOP] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINTOP] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
length = INTTOFIX(nsoption_int(margin_bottom));
- settings->margins[MARGINBOTTOM] =
- nscss_len2px(length, unit, NULL);
+ settings->margins[MARGINBOTTOM] = nscss_len2px(
+ &len_ctx, length, unit, NULL);
break;
default:
return NULL;
diff --git a/desktop/save_complete.c b/desktop/save_complete.c
index d6fb2feb1..9a88ad180 100644
--- a/desktop/save_complete.c
+++ b/desktop/save_complete.c
@@ -168,7 +168,7 @@ static bool save_complete_save_buffer(save_complete_ctx *ctx,
fp = fopen(fname, "wb");
if (fp == NULL) {
free(fname);
- LOG("fopen(): errno = %i", errno);
+ NSLOG(netsurf, INFO, "fopen(): errno = %i", errno);
guit->misc->warning("SaveError", strerror(errno));
return false;
}
@@ -195,10 +195,12 @@ static bool save_complete_save_buffer(save_complete_ctx *ctx,
* \param osize updated with the size of the result.
* \return converted source, or NULL on out of memory.
*/
-
-static char *save_complete_rewrite_stylesheet_urls(save_complete_ctx *ctx,
- const char *source, unsigned long size, const nsurl *base,
- unsigned long *osize)
+static char *
+save_complete_rewrite_stylesheet_urls(save_complete_ctx *ctx,
+ const char *source,
+ unsigned long size,
+ const nsurl *base,
+ unsigned long *osize)
{
char *rewritten;
unsigned long offset = 0;
@@ -207,8 +209,9 @@ static char *save_complete_rewrite_stylesheet_urls(save_complete_ctx *ctx,
/* count number occurrences of @import to (over)estimate result size */
/* can't use strstr because source is not 0-terminated string */
- for (offset = 0; SLEN("@import") < size &&
- offset <= size - SLEN("@import"); offset++) {
+ for (offset = 0;
+ (SLEN("@import") < size) && (offset <= (size - SLEN("@import")));
+ offset++) {
if (source[offset] == '@' &&
ascii_to_lower(source[offset + 1]) == 'i' &&
ascii_to_lower(source[offset + 2]) == 'm' &&
@@ -1044,7 +1047,7 @@ static bool save_complete_node_handler(dom_node *node,
} else if (type == DOM_DOCUMENT_NODE) {
/* Do nothing */
} else {
- LOG("Unhandled node type: %d", type);
+ NSLOG(netsurf, INFO, "Unhandled node type: %d", type);
}
return true;
@@ -1075,7 +1078,7 @@ static bool save_complete_save_html_document(save_complete_ctx *ctx,
fp = fopen(fname, "wb");
if (fp == NULL) {
free(fname);
- LOG("fopen(): errno = %i", errno);
+ NSLOG(netsurf, INFO, "fopen(): errno = %i", errno);
guit->misc->warning("SaveError", strerror(errno));
return false;
}
@@ -1154,7 +1157,7 @@ static bool save_complete_inventory(save_complete_ctx *ctx)
fp = fopen(fname, "w");
free(fname);
if (fp == NULL) {
- LOG("fopen(): errno = %i", errno);
+ NSLOG(netsurf, INFO, "fopen(): errno = %i", errno);
guit->misc->warning("SaveError", strerror(errno));
return false;
}
@@ -1182,7 +1185,8 @@ static nserror regcomp_wrapper(regex_t *preg, const char *regex, int cflags)
if (r) {
char errbuf[200];
regerror(r, preg, errbuf, sizeof errbuf);
- LOG("Failed to compile regexp '%s': %s\n", regex, errbuf);
+ NSLOG(netsurf, INFO, "Failed to compile regexp '%s': %s\n",
+ regex, errbuf);
return NSERROR_INIT_FAILED;
}
return NSERROR_OK;
diff --git a/desktop/save_pdf.c b/desktop/save_pdf.c
index d303eca7c..83e3d4f31 100644
--- a/desktop/save_pdf.c
+++ b/desktop/save_pdf.c
@@ -171,7 +171,8 @@ bool pdf_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *psty
{
DashPattern_e dash;
#ifdef PDF_DEBUG
- LOG("%d %d %d %d %f %X", x0, y0, x1, y1, page_height - y0, pstyle->fill_colour);
+ NSLOG(netsurf, INFO, "%d %d %d %d %f %X", x0, y0, x1, y1,
+ page_height - y0, pstyle->fill_colour);
#endif
if (pstyle->fill_type != PLOT_OP_TYPE_NONE) {
@@ -262,7 +263,7 @@ bool pdf_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
#ifdef PDF_DEBUG
int pmaxx = p[0], pmaxy = p[1];
int pminx = p[0], pminy = p[1];
- LOG(".");
+ NSLOG(netsurf, INFO, ".");
#endif
if (n == 0)
return true;
@@ -281,7 +282,8 @@ bool pdf_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
}
#ifdef PDF_DEBUG
- LOG("%d %d %d %d %f", pminx, pminy, pmaxx, pmaxy, page_height - pminy);
+ NSLOG(netsurf, INFO, "%d %d %d %d %f", pminx, pminy, pmaxx, pmaxy,
+ page_height - pminy);
#endif
HPDF_Page_Fill(pdf_page);
@@ -294,7 +296,8 @@ bool pdf_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
bool pdf_plot_clip(const struct rect *clip)
{
#ifdef PDF_DEBUG
- LOG("%d %d %d %d", clip->x0, clip->y0, clip->x1, clip->y1);
+ NSLOG(netsurf, INFO, "%d %d %d %d", clip->x0, clip->y0, clip->x1,
+ clip->y1);
#endif
/*Normalize cllipping area - to prevent overflows.
@@ -314,7 +317,7 @@ bool pdf_plot_text(int x, int y, const char *text, size_t length,
const plot_font_style_t *fstyle)
{
#ifdef PDF_DEBUG
- LOG(". %d %d %.*s", x, y, (int)length, text);
+ NSLOG(netsurf, INFO, ". %d %d %.*s", x, y, (int)length, text);
#endif
char *word;
HPDF_Font pdf_font;
@@ -347,7 +350,7 @@ bool pdf_plot_text(int x, int y, const char *text, size_t length,
bool pdf_plot_disc(int x, int y, int radius, const plot_style_t *style)
{
#ifdef PDF_DEBUG
- LOG(".");
+ NSLOG(netsurf, INFO, ".");
#endif
if (style->fill_type != PLOT_OP_TYPE_NONE) {
apply_clip_and_mode(false,
@@ -378,7 +381,8 @@ bool pdf_plot_disc(int x, int y, int radius, const plot_style_t *style)
bool pdf_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
{
#ifdef PDF_DEBUG
- LOG("%d %d %d %d %d %X", x, y, radius, angle1, angle2, style->stroke_colour);
+ NSLOG(netsurf, INFO, "%d %d %d %d %d %X", x, y, radius, angle1,
+ angle2, style->stroke_colour);
#endif
/* FIXME: line width 1 is ok ? */
@@ -406,7 +410,8 @@ bool pdf_plot_bitmap_tile(int x, int y, int width, int height,
HPDF_REAL max_width, max_height;
#ifdef PDF_DEBUG
- LOG("%d %d %d %d %p 0x%x", x, y, width, height, bitmap, bg);
+ NSLOG(netsurf, INFO, "%d %d %d %d %p 0x%x", x, y, width, height,
+ bitmap, bg);
#endif
if (width == 0 || height == 0)
return true;
@@ -483,7 +488,8 @@ HPDF_Image pdf_extract_image(struct bitmap *bitmap)
rgb_buffer = (unsigned char *)malloc(3 * img_width * img_height);
alpha_buffer = (unsigned char *)malloc(img_width * img_height);
if (rgb_buffer == NULL || alpha_buffer == NULL) {
- LOG("Not enough memory to create RGB buffer");
+ NSLOG(netsurf, INFO,
+ "Not enough memory to create RGB buffer");
free(rgb_buffer);
free(alpha_buffer);
return NULL;
@@ -607,7 +613,7 @@ bool pdf_plot_path(const float *p, unsigned int n, colour fill, float width,
bool empty_path;
#ifdef PDF_DEBUG
- LOG(".");
+ NSLOG(netsurf, INFO, ".");
#endif
if (n == 0)
@@ -649,7 +655,7 @@ bool pdf_plot_path(const float *p, unsigned int n, colour fill, float width,
i += 7;
empty_path = false;
} else {
- LOG("bad path command %f", p[i]);
+ NSLOG(netsurf, INFO, "bad path command %f", p[i]);
return false;
}
}
@@ -685,7 +691,7 @@ bool pdf_begin(struct print_settings *print_settings)
HPDF_Free(pdf_doc);
pdf_doc = HPDF_New(error_handler, NULL);
if (!pdf_doc) {
- LOG("Error creating pdf_doc");
+ NSLOG(netsurf, INFO, "Error creating pdf_doc");
return false;
}
@@ -708,7 +714,7 @@ bool pdf_begin(struct print_settings *print_settings)
pdf_page = NULL;
#ifdef PDF_DEBUG
- LOG("pdf_begin finishes");
+ NSLOG(netsurf, INFO, "pdf_begin finishes");
#endif
return true;
}
@@ -717,7 +723,7 @@ bool pdf_begin(struct print_settings *print_settings)
bool pdf_next_page(void)
{
#ifdef PDF_DEBUG
- LOG("pdf_next_page begins");
+ NSLOG(netsurf, INFO, "pdf_next_page begins");
#endif
clip_update_needed = false;
if (pdf_page != NULL) {
@@ -745,7 +751,7 @@ bool pdf_next_page(void)
pdfw_gs_save(pdf_page);
#ifdef PDF_DEBUG
- LOG("%f %f", page_width, page_height);
+ NSLOG(netsurf, INFO, "%f %f", page_width, page_height);
#endif
return true;
@@ -755,7 +761,7 @@ bool pdf_next_page(void)
void pdf_end(void)
{
#ifdef PDF_DEBUG
- LOG("pdf_end begins");
+ NSLOG(netsurf, INFO, "pdf_end begins");
#endif
clip_update_needed = false;
if (pdf_page != NULL) {
@@ -780,7 +786,7 @@ void pdf_end(void)
else
save_pdf(settings->output);
#ifdef PDF_DEBUG
- LOG("pdf_end finishes");
+ NSLOG(netsurf, INFO, "pdf_end finishes");
#endif
}
@@ -819,7 +825,8 @@ nserror save_pdf(const char *path)
static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no,
void *user_data)
{
- LOG("ERROR:\n\terror_no=%x\n\tdetail_no=%d\n", (HPDF_UINT)error_no, (HPDF_UINT)detail_no);
+ NSLOG(netsurf, INFO, "ERROR:\n\terror_no=%x\n\tdetail_no=%d\n",
+ (HPDF_UINT)error_no, (HPDF_UINT)detail_no);
#ifdef PDF_DEBUG
exit(1);
#endif
diff --git a/desktop/save_text.c b/desktop/save_text.c
index e63c96eb9..791ae9201 100644
--- a/desktop/save_text.c
+++ b/desktop/save_text.c
@@ -75,7 +75,8 @@ void save_as_text(struct hlcache_handle *c, char *path)
free(save.block);
if (ret != NSERROR_OK) {
- LOG("failed to convert to local encoding, return %d", ret);
+ NSLOG(netsurf, INFO,
+ "failed to convert to local encoding, return %d", ret);
return;
}
@@ -84,12 +85,13 @@ void save_as_text(struct hlcache_handle *c, char *path)
int res = fputs(result, out);
if (res < 0) {
- LOG("Warning: write failed");
+ NSLOG(netsurf, INFO, "Warning: write failed");
}
res = fputs("\n", out);
if (res < 0) {
- LOG("Warning: failed writing trailing newline");
+ NSLOG(netsurf, INFO,
+ "Warning: failed writing trailing newline");
}
fclose(out);
diff --git a/desktop/searchweb.c b/desktop/searchweb.c
index 29a998eb2..c07cac9d5 100644
--- a/desktop/searchweb.c
+++ b/desktop/searchweb.c
@@ -289,13 +289,19 @@ search_web_ico_callback(hlcache_handle *ico,
switch (event->type) {
case CONTENT_MSG_DONE:
- LOG("icon '%s' retrieved", nsurl_access(hlcache_handle_get_url(ico)));
+ NSLOG(netsurf, INFO, "icon '%s' retrieved",
+ nsurl_access(hlcache_handle_get_url(ico)));
guit->search_web->provider_update(provider->name,
content_get_bitmap(ico));
break;
case CONTENT_MSG_ERROR:
- LOG("icon %s error: %s", nsurl_access(hlcache_handle_get_url(ico)), event->data.error);
+ NSLOG(netsurf, INFO, "icon %s error: %s",
+ nsurl_access(hlcache_handle_get_url(ico)),
+ event->data.error);
+ /* fall through */
+
+ case CONTENT_MSG_ERRORCODE:
hlcache_handle_release(ico);
/* clear reference to released handle */
provider->ico_handle = NULL;
@@ -438,7 +444,8 @@ default_ico_callback(hlcache_handle *ico,
switch (event->type) {
case CONTENT_MSG_DONE:
- LOG("default icon '%s' retrieved", nsurl_access(hlcache_handle_get_url(ico)));
+ NSLOG(netsurf, INFO, "default icon '%s' retrieved",
+ nsurl_access(hlcache_handle_get_url(ico)));
/* only set to default icon if providers icon has no handle */
if (ctx->providers[search_web_ctx.current].ico_handle == NULL) {
@@ -449,7 +456,12 @@ default_ico_callback(hlcache_handle *ico,
break;
case CONTENT_MSG_ERROR:
- LOG("icon %s error: %s", nsurl_access(hlcache_handle_get_url(ico)), event->data.error);
+ NSLOG(netsurf, INFO, "icon %s error: %s",
+ nsurl_access(hlcache_handle_get_url(ico)),
+ event->data.error);
+ /* fall through */
+
+ case CONTENT_MSG_ERRORCODE:
hlcache_handle_release(ico);
/* clear reference to released handle */
ctx->default_ico_handle = NULL;
diff --git a/desktop/selection.c b/desktop/selection.c
index 7506af0ef..5cb43b8c3 100644
--- a/desktop/selection.c
+++ b/desktop/selection.c
@@ -70,18 +70,20 @@ struct selection_string {
typedef bool (*seln_traverse_handler)(const char *text, size_t length,
- struct box *box, void *handle, const char *whitespace_text,
- size_t whitespace_length);
+ struct box *box, const nscss_len_ctx *len_ctx, void *handle,
+ const char *whitespace_text, size_t whitespace_length);
-static bool redraw_handler(const char *text, size_t length, struct box *box,
+static bool redraw_handler(const char *text, size_t length,
+ struct box *box, const nscss_len_ctx *len_ctx,
void *handle, const char *whitespace_text,
size_t whitespace_length);
static void selection_redraw(struct selection *s, unsigned start_idx,
unsigned end_idx);
static bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx,
unsigned *start_offset, unsigned *end_offset);
-static bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
+static bool traverse_tree(struct box *box, const nscss_len_ctx *len_ctx,
+ unsigned start_idx, unsigned end_idx,
seln_traverse_handler handler,
void *handle, save_text_whitespace *before, bool *first,
bool do_marker);
@@ -198,7 +200,10 @@ void selection_reinit(struct selection *s, struct box *root)
* \param root the root box for html document or NULL for text/plain
*/
-void selection_init(struct selection *s, struct box *root)
+void selection_init(
+ struct selection *s,
+ struct box *root,
+ const nscss_len_ctx *len_ctx)
{
if (s->defined)
selection_clear(s, true);
@@ -207,6 +212,13 @@ void selection_init(struct selection *s, struct box *root)
s->start_idx = 0;
s->end_idx = 0;
s->drag_state = DRAG_NONE;
+ if (len_ctx != NULL) {
+ s->len_ctx = *len_ctx;
+ } else {
+ s->len_ctx.vw = 0;
+ s->len_ctx.vh = 0;
+ s->len_ctx.root_style = NULL;
+ }
selection_reinit(s, root);
}
@@ -442,6 +454,7 @@ bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx,
* for all boxes that lie (partially) within the given range
*
* \param box box subtree
+ * \param len_ctx Length conversion context.
* \param start_idx start of range within textual representation (bytes)
* \param end_idx end of range
* \param handler handler function to call
@@ -452,7 +465,9 @@ bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx,
* \return false iff traversal abandoned part-way through
*/
-bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
+bool traverse_tree(
+ struct box *box, const nscss_len_ctx *len_ctx,
+ unsigned start_idx, unsigned end_idx,
seln_traverse_handler handler,
void *handle, save_text_whitespace *before, bool *first,
bool do_marker)
@@ -473,9 +488,9 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
if (box->list_marker) {
/* do the marker box before continuing with the rest of the
* list element */
- if (!traverse_tree(box->list_marker, start_idx, end_idx,
- handler, handle, before, first,
- true))
+ if (!traverse_tree(box->list_marker, len_ctx,
+ start_idx, end_idx, handler, handle,
+ before, first, true))
return false;
}
@@ -506,7 +521,7 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
&end_offset)) {
if (!handler(box->text + start_offset, min(box->length,
end_offset) - start_offset,
- box, handle, whitespace_text,
+ box, len_ctx, handle, whitespace_text,
whitespace_length))
return false;
if (before) {
@@ -533,7 +548,7 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
* the tree */
struct box *next = child->next;
- if (!traverse_tree(child, start_idx, end_idx,
+ if (!traverse_tree(child, len_ctx, start_idx, end_idx,
handler, handle, before, first, false))
return false;
@@ -568,14 +583,16 @@ static bool selection_traverse(struct selection *s,
if (s->root) {
/* HTML */
- return traverse_tree(s->root, s->start_idx, s->end_idx,
- handler, handle, &before, &first, false);
+ return traverse_tree(s->root, &s->len_ctx,
+ s->start_idx, s->end_idx,
+ handler, handle,
+ &before, &first, false);
}
/* Text */
text = textplain_get_raw_data(s->c, s->start_idx, s->end_idx, &length);
- if (text && !handler(text, length, NULL, handle, NULL, 0))
+ if (text && !handler(text, length, NULL, NULL, handle, NULL, 0))
return false;
return true;
@@ -597,8 +614,8 @@ static bool selection_traverse(struct selection *s,
*/
bool redraw_handler(const char *text, size_t length, struct box *box,
- void *handle, const char *whitespace_text,
- size_t whitespace_length)
+ const nscss_len_ctx *len_ctx, void *handle,
+ const char *whitespace_text, size_t whitespace_length)
{
if (box) {
struct rdw_info *r = (struct rdw_info*)handle;
@@ -606,7 +623,7 @@ bool redraw_handler(const char *text, size_t length, struct box *box,
int x, y;
plot_font_style_t fstyle;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(len_ctx, box->style, &fstyle);
/* \todo - it should be possible to reduce the redrawn area by
* considering the 'text', 'length' and 'space' parameters */
@@ -652,7 +669,7 @@ void selection_redraw(struct selection *s, unsigned start_idx, unsigned end_idx)
rdw.inited = false;
if (s->root) {
- if (!traverse_tree(s->root, start_idx, end_idx,
+ if (!traverse_tree(s->root, &s->len_ctx, start_idx, end_idx,
redraw_handler, &rdw,
NULL, NULL, false))
return;
@@ -739,10 +756,11 @@ static bool selection_string_append(const char *text, size_t length, bool space,
/**
* Selection traversal routine for appending text to a string
*
- * \param text pointer to text being added, or NULL for newline
- * \param length length of text to be appended (bytes)
- * \param box pointer to text box, or NULL if from textplain
- * \param handle selection string to append to
+ * \param text pointer to text being added, or NULL for newline
+ * \param length length of text to be appended (bytes)
+ * \param box pointer to text box, or NULL if from textplain
+ * \param len_ctx Length conversion context
+ * \param handle selection string to append to
* \param whitespace_text whitespace to place before text for formatting
* may be NULL
* \param whitespace_length length of whitespace_text
@@ -750,7 +768,8 @@ static bool selection_string_append(const char *text, size_t length, bool space,
*/
static bool selection_copy_handler(const char *text, size_t length,
- struct box *box, void *handle, const char *whitespace_text,
+ struct box *box, const nscss_len_ctx *len_ctx,
+ void *handle, const char *whitespace_text,
size_t whitespace_length)
{
bool add_space = false;
@@ -771,7 +790,7 @@ static bool selection_copy_handler(const char *text, size_t length,
if (box->style != NULL) {
/* Override default font style */
- font_plot_style_from_css(box->style, &style);
+ font_plot_style_from_css(len_ctx, box->style, &style);
pstyle = &style;
} else {
/* If there's no style, there must be no text */
diff --git a/desktop/selection.h b/desktop/selection.h
index e2bc3b31d..2f3f6dcfe 100644
--- a/desktop/selection.h
+++ b/desktop/selection.h
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include "netsurf/mouse.h"
+#include "content/handlers/css/utils.h"
struct box;
@@ -43,6 +44,7 @@ struct selection
{
struct content *c;
struct box *root;
+ nscss_len_ctx len_ctx;
unsigned max_idx; /* total bytes in text representation */
@@ -60,7 +62,10 @@ struct selection *selection_create(struct content *c, bool is_html);
void selection_prepare(struct selection *s, struct content *c, bool is_html);
void selection_destroy(struct selection *s);
-void selection_init(struct selection *s, struct box *root);
+void selection_init(
+ struct selection *s,
+ struct box *root,
+ const nscss_len_ctx *len_ctx);
void selection_reinit(struct selection *s, struct box *root);
/* struct box *selection_root(struct selection *s); */
diff --git a/desktop/sslcert_viewer.c b/desktop/sslcert_viewer.c
index e7f87bd9d..f40af5968 100644
--- a/desktop/sslcert_viewer.c
+++ b/desktop/sslcert_viewer.c
@@ -391,7 +391,7 @@ sslcert_viewer_init(struct core_window_callback_table *cw_t,
return err;
}
- LOG("Building certificate viewer");
+ NSLOG(netsurf, INFO, "Building certificate viewer");
/* Init. certificate chain treeview entry fields */
err = sslcert_init_entry_fields(ssl_d);
@@ -417,7 +417,7 @@ sslcert_viewer_init(struct core_window_callback_table *cw_t,
}
}
- LOG("Built certificate viewer");
+ NSLOG(netsurf, INFO, "Built certificate viewer");
return NSERROR_OK;
}
@@ -452,7 +452,7 @@ nserror sslcert_viewer_fini(struct sslcert_session_data *ssl_d)
int i;
nserror err;
- LOG("Finalising ssl certificate viewer");
+ NSLOG(netsurf, INFO, "Finalising ssl certificate viewer");
/* Destroy the treeview */
err = treeview_destroy(ssl_d->tree);
@@ -470,7 +470,7 @@ nserror sslcert_viewer_fini(struct sslcert_session_data *ssl_d)
return err;
}
- LOG("Finalised ssl certificate viewer");
+ NSLOG(netsurf, INFO, "Finalised ssl certificate viewer");
return err;
}
diff --git a/desktop/textarea.c b/desktop/textarea.c
index 65ee8b82f..3fd4c9804 100644
--- a/desktop/textarea.c
+++ b/desktop/textarea.c
@@ -828,7 +828,7 @@ static bool textarea_reflow_singleline(struct textarea *ta, size_t b_off,
ta->lines =
malloc(LINE_CHUNK_SIZE * sizeof(struct line_info));
if (ta->lines == NULL) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
return false;
}
ta->lines_alloc_size = LINE_CHUNK_SIZE;
@@ -852,7 +852,7 @@ static bool textarea_reflow_singleline(struct textarea *ta, size_t b_off,
char *temp = realloc(ta->password.data,
b_len + TA_ALLOC_STEP);
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
@@ -936,7 +936,8 @@ static bool textarea_reflow_multiline(struct textarea *ta,
if (ta->lines == NULL) {
ta->lines = calloc(sizeof(struct line_info), LINE_CHUNK_SIZE);
if (ta->lines == NULL) {
- LOG("Failed to allocate memory for textarea lines");
+ NSLOG(netsurf, INFO,
+ "Failed to allocate memory for textarea lines");
return false;
}
ta->lines_alloc_size = LINE_CHUNK_SIZE;
@@ -1053,7 +1054,7 @@ static bool textarea_reflow_multiline(struct textarea *ta,
(line + 2 + LINE_CHUNK_SIZE) *
sizeof(struct line_info));
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
@@ -1334,7 +1335,7 @@ static bool textarea_insert_text(struct textarea *ta, const char *text,
char *temp = realloc(ta->text.data, b_len + ta->text.len +
TA_ALLOC_STEP);
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
@@ -1484,7 +1485,7 @@ static bool textarea_replace_text_internal(struct textarea *ta, size_t b_start,
rep_len + ta->text.len - (b_end - b_start) +
TA_ALLOC_STEP);
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
@@ -1561,7 +1562,7 @@ static bool textarea_copy_to_undo_buffer(struct textarea *ta,
char *temp = realloc(undo->text.data,
b_offset + len + TA_ALLOC_STEP);
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
@@ -1575,7 +1576,7 @@ static bool textarea_copy_to_undo_buffer(struct textarea *ta,
(undo->next_detail + 128) *
sizeof(struct textarea_undo_detail));
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
@@ -1802,6 +1803,10 @@ static void textarea_setup_text_offsets(struct textarea *ta)
{
int text_y_offset, text_y_offset_baseline;
+ ta->line_height = FIXTOINT(FMUL(FLTTOFIX(1.3), FDIV(FMUL(
+ nscss_screen_dpi, FDIV(INTTOFIX(ta->fstyle.size),
+ INTTOFIX(FONT_SIZE_SCALE))), F_72)));
+
text_y_offset = text_y_offset_baseline = ta->border_width;
if (ta->flags & TEXTAREA_MULTILINE) {
/* Multiline textarea */
@@ -1821,6 +1826,27 @@ static void textarea_setup_text_offsets(struct textarea *ta)
}
+/**
+ * Set font styles up for a textarea.
+ *
+ * \param[in] ta Textarea to update.
+ * \param[in] fstyle Font style to set in textarea.
+ * \param[in] selected_text Textarea selected text colour.
+ * \param[in] selected_bg Textarea selection background colour.
+ */
+static void textarea_set_text_style(
+ struct textarea *ta,
+ const plot_font_style_t *fstyle,
+ colour selected_text,
+ colour selected_bg)
+{
+ ta->fstyle = *fstyle;
+
+ ta->sel_fstyle = *fstyle;
+ ta->sel_fstyle.foreground = selected_text;
+ ta->sel_fstyle.background = selected_bg;
+}
+
/* exported interface, documented in textarea.h */
struct textarea *textarea_create(const textarea_flags flags,
@@ -1835,13 +1861,13 @@ struct textarea *textarea_create(const textarea_flags flags,
flags & TEXTAREA_PASSWORD));
if (callback == NULL) {
- LOG("no callback provided");
+ NSLOG(netsurf, INFO, "no callback provided");
return NULL;
}
ret = malloc(sizeof(struct textarea));
if (ret == NULL) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
return NULL;
}
@@ -1860,11 +1886,10 @@ struct textarea *textarea_create(const textarea_flags flags,
ret->border_width = setup->border_width;
ret->border_col = setup->border_col;
- ret->fstyle = setup->text;
-
- ret->sel_fstyle = setup->text;
- ret->sel_fstyle.foreground = setup->selected_text;
- ret->sel_fstyle.background = setup->selected_bg;
+ textarea_set_text_style(ret,
+ &setup->text,
+ setup->selected_text,
+ setup->selected_bg);
ret->scroll_x = 0;
ret->scroll_y = 0;
@@ -1888,7 +1913,7 @@ struct textarea *textarea_create(const textarea_flags flags,
ret->text.data = malloc(TA_ALLOC_STEP);
if (ret->text.data == NULL) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
free(ret);
return NULL;
}
@@ -1900,7 +1925,7 @@ struct textarea *textarea_create(const textarea_flags flags,
if (flags & TEXTAREA_PASSWORD) {
ret->password.data = malloc(TA_ALLOC_STEP);
if (ret->password.data == NULL) {
- LOG("malloc failed");
+ NSLOG(netsurf, INFO, "malloc failed");
free(ret->text.data);
free(ret);
return NULL;
@@ -1975,7 +2000,7 @@ bool textarea_set_text(struct textarea *ta, const char *text)
if (len >= ta->text.alloc) {
char *temp = realloc(ta->text.data, len + TA_ALLOC_STEP);
if (temp == NULL) {
- LOG("realloc failed");
+ NSLOG(netsurf, INFO, "realloc failed");
return false;
}
ta->text.data = temp;
@@ -2062,7 +2087,7 @@ int textarea_get_text(struct textarea *ta, char *buf, unsigned int len)
}
if (len < ta->text.len) {
- LOG("buffer too small");
+ NSLOG(netsurf, INFO, "buffer too small");
return -1;
}
@@ -2073,6 +2098,17 @@ int textarea_get_text(struct textarea *ta, char *buf, unsigned int len)
/* exported interface, documented in textarea.h */
+const char * textarea_data(struct textarea *ta, unsigned int *len)
+{
+ if (len != NULL) {
+ *len = ta->text.len;
+ }
+
+ return ta->text.data;
+}
+
+
+/* exported interface, documented in textarea.h */
bool textarea_set_caret(struct textarea *ta, int caret)
{
int b_off;
@@ -2849,7 +2885,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
return false;
}
- redraw &= ~textarea_set_caret_internal(ta, caret);
+ redraw &= !textarea_set_caret_internal(ta, caret);
/* TODO: redraw only the bit that changed */
msg.ta = ta;
@@ -3208,8 +3244,12 @@ void textarea_set_dimensions(struct textarea *ta, int width, int height)
/* exported interface, documented in textarea.h */
-void textarea_set_layout(struct textarea *ta, int width, int height,
- int top, int right, int bottom, int left)
+void textarea_set_layout(
+ struct textarea *ta,
+ const plot_font_style_t *fstyle,
+ int width, int height,
+ int top, int right,
+ int bottom, int left)
{
struct rect r = {0, 0, 0, 0};
@@ -3220,6 +3260,10 @@ void textarea_set_layout(struct textarea *ta, int width, int height,
ta->pad_bottom = bottom + ((ta->bar_x == NULL) ? 0 : SCROLLBAR_WIDTH);
ta->pad_left = left;
+ textarea_set_text_style(ta, fstyle,
+ ta->sel_fstyle.foreground,
+ ta->sel_fstyle.background);
+
textarea_setup_text_offsets(ta);
if (ta->flags & TEXTAREA_MULTILINE) {
diff --git a/desktop/textarea.h b/desktop/textarea.h
index 898609730..82e0de95b 100644
--- a/desktop/textarea.h
+++ b/desktop/textarea.h
@@ -213,6 +213,16 @@ int textarea_get_text(struct textarea *ta, char *buf, unsigned int len);
/**
+ * Access text data in a text area
+ *
+ * \param[in] ta Text area
+ * \param[out] len Returns byte length of returned text, if passed non-NULL.
+ * \return textarea string data.
+ */
+const char * textarea_data(struct textarea *ta, unsigned int *len);
+
+
+/**
* Set the caret's position
*
* \param ta Text area
@@ -319,8 +329,12 @@ void textarea_set_dimensions(struct textarea *ta, int width, int height);
* \param bottom the new bottom padding of the textarea
* \param left the new left padding of the textarea
*/
-void textarea_set_layout(struct textarea *ta, int width, int height,
- int top, int right, int bottom, int left);
+void textarea_set_layout(
+ struct textarea *ta,
+ const plot_font_style_t *fstyle,
+ int width, int height,
+ int top, int right,
+ int bottom, int left);
/**
diff --git a/desktop/treeview.c b/desktop/treeview.c
index fe3aa94c3..1651ff5ef 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -22,10 +22,13 @@
* Treeview handling implementation.
*/
+#include <string.h>
+
#include "utils/utils.h"
#include "utils/log.h"
#include "utils/nsurl.h"
#include "utils/nsoption.h"
+#include "utils/config.h"
#include "netsurf/bitmap.h"
#include "netsurf/content.h"
#include "netsurf/plotters.h"
@@ -104,7 +107,8 @@ enum treeview_node_flags {
TV_NFLAGS_NONE = 0, /**< No node flags set */
TV_NFLAGS_EXPANDED = (1 << 0), /**< Whether node is expanded */
TV_NFLAGS_SELECTED = (1 << 1), /**< Whether node is selected */
- TV_NFLAGS_SPECIAL = (1 << 2) /**< Render as special node */
+ TV_NFLAGS_SPECIAL = (1 << 2), /**< Render as special node */
+ TV_NFLAGS_MATCHED = (1 << 3), /**< Whether node matches search */
};
@@ -171,7 +175,8 @@ struct treeview_drag {
TV_DRAG_NONE,
TV_DRAG_SELECTION,
TV_DRAG_MOVE,
- TV_DRAG_TEXTAREA
+ TV_DRAG_TEXTAREA,
+ TV_DRAG_SEARCH,
} type; /**< Drag type */
treeview_node *start_node; /**< Start node */
bool selected; /**< Start node is selected */
@@ -207,6 +212,17 @@ struct treeview_edit {
/**
+ * Treeview search box details
+ */
+struct treeview_search {
+ struct textarea *textarea; /**< Search box. */
+ bool active; /**< Whether the search box has focus. */
+ bool search; /**< Whether we have a search term. */
+ int height; /**< Current search display height. */
+};
+
+
+/**
* The treeview context
*/
struct treeview {
@@ -224,6 +240,8 @@ struct treeview {
struct treeview_move move; /**< Move drag details */
struct treeview_edit edit; /**< Edit details */
+ struct treeview_search search; /**< Treeview search box */
+
const struct treeview_callback_table *callbacks; /**< For node events */
const struct core_window_callback_table *cw_t; /**< Window cb table */
@@ -310,14 +328,28 @@ static struct treeview_resource treeview_res[TREE_RES_LAST] = {
/**
+ * Get the display height of the treeview data component of the display.
+ *
+ * \param[in] tree Treeview to get the height of.
+ * \return the display height in pixels.
+ */
+static inline int treeview__get_display_height(treeview *tree)
+{
+ return (tree->search.search == false) ?
+ tree->root->height :
+ tree->search.height;
+}
+
+
+/**
* Corewindow callback wrapper: Request a redraw of the window
*
* \param[in] tree The treeview to request redraw on.
* \param[in] r rectangle to redraw
*/
-static inline
-void cw_invalidate_area(const struct treeview *tree,
- const struct rect *r)
+static inline void treeview__cw_invalidate_area(
+ const struct treeview *tree,
+ const struct rect *r)
{
if (tree->cw_t != NULL) {
tree->cw_t->invalidate(tree->cw_h, r);
@@ -336,8 +368,33 @@ static inline void treeview__cw_update_size(
const struct treeview *tree,
int width, int height)
{
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
+
+ if (tree->cw_t != NULL) {
+ tree->cw_t->update_size(tree->cw_h, width,
+ height + search_height);
+ }
+}
+
+
+/**
+ * Corewindow callback_wrapper: Scroll to top of window.
+ *
+ * \param[in] tree The treeview to scroll.
+ */
+static inline void treeview__cw_scroll_top(
+ const struct treeview *tree)
+{
+ struct rect r = {
+ .x0 = 0,
+ .y0 = 0,
+ .x1 = tree_g.window_padding,
+ .y1 = tree_g.line_height,
+ };
+
if (tree->cw_t != NULL) {
- tree->cw_t->update_size(tree->cw_h, width, height);
+ tree->cw_t->scroll_visible(tree->cw_h, &r);
}
}
@@ -496,10 +553,35 @@ static int treeview_node_y(treeview *tree, treeview_node *node)
/**
+ * The treeview walk mode. Controls which nodes are visited in a walk.
+ */
+enum treeview_walk_mode {
+ /**
+ * Walk to all nodes in the (sub)tree.
+ */
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
+
+ /**
+ * Walk to expanded nodes in the (sub)tree only. Children of
+ * collapsed nodes are not visited.
+ */
+ TREEVIEW_WALK_MODE_LOGICAL_EXPANDED,
+
+ /**
+ * Walk displayed nodes. This differs from the
+ * `TREEVIEW_WALK_MODE_LOGICAL_EXPANDED` mode when there is
+ * an active search filter display.
+ */
+ TREEVIEW_WALK_MODE_DISPLAY,
+};
+
+
+/**
* Walk a treeview subtree, calling a callback at each node (depth first)
*
+ * \param tree Treeview being walked.
* \param root Root to walk tree from (doesn't get a callback call)
- * \param full Iff true, visit children of collapsed nodes
+ * \param mode The treeview walk mode to use.
* \param callback_bwd Function to call on each node in backwards order
* \param callback_fwd Function to call on each node in forwards order
* \param ctx Context to pass to callback
@@ -507,30 +589,46 @@ static int treeview_node_y(treeview *tree, treeview_node *node)
*
* \note Any node deletion must happen in callback_bwd.
*/
-static nserror
-treeview_walk_internal(treeview_node *root,
- bool full,
- nserror (*callback_bwd)(treeview_node *n, void *ctx, bool *end),
- nserror (*callback_fwd)(treeview_node *n, void *ctx, bool *skip_children, bool *end),
- void *ctx)
+static nserror treeview_walk_internal(
+ treeview *tree,
+ treeview_node *root,
+ enum treeview_walk_mode mode,
+ nserror (*callback_bwd)(
+ treeview_node *n,
+ void *ctx,
+ bool *end),
+ nserror (*callback_fwd)(
+ treeview_node *n,
+ void *ctx,
+ bool *skip_children,
+ bool *end),
+ void *ctx)
{
treeview_node *node, *child, *parent, *next_sibling;
- bool abort = false;
+ bool walking_search = (mode == TREEVIEW_WALK_MODE_DISPLAY &&
+ tree->search.search == true);
bool skip_children = false;
+ bool abort = false;
+ bool full = false;
nserror err;
+ bool entry;
assert(root != NULL);
+ if (mode == TREEVIEW_WALK_MODE_LOGICAL_COMPLETE || walking_search) {
+ /* We need to visit children of collapsed folders. */
+ full = true;
+ }
+
node = root;
parent = node->parent;
next_sibling = node->next_sib;
- child = (!skip_children &&
- (full || (node->flags & TV_NFLAGS_EXPANDED))) ?
+ child = (full || (node->flags & TV_NFLAGS_EXPANDED)) ?
node->children : NULL;
while (node != NULL) {
- if (child != NULL) {
+ if (child != NULL && !skip_children) {
/* Down to children */
node = child;
} else {
@@ -538,9 +636,10 @@ treeview_walk_internal(treeview_node *root,
* go to next sibling if present, or nearest ancestor
* with a next sibling. */
- while (node != root &&
- next_sibling == NULL) {
- if (callback_bwd != NULL) {
+ while (node != root && next_sibling == NULL) {
+ entry = (node->type == TREE_NODE_ENTRY);
+ if (callback_bwd != NULL &&
+ (entry || !walking_search)) {
/* Backwards callback */
err = callback_bwd(node, ctx, &abort);
@@ -580,11 +679,18 @@ treeview_walk_internal(treeview_node *root,
assert(node != NULL);
assert(node != root);
+ entry = (node->type == TREE_NODE_ENTRY);
+
parent = node->parent;
next_sibling = node->next_sib;
child = (full || (node->flags & TV_NFLAGS_EXPANDED)) ?
node->children : NULL;
+ if (walking_search && (!entry ||
+ !(node->flags & TV_NFLAGS_MATCHED))) {
+ continue;
+ }
+
if (callback_fwd != NULL) {
/* Forwards callback */
err = callback_fwd(node, ctx, &skip_children, &abort);
@@ -597,13 +703,248 @@ treeview_walk_internal(treeview_node *root,
return NSERROR_OK;
}
}
- child = skip_children ? NULL : child;
}
return NSERROR_OK;
}
/**
+ * Data used when doing a treeview walk for search.
+ */
+struct treeview_search_walk_data {
+ treeview *tree; /**< The treeview to search. */
+ const char *text; /**< The string being searched for. */
+ const unsigned int len; /**< Length of string being searched for. */
+ int window_height; /**< Accumulate height for matching entries. */
+};
+
+
+/**
+ * Treewalk node callback for handling search.
+ *
+ * \param[in] n Current node.
+ * \param[in] ctx Treeview search context.
+ * \param[in,out] skip_children Flag to allow children to be skipped.
+ * \param[in,out] end Flag to allow iteration to be finished early.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror treeview__search_walk_cb(
+ treeview_node *n,
+ void *ctx,
+ bool *skip_children,
+ bool *end)
+{
+ struct treeview_search_walk_data *sw = ctx;
+
+ if (n->type != TREE_NODE_ENTRY) {
+ return NSERROR_OK;
+ }
+
+ if (sw->len == 0) {
+ n->flags &= ~TV_NFLAGS_MATCHED;
+ } else {
+ struct treeview_node_entry *entry =
+ (struct treeview_node_entry *)n;
+ bool matched = false;
+
+ for (int i = 0; i < sw->tree->n_fields; i++) {
+ struct treeview_field *ef = &(sw->tree->fields[i + 1]);
+ if (ef->flags & TREE_FLAG_SEARCHABLE) {
+ if (strcasestr(entry->fields[i].value.data,
+ sw->text) != NULL) {
+ matched = true;
+ break;
+ }
+ }
+ }
+
+ if (!matched && strcasestr(n->text.data, sw->text) != NULL) {
+ matched = true;
+ }
+
+ if (matched) {
+ n->flags |= TV_NFLAGS_MATCHED;
+ sw->window_height += n->height;
+ } else {
+ n->flags &= ~TV_NFLAGS_MATCHED;
+ }
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Search treeview for text.
+ *
+ * \param[in] tree Treeview to search.
+ * \param[in] text UTF-8 string to search for. (NULL-terminated.)
+ * \param[in] len Byte length of UTF-8 string.
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+static nserror treeview__search(
+ treeview *tree,
+ const char *text,
+ unsigned int len)
+{
+ nserror err;
+ uint32_t height;
+ uint32_t prev_height = treeview__get_display_height(tree);
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
+ struct treeview_search_walk_data sw = {
+ .len = len,
+ .text = text,
+ .tree = tree,
+ .window_height = 0,
+ };
+ struct rect r = {
+ .x0 = 0,
+ .y0 = search_height,
+ .x1 = REDRAW_MAX,
+ };
+
+ assert(text[len] == '\0');
+
+ if (tree->root == NULL) {
+ return NSERROR_OK;
+ }
+
+ err = treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE, NULL,
+ treeview__search_walk_cb, &sw);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ if (len > 0) {
+ tree->search.height = sw.window_height;
+ tree->search.search = true;
+ height = sw.window_height;
+ } else {
+ tree->search.search = false;
+ height = tree->root->height;
+ }
+
+ r.y1 = ((height > prev_height) ? height : prev_height) + search_height;
+ treeview__cw_invalidate_area(tree, &r);
+ treeview__cw_update_size(tree, -1, height);
+ treeview__cw_scroll_top(tree);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Cancel a treeview search, optionally droping focus from search widget.
+ *
+ * \param[in] tree Treeview to cancel search in.
+ * \param[in] drop_focus Iff true, drop input focus from search widget.
+ */
+static void treeview__search_cancel(treeview *tree, bool drop_focus)
+{
+ struct rect r = {
+ .x0 = tree_g.window_padding + tree_g.icon_size,
+ .x1 = 600,
+ .y0 = 0,
+ .y1 = tree_g.line_height,
+ };
+
+ tree->search.search = false;
+ if (tree->search.active == false) {
+ return;
+ }
+
+ if (drop_focus) {
+ tree->search.active = false;
+ textarea_set_caret(tree->search.textarea, -1);
+ } else {
+ textarea_set_caret(tree->search.textarea, 0);
+ }
+
+ textarea_set_text(tree->search.textarea, "");
+ treeview__cw_invalidate_area(tree, &r);
+}
+
+
+/**
+ * Callback for textarea_create, in desktop/treeview.h
+ *
+ * \param data treeview context
+ * \param msg textarea message
+ */
+static void treeview_textarea_search_callback(void *data,
+ struct textarea_msg *msg)
+{
+ treeview *tree = data;
+ struct rect *r;
+
+ if (tree->search.active == false || tree->root == NULL) {
+ return;
+ }
+
+ switch (msg->type) {
+ case TEXTAREA_MSG_DRAG_REPORT:
+ if (msg->data.drag == TEXTAREA_DRAG_NONE) {
+ /* Textarea drag finished */
+ tree->drag.type = TV_DRAG_NONE;
+ } else {
+ /* Textarea drag started */
+ tree->drag.type = TV_DRAG_SEARCH;
+ }
+ treeview__cw_drag_status(tree, tree->drag.type);
+ break;
+
+ case TEXTAREA_MSG_REDRAW_REQUEST:
+ r = &msg->data.redraw;
+ r->x0 += tree_g.window_padding + tree_g.icon_size;
+ r->y0 += 0;
+ r->x1 += 600;
+ r->y1 += tree_g.line_height;
+
+ /* Redraw the textarea */
+ treeview__cw_invalidate_area(tree, r);
+ break;
+
+ case TEXTAREA_MSG_TEXT_MODIFIED:
+ /* Textarea length includes trailing NULL, so subtract it. */
+ treeview__search(tree,
+ msg->data.modified.text,
+ msg->data.modified.len - 1);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**
+ * Update the layout for any active search.
+ *
+ * \param[in] tree The tree to update.
+ */
+static void treeview__search_update_display(
+ treeview *tree)
+{
+ const char *string;
+ unsigned int len;
+
+ if (tree->search.search == false) {
+ /* No active search to update view for. */
+ return;
+ }
+
+ string = textarea_data(tree->search.textarea, &len);
+ if (string == NULL || len == 0) {
+ return;
+ }
+
+ treeview__search(tree, string, len - 1);
+}
+
+
+/**
* Create treeview's root node
*
* \param[out] root Returns root node
@@ -668,14 +1009,17 @@ treeview_set_inset_from_parent(treeview_node *n,
/**
* Insert a treeview node into a treeview
*
- * \param a parentless node to insert
- * \param b tree node to insert a as a relation of
+ * \param tree the treeview to insert node into.
+ * \param a parentless node to insert
+ * \param b tree node to insert a as a relation of
* \param rel The relationship between \a a and \a b
*/
static inline void
-treeview_insert_node(treeview_node *a,
- treeview_node *b,
- enum treeview_relationship rel)
+treeview_insert_node(
+ treeview *tree,
+ treeview_node *a,
+ treeview_node *b,
+ enum treeview_relationship rel)
{
assert(a != NULL);
assert(a->parent == NULL);
@@ -710,8 +1054,9 @@ treeview_insert_node(treeview_node *a,
a->inset = a->parent->inset + tree_g.step_width;
if (a->children != NULL) {
- treeview_walk_internal(a, true, NULL,
- treeview_set_inset_from_parent, NULL);
+ treeview_walk_internal(tree, a,
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE, NULL,
+ treeview_set_inset_from_parent, NULL);
}
if (a->parent->flags & TV_NFLAGS_EXPANDED) {
@@ -776,7 +1121,7 @@ treeview_create_node_folder(treeview *tree,
n->client_data = data;
- treeview_insert_node(n, relation, rel);
+ treeview_insert_node(tree, n, relation, rel);
if (n->parent->flags & TV_NFLAGS_EXPANDED) {
/* Inform front end of change in dimensions */
@@ -791,7 +1136,7 @@ treeview_create_node_folder(treeview *tree,
r.y0 = treeview_node_y(tree, n);
r.x1 = REDRAW_MAX;
r.y1 = tree->root->height;
- cw_invalidate_area(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
}
@@ -842,7 +1187,7 @@ treeview_update_node_folder(treeview *tree,
r.y0 = treeview_node_y(tree, folder);
r.x1 = REDRAW_MAX;
r.y1 = r.y0 + tree_g.line_height;
- cw_invalidate_area(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
return NSERROR_OK;
@@ -907,6 +1252,8 @@ treeview_update_node_entry(treeview *tree,
}
}
+ treeview__search_update_display(tree);
+
/* Redraw */
if (entry->parent->flags & TV_NFLAGS_EXPANDED) {
struct rect r;
@@ -914,7 +1261,7 @@ treeview_update_node_entry(treeview *tree,
r.y0 = treeview_node_y(tree, entry);
r.x1 = REDRAW_MAX;
r.y1 = r.y0 + entry->height;
- cw_invalidate_area(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
return NSERROR_OK;
@@ -946,7 +1293,7 @@ treeview_create_node_entry(treeview *tree,
}
e = malloc(sizeof(struct treeview_node_entry) +
- (tree->n_fields - 1) * sizeof(struct treeview_field));
+ (tree->n_fields - 1) * sizeof(struct treeview_field));
if (e == NULL) {
return NSERROR_NOMEM;
}
@@ -962,8 +1309,8 @@ treeview_create_node_entry(treeview *tree,
assert(fields != NULL);
assert(fields[0].field != NULL);
assert(lwc_string_isequal(tree->fields[0].field,
- fields[0].field, &match) == lwc_error_ok &&
- match == true);
+ fields[0].field, &match) == lwc_error_ok &&
+ match == true);
n->text.data = fields[0].value;
n->text.len = fields[0].value_len;
n->text.width = 0;
@@ -978,15 +1325,15 @@ treeview_create_node_entry(treeview *tree,
for (i = 1; i < tree->n_fields; i++) {
assert(fields[i].field != NULL);
assert(lwc_string_isequal(tree->fields[i].field,
- fields[i].field, &match) == lwc_error_ok &&
- match == true);
+ fields[i].field, &match) == lwc_error_ok &&
+ match == true);
e->fields[i - 1].value.data = fields[i].value;
e->fields[i - 1].value.len = fields[i].value_len;
e->fields[i - 1].value.width = 0;
}
- treeview_insert_node(n, relation, rel);
+ treeview_insert_node(tree, n, relation, rel);
if (n->parent->flags & TV_NFLAGS_EXPANDED) {
/* Inform front end of change in dimensions */
@@ -1001,10 +1348,12 @@ treeview_create_node_entry(treeview *tree,
r.y0 = treeview_node_y(tree, n);
r.x1 = REDRAW_MAX;
r.y1 = tree->root->height;
- cw_invalidate_area(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
}
+ treeview__search_update_display(tree);
+
*entry = n;
return NSERROR_OK;
@@ -1087,11 +1436,11 @@ treeview_walk(treeview *tree,
if (root == NULL)
root = tree->root;
- return treeview_walk_internal(root,
- true,
- (leave_cb != NULL) ? treeview_walk_bwd_cb : NULL,
- (enter_cb != NULL) ? treeview_walk_fwd_cb : NULL,
- &tw);
+ return treeview_walk_internal(tree, root,
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
+ (leave_cb != NULL) ? treeview_walk_bwd_cb : NULL,
+ (enter_cb != NULL) ? treeview_walk_fwd_cb : NULL,
+ &tw);
}
@@ -1154,7 +1503,7 @@ static void treeview_edit_cancel(treeview *tree, bool redraw)
r.y0 = tree->edit.y;
r.x1 = tree->edit.x + tree->edit.w;
r.y1 = tree->edit.y + tree->edit.h;
- cw_invalidate_area(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
}
@@ -1316,8 +1665,9 @@ treeview_delete_node_internal(treeview *tree,
}
/* Delete any children first */
- err = treeview_walk_internal(n, true, treeview_delete_node_walk_cb,
- NULL, &nd);
+ err = treeview_walk_internal(tree, n,
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
+ treeview_delete_node_walk_cb, NULL, &nd);
if (err != NSERROR_OK) {
return err;
}
@@ -1345,6 +1695,8 @@ treeview_delete_node_internal(treeview *tree,
tree->root->height);
}
+ treeview__search_update_display(tree);
+
return NSERROR_OK;
}
@@ -1496,13 +1848,60 @@ treeview_delete_node(treeview *tree,
if (visible && !(flags & TREE_OPTION_SUPPRESS_REDRAW)) {
r.x0 = 0;
r.x1 = REDRAW_MAX;
- cw_invalidate_area(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
return NSERROR_OK;
}
+/**
+ * Helper to create a textarea.
+ *
+ * \param[in] tree The treeview we're creating the textarea for.
+ * \param[in] width The width of the textarea.
+ * \param[in] height The height of the textarea.
+ * \param[in] border The border colour to use.
+ * \param[in] background The background colour to use.
+ * \param[in] foreground The foreground colour to use.
+ * \param[in] text The text style to use for the text area.
+ * \param[in] ta_callback The textarea callback function to give the textarea.
+ * \return the textarea pointer on success, or NULL on failure.
+ */
+static struct textarea *treeview__create_textarea(
+ treeview *tree,
+ int width,
+ int height,
+ colour border,
+ colour background,
+ colour foreground,
+ plot_font_style_t text,
+ textarea_client_callback ta_callback)
+{
+ /* Configure the textarea */
+ textarea_flags ta_flags = TEXTAREA_INTERNAL_CARET;
+ textarea_setup ta_setup = {
+ .text = text,
+ .width = width,
+ .height = height,
+ .pad_top = 0,
+ .pad_left = 2,
+ .pad_right = 2,
+ .pad_bottom = 0,
+ .border_width = 1,
+ .border_col = border,
+ .selected_bg = foreground,
+ .selected_text = background,
+ };
+
+ ta_setup.text.foreground = foreground;
+ ta_setup.text.background = background;
+
+ /* Create text area */
+ return textarea_create(ta_flags, &ta_setup, ta_callback, tree);
+}
+
+
/* Exported interface, documented in treeview.h */
nserror
treeview_create(treeview **tree,
@@ -1582,6 +1981,24 @@ treeview_create(treeview **tree,
(*tree)->edit.textarea = NULL;
(*tree)->edit.node = NULL;
+ if (flags & TREEVIEW_SEARCHABLE) {
+ (*tree)->search.textarea = treeview__create_textarea(
+ *tree, 600, tree_g.line_height,
+ plot_style_even.text.background,
+ plot_style_even.text.background,
+ plot_style_even.text.foreground,
+ plot_style_odd.text,
+ treeview_textarea_search_callback);
+ if ((*tree)->search.textarea == NULL) {
+ treeview_destroy(*tree);
+ return NSERROR_NOMEM;
+ }
+ } else {
+ (*tree)->search.textarea = NULL;
+ }
+ (*tree)->search.active = false;
+ (*tree)->search.search = false;
+
(*tree)->flags = flags;
(*tree)->cw_t = cw_t;
@@ -1601,7 +2018,7 @@ treeview_cw_attach(treeview *tree,
assert(cw != NULL);
if (tree->cw_t != NULL || tree->cw_h != NULL) {
- LOG("Treeview already attached.");
+ NSLOG(netsurf, INFO, "Treeview already attached.");
return NSERROR_UNKNOWN;
}
tree->cw_t = cw_t;
@@ -1617,6 +2034,8 @@ nserror treeview_cw_detach(treeview *tree)
tree->cw_t = NULL;
tree->cw_h = NULL;
+ treeview__search_cancel(tree, true);
+
return NSERROR_OK;
}
@@ -1628,6 +2047,12 @@ nserror treeview_destroy(treeview *tree)
assert(tree != NULL);
+ if (tree->search.textarea != NULL) {
+ tree->search.active = false;
+ tree->search.search = false;
+ textarea_destroy(tree->search.textarea);
+ }
+
/* Destroy nodes */
treeview_delete_node_internal(tree, tree->root, false,
TREE_OPTION_SUPPRESS_RESIZE |
@@ -1666,7 +2091,7 @@ treeview_node_expand_internal(treeview *tree, treeview_node *node)
if (node->flags & TV_NFLAGS_EXPANDED) {
/* What madness is this? */
- LOG("Tried to expand an expanded node.");
+ NSLOG(netsurf, INFO, "Tried to expand an expanded node.");
return NSERROR_OK;
}
@@ -1679,7 +2104,6 @@ treeview_node_expand_internal(treeview *tree, treeview_node *node)
}
do {
- assert((child->flags & TV_NFLAGS_EXPANDED) == false);
if (child->text.width == 0) {
guit->layout->width(&plot_style_odd.text,
child->text.data,
@@ -1724,17 +2148,23 @@ treeview_node_expand_internal(treeview *tree, treeview_node *node)
/* Update the node */
node->flags |= TV_NFLAGS_EXPANDED;
- /* And parent's heights */
- do {
- node->height += additional_height;
- node = node->parent;
- } while (node->parent != NULL);
+ /* And node heights */
+ for (struct treeview_node *n = node;
+ (n != NULL) && (n->flags & TV_NFLAGS_EXPANDED);
+ n = n->parent) {
+ n->height += additional_height;
+ }
- node->height += additional_height;
+ if (tree->search.search &&
+ node->type == TREE_NODE_ENTRY &&
+ node->flags & TV_NFLAGS_MATCHED) {
+ tree->search.height += additional_height;
+ }
/* Inform front end of change in dimensions */
if (additional_height != 0) {
- treeview__cw_update_size(tree, -1, tree->root->height);
+ treeview__cw_update_size(tree, -1,
+ treeview__get_display_height(tree));
}
return NSERROR_OK;
@@ -1753,9 +2183,9 @@ nserror treeview_node_expand(treeview *tree, treeview_node *node)
r.x0 = 0;
r.y0 = treeview_node_y(tree, node);
r.x1 = REDRAW_MAX;
- r.y1 = tree->root->height;
+ r.y1 = treeview__get_display_height(tree);
- cw_invalidate_area(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
return res;
@@ -1766,6 +2196,7 @@ nserror treeview_node_expand(treeview *tree, treeview_node *node)
* context for treeview contraction callback
*/
struct treeview_contract_data {
+ treeview *tree;
bool only_entries;
};
@@ -1794,15 +2225,20 @@ static nserror treeview_node_contract_cb(treeview_node *n, void *ctx, bool *end)
return NSERROR_OK;
}
- n->flags ^= TV_NFLAGS_EXPANDED;
h_reduction = n->height - tree_g.line_height;
assert(h_reduction >= 0);
+ for (struct treeview_node *node = n;
+ (node != NULL) && (node->flags & TV_NFLAGS_EXPANDED);
+ node = node->parent) {
+ node->height -= h_reduction;
+ }
- do {
- n->height -= h_reduction;
- n = n->parent;
- } while (n != NULL);
+ if (data->tree->search.search) {
+ data->tree->search.height -= h_reduction;
+ }
+
+ n->flags ^= TV_NFLAGS_EXPANDED;
return NSERROR_OK;
}
@@ -1824,16 +2260,17 @@ treeview_node_contract_internal(treeview *tree, treeview_node *node)
if ((node->flags & TV_NFLAGS_EXPANDED) == false) {
/* What madness is this? */
- LOG("Tried to contract a contracted node.");
+ NSLOG(netsurf, INFO, "Tried to contract a contracted node.");
return NSERROR_OK;
}
+ data.tree = tree;
data.only_entries = false;
selected = node->flags & TV_NFLAGS_SELECTED;
/* Contract children. */
- treeview_walk_internal(node, false, treeview_node_contract_cb,
- NULL, &data);
+ treeview_walk_internal(tree, node, TREEVIEW_WALK_MODE_LOGICAL_EXPANDED,
+ treeview_node_contract_cb, NULL, &data);
/* Contract node */
treeview_node_contract_cb(node, &data, false);
@@ -1842,7 +2279,7 @@ treeview_node_contract_internal(treeview *tree, treeview_node *node)
node->flags |= TV_NFLAGS_SELECTED;
/* Inform front end of change in dimensions */
- treeview__cw_update_size(tree, -1, tree->root->height);
+ treeview__cw_update_size(tree, -1, treeview__get_display_height(tree));
return NSERROR_OK;
}
@@ -1864,7 +2301,7 @@ nserror treeview_node_contract(treeview *tree, treeview_node *node)
r.x1 = REDRAW_MAX;
r.y1 = tree->root->height;
- cw_invalidate_area(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
return res;
@@ -1887,6 +2324,7 @@ nserror treeview_contract(treeview *tree, bool all)
r.x1 = REDRAW_MAX;
r.y1 = tree->root->height;
+ data.tree = tree;
data.only_entries = !all;
for (n = tree->root->children; n != NULL; n = n->next_sib) {
@@ -1897,8 +2335,9 @@ nserror treeview_contract(treeview *tree, bool all)
selected = n->flags & TV_NFLAGS_SELECTED;
/* Contract children. */
- treeview_walk_internal(n, false,
- treeview_node_contract_cb, NULL, &data);
+ treeview_walk_internal(tree, n,
+ TREEVIEW_WALK_MODE_LOGICAL_EXPANDED,
+ treeview_node_contract_cb, NULL, &data);
/* Contract node */
treeview_node_contract_cb(n, &data, false);
@@ -1911,7 +2350,7 @@ nserror treeview_contract(treeview *tree, bool all)
treeview__cw_update_size(tree, -1, tree->root->height);
/* Redraw */
- cw_invalidate_area(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
return NSERROR_OK;
}
@@ -1972,11 +2411,9 @@ nserror treeview_expand(treeview *tree, bool only_folders)
data.tree = tree;
data.only_folders = only_folders;
- res = treeview_walk_internal(tree->root,
- true,
- NULL,
- treeview_expand_cb,
- &data);
+ res = treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
+ NULL, treeview_expand_cb, &data);
if (res == NSERROR_OK) {
/* expansion succeeded, schedule redraw */
@@ -1985,44 +2422,46 @@ nserror treeview_expand(treeview *tree, bool only_folders)
r.x1 = REDRAW_MAX;
r.y1 = tree->root->height;
- cw_invalidate_area(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
return res;
}
-/* Exported interface, documented in treeview.h */
-void
-treeview_redraw(treeview *tree,
+/**
+ * Draw a treeview normally, in tree mode.
+ *
+ * \param[in] tree The treeview we're rendering.
+ * \param[in] x X coordinate we're rendering the treeview at.
+ * \param[in] y Y coordinate we're rendering the treeview at.
+ * \param[in,out] render_y Current vertical position in tree, updated on exit.
+ * \param[in] r Clip rectangle.
+ * \param[in] data Redraw data for rendering contents.
+ * \param[in] ctx Current render context.
+ */
+static void treeview_redraw_tree(
+ treeview *tree,
const int x,
const int y,
- struct rect *clip,
+ int *render_y_in_out,
+ struct rect *r,
+ struct content_redraw_data *data,
const struct redraw_context *ctx)
{
- struct redraw_context new_ctx = *ctx;
- treeview_node *node, *root, *next;
- struct treeview_node_entry *entry;
struct treeview_node_style *style = &plot_style_odd;
- struct content_redraw_data data;
- struct rect r;
- struct rect rect;
- uint32_t count = 0;
- int render_y = y;
- int inset;
- int x0;
- int baseline = (tree_g.line_height * 3 + 2) / 4;
enum treeview_resource_id res = TREE_RES_CONTENT;
- plot_style_t *bg_style;
- plot_font_style_t *text_style;
+ int baseline = (tree_g.line_height * 3 + 2) / 4;
plot_font_style_t *infotext_style;
- struct bitmap *furniture;
- int height;
+ treeview_node *root = tree->root;
+ treeview_node *node = tree->root;
+ int render_y = *render_y_in_out;
+ plot_font_style_t *text_style;
+ plot_style_t *bg_style;
int sel_min, sel_max;
- bool invert_selection;
-
- assert(tree != NULL);
- assert(tree->root != NULL);
- assert(tree->root->flags & TV_NFLAGS_EXPANDED);
+ uint32_t count = 0;
+ struct rect rect;
+ int inset;
+ int x0;
if (tree->drag.start.y > tree->drag.prev.y) {
sel_min = tree->drag.prev.y;
@@ -2032,30 +2471,14 @@ treeview_redraw(treeview *tree,
sel_max = tree->drag.prev.y;
}
- /* Start knockout rendering if it's available for this plotter */
- if (ctx->plot->option_knockout) {
- knockout_plot_start(ctx, &new_ctx);
- }
-
- /* Set up clip rectangle */
- r.x0 = clip->x0 + x;
- r.y0 = clip->y0 + y;
- r.x1 = clip->x1 + x;
- r.y1 = clip->y1 + y;
- new_ctx.plot->clip(&new_ctx, &r);
-
- /* Draw the tree */
- node = root = tree->root;
-
- /* Setup common content redraw data */
- data.width = tree_g.icon_size;
- data.height = tree_g.icon_size;
- data.scale = 1;
- data.repeat_x = false;
- data.repeat_y = false;
-
while (node != NULL) {
+ struct treeview_node_entry *entry;
+ struct bitmap *furniture;
+ bool invert_selection;
+ treeview_node *next;
+ int height;
int i;
+
next = (node->flags & TV_NFLAGS_EXPANDED) ?
node->children : NULL;
@@ -2088,7 +2511,7 @@ treeview_redraw(treeview *tree,
height = (node->type == TREE_NODE_ENTRY) ? node->height :
tree_g.line_height;
- if ((render_y + height) < r.y0) {
+ if ((render_y + height) < r->y0) {
/* This node's line is above clip region */
render_y += height;
continue;
@@ -2121,21 +2544,243 @@ treeview_redraw(treeview *tree,
}
/* Render background */
- rect.x0 = r.x0;
+ rect.x0 = r->x0;
rect.y0 = render_y;
- rect.x1 = r.x1;
+ rect.x1 = r->x1;
+ rect.y1 = render_y + height;
+ ctx->plot->rectangle(ctx, bg_style, &rect);
+
+ /* Render toggle */
+ ctx->plot->bitmap(ctx,
+ furniture,
+ inset,
+ render_y + tree_g.line_height / 4,
+ style->furn[TREE_FURN_EXPAND].size,
+ style->furn[TREE_FURN_EXPAND].size,
+ bg_style->fill_colour,
+ BITMAPF_NONE);
+
+ /* Render icon */
+ if (node->type == TREE_NODE_ENTRY) {
+ res = TREE_RES_CONTENT;
+ } else if (node->flags & TV_NFLAGS_SPECIAL) {
+ res = TREE_RES_FOLDER_SPECIAL;
+ } else {
+ res = TREE_RES_FOLDER;
+ }
+
+ if (treeview_res[res].ready) {
+ /* Icon resource is available */
+ data->x = inset + tree_g.step_width;
+ data->y = render_y + ((tree_g.line_height -
+ treeview_res[res].height + 1) / 2);
+ data->background_colour = bg_style->fill_colour;
+
+ content_redraw(treeview_res[res].c, data, r, ctx);
+ }
+
+ /* Render text */
+ x0 = inset + tree_g.step_width + tree_g.icon_step;
+ ctx->plot->text(ctx,
+ text_style,
+ x0, render_y + baseline,
+ node->text.data,
+ node->text.len);
+
+ /* Rendered the node */
+ render_y += tree_g.line_height;
+ if (render_y > r->y1) {
+ /* Passed the bottom of what's in the clip region.
+ * Done. */
+ break;
+ }
+
+
+ if (node->type != TREE_NODE_ENTRY ||
+ !(node->flags & TV_NFLAGS_EXPANDED))
+ /* Done everything for this node */
+ continue;
+
+ /* Render expanded entry fields */
+ entry = (struct treeview_node_entry *)node;
+ for (i = 0; i < tree->n_fields - 1; i++) {
+ struct treeview_field *ef = &(tree->fields[i + 1]);
+
+ if (ef->flags & TREE_FLAG_SHOW_NAME) {
+ int max_width = tree->field_width;
+
+ ctx->plot->text(ctx,
+ infotext_style,
+ x0 + max_width - ef->value.width - tree_g.step_width,
+ render_y + baseline,
+ ef->value.data,
+ ef->value.len);
+
+ ctx->plot->text(ctx,
+ infotext_style,
+ x0 + max_width,
+ render_y + baseline,
+ entry->fields[i].value.data,
+ entry->fields[i].value.len);
+ } else {
+ ctx->plot->text(ctx,
+ infotext_style,
+ x0, render_y + baseline,
+ entry->fields[i].value.data,
+ entry->fields[i].value.len);
+ }
+
+ /* Rendered the expanded entry field */
+ render_y += tree_g.line_height;
+ }
+
+ /* Finished rendering expanded entry */
+
+ if (render_y > r->y1) {
+ /* Passed the bottom of what's in the clip region.
+ * Done. */
+ break;
+ }
+ }
+
+ *render_y_in_out = render_y;
+}
+
+
+/**
+ * Draw a treeview normally, in tree mode.
+ *
+ * \param[in] tree The treeview we're rendering.
+ * \param[in] x X coordinate we're rendering the treeview at.
+ * \param[in] y Y coordinate we're rendering the treeview at.
+ * \param[in,out] render_y Current vertical position in tree, updated on exit.
+ * \param[in] r Clip rectangle.
+ * \param[in] data Redraw data for rendering contents.
+ * \param[in] ctx Current render context.
+ */
+static void treeview_redraw_search(
+ treeview *tree,
+ const int x,
+ const int y,
+ int *render_y_in_out,
+ struct rect *r,
+ struct content_redraw_data *data,
+ const struct redraw_context *ctx)
+{
+ struct treeview_node_style *style = &plot_style_odd;
+ enum treeview_resource_id res = TREE_RES_CONTENT;
+ int baseline = (tree_g.line_height * 3 + 2) / 4;
+ plot_font_style_t *infotext_style;
+ treeview_node *root = tree->root;
+ treeview_node *node = tree->root;
+ int render_y = *render_y_in_out;
+ plot_font_style_t *text_style;
+ plot_style_t *bg_style;
+ int sel_min, sel_max;
+ uint32_t count = 0;
+ struct rect rect;
+ int inset;
+ int x0;
+
+ if (tree->drag.start.y > tree->drag.prev.y) {
+ sel_min = tree->drag.prev.y;
+ sel_max = tree->drag.start.y;
+ } else {
+ sel_min = tree->drag.start.y;
+ sel_max = tree->drag.prev.y;
+ }
+
+ while (node != NULL) {
+ struct treeview_node_entry *entry;
+ struct bitmap *furniture;
+ bool invert_selection;
+ treeview_node *next;
+ int height;
+ int i;
+
+ next = node->children;
+
+ if (next != NULL) {
+ /* down to children */
+ node = next;
+ } else {
+ /* No children. As long as we're not at the root,
+ * go to next sibling if present, or nearest ancestor
+ * with a next sibling. */
+
+ while (node != root &&
+ node->next_sib == NULL) {
+ node = node->parent;
+ }
+
+ if (node == root)
+ break;
+
+ node = node->next_sib;
+ }
+
+ assert(node != NULL);
+ assert(node != root);
+ assert(node->type == TREE_NODE_FOLDER ||
+ node->type == TREE_NODE_ENTRY);
+
+ if (node->type == TREE_NODE_FOLDER ||
+ !(node->flags & TV_NFLAGS_MATCHED)) {
+ continue;
+ }
+
+ count++;
+ inset = x + tree_g.window_padding;
+ height = node->height;
+
+ if ((render_y + height) < r->y0) {
+ /* This node's line is above clip region */
+ render_y += height;
+ continue;
+ }
+
+ style = (count & 0x1) ? &plot_style_odd : &plot_style_even;
+ if (tree->drag.type == TV_DRAG_SELECTION &&
+ (render_y + height >= sel_min &&
+ render_y < sel_max)) {
+ invert_selection = true;
+ } else {
+ invert_selection = false;
+ }
+ if ((node->flags & TV_NFLAGS_SELECTED && !invert_selection) ||
+ (!(node->flags & TV_NFLAGS_SELECTED) &&
+ invert_selection)) {
+ bg_style = &style->sbg;
+ text_style = &style->stext;
+ infotext_style = &style->sitext;
+ furniture = (node->flags & TV_NFLAGS_EXPANDED) ?
+ style->furn[TREE_FURN_CONTRACT].sel :
+ style->furn[TREE_FURN_EXPAND].sel;
+ } else {
+ bg_style = &style->bg;
+ text_style = &style->text;
+ infotext_style = &style->itext;
+ furniture = (node->flags & TV_NFLAGS_EXPANDED) ?
+ style->furn[TREE_FURN_CONTRACT].bmp :
+ style->furn[TREE_FURN_EXPAND].bmp;
+ }
+
+ /* Render background */
+ rect.x0 = r->x0;
+ rect.y0 = render_y;
+ rect.x1 = r->x1;
rect.y1 = render_y + height;
- new_ctx.plot->rectangle(&new_ctx, bg_style, &rect);
+ ctx->plot->rectangle(ctx, bg_style, &rect);
/* Render toggle */
- new_ctx.plot->bitmap(&new_ctx,
- furniture,
- inset,
- render_y + tree_g.line_height / 4,
- style->furn[TREE_FURN_EXPAND].size,
- style->furn[TREE_FURN_EXPAND].size,
- bg_style->fill_colour,
- BITMAPF_NONE);
+ ctx->plot->bitmap(ctx,
+ furniture,
+ inset,
+ render_y + tree_g.line_height / 4,
+ style->furn[TREE_FURN_EXPAND].size,
+ style->furn[TREE_FURN_EXPAND].size,
+ bg_style->fill_colour,
+ BITMAPF_NONE);
/* Render icon */
if (node->type == TREE_NODE_ENTRY) {
@@ -2148,26 +2793,25 @@ treeview_redraw(treeview *tree,
if (treeview_res[res].ready) {
/* Icon resource is available */
- data.x = inset + tree_g.step_width;
- data.y = render_y + ((tree_g.line_height -
+ data->x = inset + tree_g.step_width;
+ data->y = render_y + ((tree_g.line_height -
treeview_res[res].height + 1) / 2);
- data.background_colour = bg_style->fill_colour;
+ data->background_colour = bg_style->fill_colour;
- content_redraw(treeview_res[res].c,
- &data, &r, &new_ctx);
+ content_redraw(treeview_res[res].c, data, r, ctx);
}
/* Render text */
x0 = inset + tree_g.step_width + tree_g.icon_step;
- new_ctx.plot->text(&new_ctx,
- text_style,
- x0, render_y + baseline,
- node->text.data,
- node->text.len);
+ ctx->plot->text(ctx,
+ text_style,
+ x0, render_y + baseline,
+ node->text.data,
+ node->text.len);
/* Rendered the node */
render_y += tree_g.line_height;
- if (render_y > r.y1) {
+ if (render_y > r->y1) {
/* Passed the bottom of what's in the clip region.
* Done. */
break;
@@ -2187,25 +2831,25 @@ treeview_redraw(treeview *tree,
if (ef->flags & TREE_FLAG_SHOW_NAME) {
int max_width = tree->field_width;
- new_ctx.plot->text(&new_ctx,
- infotext_style,
- x0 + max_width - ef->value.width - tree_g.step_width,
- render_y + baseline,
- ef->value.data,
- ef->value.len);
-
- new_ctx.plot->text(&new_ctx,
- infotext_style,
- x0 + max_width,
- render_y + baseline,
- entry->fields[i].value.data,
- entry->fields[i].value.len);
+ ctx->plot->text(ctx,
+ infotext_style,
+ x0 + max_width - ef->value.width - tree_g.step_width,
+ render_y + baseline,
+ ef->value.data,
+ ef->value.len);
+
+ ctx->plot->text(ctx,
+ infotext_style,
+ x0 + max_width,
+ render_y + baseline,
+ entry->fields[i].value.data,
+ entry->fields[i].value.len);
} else {
- new_ctx.plot->text(&new_ctx,
- infotext_style,
- x0, render_y + baseline,
- entry->fields[i].value.data,
- entry->fields[i].value.len);
+ ctx->plot->text(ctx,
+ infotext_style,
+ x0, render_y + baseline,
+ entry->fields[i].value.data,
+ entry->fields[i].value.len);
}
/* Rendered the expanded entry field */
@@ -2214,13 +2858,97 @@ treeview_redraw(treeview *tree,
/* Finished rendering expanded entry */
- if (render_y > r.y1) {
+ if (render_y > r->y1) {
/* Passed the bottom of what's in the clip region.
* Done. */
break;
}
}
+ *render_y_in_out = render_y;
+}
+
+
+/* Exported interface, documented in treeview.h */
+void
+treeview_redraw(treeview *tree,
+ const int x,
+ const int y,
+ struct rect *clip,
+ const struct redraw_context *ctx)
+{
+ struct redraw_context new_ctx = *ctx;
+ struct content_redraw_data data;
+ struct rect r;
+ struct rect rect;
+ int render_y = y;
+
+ assert(tree != NULL);
+ assert(tree->root != NULL);
+ assert(tree->root->flags & TV_NFLAGS_EXPANDED);
+
+ /* Start knockout rendering if it's available for this plotter */
+ if (ctx->plot->option_knockout) {
+ knockout_plot_start(ctx, &new_ctx);
+ }
+
+ /* Set up clip rectangle */
+ r.x0 = clip->x0 + x;
+ r.y0 = clip->y0 + y;
+ r.x1 = clip->x1 + x;
+ r.y1 = clip->y1 + y;
+ new_ctx.plot->clip(&new_ctx, &r);
+
+ /* Setup common content redraw data */
+ data.width = tree_g.icon_size;
+ data.height = tree_g.icon_size;
+ data.scale = 1;
+ data.repeat_x = false;
+ data.repeat_y = false;
+
+ if (tree->flags & TREEVIEW_SEARCHABLE) {
+ if (render_y < r.y1) {
+ enum treeview_resource_id icon = TREE_RES_SEARCH;
+
+ /* Fill the blank area at the bottom */
+ rect.x0 = r.x0;
+ rect.y0 = render_y;
+ rect.x1 = r.x1;
+ rect.y1 = render_y + tree_g.line_height;
+ new_ctx.plot->rectangle(&new_ctx, &plot_style_even.bg,
+ &rect);
+
+ if (treeview_res[icon].ready) {
+ /* Icon resource is available */
+ data.x = tree_g.window_padding;
+ data.y = render_y + ((tree_g.line_height -
+ treeview_res[icon].height + 1) /
+ 2);
+ data.background_colour = plot_style_even.bg.
+ fill_colour;
+
+ content_redraw(treeview_res[icon].c,
+ &data, &r, &new_ctx);
+ }
+
+ textarea_redraw(tree->search.textarea,
+ x + tree_g.window_padding +
+ tree_g.icon_step, y,
+ plot_style_even.bg.fill_colour, 1.0,
+ &r, &new_ctx);
+ }
+ render_y += tree_g.line_height;
+ }
+
+ /* Render the treeview data */
+ if (tree->search.search == true) {
+ treeview_redraw_search(tree, x, y,
+ &render_y, &r, &data, &new_ctx);
+ } else {
+ treeview_redraw_tree(tree, x, y,
+ &render_y, &r, &data, &new_ctx);
+ }
+
if (render_y < r.y1) {
/* Fill the blank area at the bottom */
rect.x0 = r.x0;
@@ -2474,8 +3202,9 @@ bool treeview_has_selection(treeview *tree)
sw.purpose = TREEVIEW_WALK_HAS_SELECTION;
sw.data.has_selection = false;
- treeview_walk_internal(tree->root, false, NULL,
- treeview_node_selection_walk_cb, &sw);
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
+ treeview_node_selection_walk_cb, &sw);
return sw.data.has_selection;
}
@@ -2494,8 +3223,9 @@ static treeview_node * treeview_get_first_selected(treeview *tree)
sw.purpose = TREEVIEW_WALK_GET_FIRST_SELECTED;
sw.data.first.n = NULL;
- treeview_walk_internal(tree->root, false, NULL,
- treeview_node_selection_walk_cb, &sw);
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
+ treeview_node_selection_walk_cb, &sw);
return sw.data.first.n;
}
@@ -2540,10 +3270,12 @@ static bool treeview_clear_selection(treeview *tree, struct rect *rect)
sw.purpose = TREEVIEW_WALK_CLEAR_SELECTION;
sw.data.redraw.required = false;
sw.data.redraw.rect = rect;
- sw.current_y = 0;
+ sw.current_y = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
- treeview_walk_internal(tree->root, false, NULL,
- treeview_node_selection_walk_cb, &sw);
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
+ treeview_node_selection_walk_cb, &sw);
return sw.data.redraw.required;
}
@@ -2568,10 +3300,12 @@ static bool treeview_select_all(treeview *tree, struct rect *rect)
sw.purpose = TREEVIEW_WALK_SELECT_ALL;
sw.data.redraw.required = false;
sw.data.redraw.rect = rect;
- sw.current_y = 0;
+ sw.current_y = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
- treeview_walk_internal(tree->root, false, NULL,
- treeview_node_selection_walk_cb, &sw);
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
+ treeview_node_selection_walk_cb, &sw);
return sw.data.redraw.required;
}
@@ -2587,7 +3321,8 @@ static void treeview_commit_selection_drag(treeview *tree)
struct treeview_selection_walk_data sw;
sw.purpose = TREEVIEW_WALK_COMMIT_SELECT_DRAG;
- sw.current_y = 0;
+ sw.current_y = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
if (tree->drag.start.y > tree->drag.prev.y) {
sw.data.drag.sel_min = tree->drag.prev.y;
@@ -2597,8 +3332,9 @@ static void treeview_commit_selection_drag(treeview *tree)
sw.data.drag.sel_max = tree->drag.prev.y;
}
- treeview_walk_internal(tree->root, false, NULL,
- treeview_node_selection_walk_cb, &sw);
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
+ treeview_node_selection_walk_cb, &sw);
}
@@ -2615,8 +3351,9 @@ static void treeview_move_yank_selection(treeview *tree)
sw.data.yank.prev = NULL;
sw.tree = tree;
- treeview_walk_internal(tree->root, false, NULL,
- treeview_node_selection_walk_cb, &sw);
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
+ treeview_node_selection_walk_cb, &sw);
}
@@ -2635,8 +3372,9 @@ static void treeview_copy_selection(treeview *tree)
sw.data.copy.len = 0;
sw.tree = tree;
- err = treeview_walk_internal(tree->root, false, NULL,
- treeview_node_selection_walk_cb, &sw);
+ err = treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
+ treeview_node_selection_walk_cb, &sw);
if (err != NSERROR_OK) {
return;
}
@@ -2674,8 +3412,9 @@ static bool treeview_delete_selection(treeview *tree, struct rect *rect)
sw.current_y = 0;
sw.tree = tree;
- treeview_walk_internal(tree->root, false, NULL,
- treeview_node_selection_walk_cb, &sw);
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
+ treeview_node_selection_walk_cb, &sw);
return sw.data.redraw.required;
}
@@ -2706,8 +3445,9 @@ static bool treeview_propagate_selection(treeview *tree, struct rect *rect)
sw.current_y = 0;
sw.tree = tree;
- treeview_walk_internal(tree->root, false, NULL,
- treeview_node_selection_walk_cb, &sw);
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
+ treeview_node_selection_walk_cb, &sw);
return sw.data.redraw.required;
}
@@ -2771,7 +3511,7 @@ static nserror treeview_move_selection(treeview *tree, struct rect *rect)
break;
default:
- LOG("Bad drop target for move.");
+ NSLOG(netsurf, INFO, "Bad drop target for move.");
return NSERROR_BAD_PARAMETER;
}
@@ -2797,7 +3537,7 @@ static nserror treeview_move_selection(treeview *tree, struct rect *rect)
node->flags &= ~TV_NFLAGS_SELECTED;
}
- treeview_insert_node(node, relation, relationship);
+ treeview_insert_node(tree, node, relation, relationship);
relation = node;
relationship = TREE_REL_NEXT_SIBLING;
@@ -2896,9 +3636,10 @@ static nserror treeview_launch_selection(treeview *tree)
lw.selected_depth = 0;
lw.tree = tree;
- return treeview_walk_internal(tree->root, true,
- treeview_node_launch_walk_bwd_cb,
- treeview_node_launch_walk_fwd_cb, &lw);
+ return treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_LOGICAL_COMPLETE,
+ treeview_node_launch_walk_bwd_cb,
+ treeview_node_launch_walk_fwd_cb, &lw);
}
@@ -3033,18 +3774,25 @@ treeview_keyboard_navigation(treeview *tree, uint32_t key, struct rect *rect)
/* Fill out the nav. state struct, by examining the current selection
* state */
- treeview_walk_internal(tree->root, false, NULL,
- treeview_node_nav_cb, &ns);
- if (ns.next == NULL)
- ns.next = tree->root->children;
- if (ns.prev == NULL)
- ns.prev = ns.last;
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
+ treeview_node_nav_cb, &ns);
+
+ if (tree->search.search == false) {
+ if (ns.next == NULL)
+ ns.next = tree->root->children;
+ if (ns.prev == NULL)
+ ns.prev = ns.last;
+ }
/* Clear any existing selection */
redraw = treeview_clear_selection(tree, rect);
switch (key) {
case NS_KEY_LEFT:
+ if (tree->search.search == true) {
+ break;
+ }
if (ns.curr != NULL &&
ns.curr->parent != NULL &&
ns.curr->parent->type != TREE_NODE_ROOT) {
@@ -3123,7 +3871,7 @@ bool treeview_keypress(treeview *tree, uint32_t key)
assert(tree != NULL);
- /* Pass to textarea, if editing in progress */
+ /* Pass to any textarea, if editing in progress */
if (tree->edit.textarea != NULL) {
switch (key) {
case NS_KEY_ESCAPE:
@@ -3136,6 +3884,17 @@ bool treeview_keypress(treeview *tree, uint32_t key)
default:
return textarea_keypress(tree->edit.textarea, key);
}
+ } else if (tree->search.active == true) {
+ switch (key) {
+ case NS_KEY_ESCAPE:
+ treeview__search_cancel(tree, false);
+ return true;
+ case NS_KEY_NL:
+ case NS_KEY_CR:
+ return true;
+ default:
+ return textarea_keypress(tree->search.textarea, key);
+ }
}
/* Keypress to be handled by treeview */
@@ -3182,7 +3941,7 @@ bool treeview_keypress(treeview *tree, uint32_t key)
}
if (redraw) {
- cw_invalidate_area(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
return true;
@@ -3358,7 +4117,7 @@ static void treeview_textarea_callback(void *data, struct textarea_msg *msg)
r->y1 += tree->edit.y;
/* Redraw the textarea */
- cw_invalidate_area(tree, r);
+ treeview__cw_invalidate_area(tree, r);
break;
default:
@@ -3392,8 +4151,6 @@ treeview_edit_node_at_point(treeview *tree,
int field_y = node_y;
int field_x;
int width, height;
- textarea_setup ta_setup;
- textarea_flags ta_flags;
bool success;
/* If the main field is editable, make field_data point to it */
@@ -3435,31 +4192,15 @@ treeview_edit_node_at_point(treeview *tree,
/* Get window width/height */
treeview__cw_get_window_dimensions(tree, &width, &height);
- /* Anow textarea width/height */
+ /* Calculate textarea width/height */
field_x = n->inset + tree_g.step_width + tree_g.icon_step - 3;
width -= field_x;
height = tree_g.line_height;
- /* Configure the textarea */
- ta_flags = TEXTAREA_INTERNAL_CARET;
-
- ta_setup.width = width;
- ta_setup.height = height;
- ta_setup.pad_top = 0;
- ta_setup.pad_right = 2;
- ta_setup.pad_bottom = 0;
- ta_setup.pad_left = 2;
- ta_setup.border_width = 1;
- ta_setup.border_col = 0x000000;
- ta_setup.selected_text = 0xffffff;
- ta_setup.selected_bg = 0x000000;
- ta_setup.text = plot_style_odd.text;
- ta_setup.text.foreground = 0x000000;
- ta_setup.text.background = 0xffffff;
-
/* Create text area */
- tree->edit.textarea = textarea_create(ta_flags, &ta_setup,
- treeview_textarea_callback, tree);
+ tree->edit.textarea = treeview__create_textarea(tree, width, height,
+ 0x000000, 0xffffff, 0x000000, plot_style_odd.text,
+ treeview_textarea_callback);
if (tree->edit.textarea == NULL) {
return false;
}
@@ -3536,7 +4277,7 @@ void treeview_edit_selection(treeview *tree)
rect.y0 = y;
rect.x1 = REDRAW_MAX;
rect.y1 = y + tree_g.line_height;
- cw_invalidate_area(tree, &rect);
+ treeview__cw_invalidate_area(tree, &rect);
}
@@ -3593,14 +4334,18 @@ treeview_node_mouse_action_cb(treeview_node *node,
/* Find where the mouse is */
if (ma->y <= ma->current_y + tree_g.line_height) {
- if (ma->x >= node->inset - 1 &&
- ma->x < node->inset + tree_g.step_width) {
+ int inset = node->inset;
+ if (ma->tree->search.search == true) {
+ inset = tree_g.window_padding;
+ }
+ if (ma->x >= inset - 1 &&
+ ma->x < inset + tree_g.step_width) {
/* Over expansion toggle */
part = TV_NODE_PART_TOGGLE;
- } else if (ma->x >= node->inset + tree_g.step_width &&
- ma->x < node->inset + tree_g.step_width +
- tree_g.icon_step + node->text.width) {
+ } else if (ma->x >= inset + tree_g.step_width &&
+ ma->x < inset + tree_g.step_width +
+ tree_g.icon_step + node->text.width) {
/* On node */
part = TV_NODE_PART_ON_NODE;
}
@@ -3674,7 +4419,8 @@ treeview_node_mouse_action_cb(treeview_node *node,
treeview__cw_drag_status(ma->tree,
CORE_WINDOW_DRAG_SELECTION);
- } else if (!(ma->tree->flags & TREEVIEW_NO_MOVES) &&
+ } else if (ma->tree->search.search == false &&
+ !(ma->tree->flags & TREEVIEW_NO_MOVES) &&
ma->mouse & BROWSER_MOUSE_DRAG_1 &&
(ma->tree->drag.selected == true ||
ma->tree->drag.part == TV_NODE_PART_ON_NODE)) {
@@ -3714,7 +4460,7 @@ treeview_node_mouse_action_cb(treeview_node *node,
ma->tree->drag.prev.node_y = ma->current_y;
ma->tree->drag.prev.node_h = height;
}
- break;
+ break;
case TV_DRAG_MOVE:
redraw |= treeview_set_move_indicator(ma->tree, redraw,
@@ -3816,7 +4562,7 @@ treeview_node_mouse_action_cb(treeview_node *node,
}
if (redraw) {
- cw_invalidate_area(ma->tree, &r);
+ treeview__cw_invalidate_area(ma->tree, &r);
}
*end = true; /* Reached line with click; stop walking tree */
@@ -3830,15 +4576,45 @@ treeview_mouse_action(treeview *tree, browser_mouse_state mouse, int x, int y)
{
struct rect r;
bool redraw = false;
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
assert(tree != NULL);
assert(tree->root != NULL);
+ /* Not interested in whether mouse leaves window. */
+ if (mouse == BROWSER_MOUSE_LEAVE) {
+ return;
+ }
+
/* Handle mouse drag captured by textarea */
if (tree->drag.type == TV_DRAG_TEXTAREA) {
textarea_mouse_action(tree->edit.textarea, mouse,
x - tree->edit.x, y - tree->edit.y);
return;
+ } else if (tree->drag.type == TV_DRAG_SEARCH ||
+ (y < search_height &&
+ tree->drag.type == TV_DRAG_NONE)) {
+ if (tree->search.active == false) {
+ tree->search.active = true;
+ if (treeview_clear_selection(tree, &r)) {
+ treeview__cw_invalidate_area(tree, &r);
+ }
+ }
+ textarea_mouse_action(tree->search.textarea, mouse,
+ x - tree_g.window_padding - tree_g.icon_size,
+ y);
+ return;
+ } else if (mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2) &&
+ tree->search.active == true) {
+
+ tree->search.active = false;
+ textarea_set_caret(tree->search.textarea, -1);
+ r.x0 = 0;
+ r.y0 = 0;
+ r.x1 = REDRAW_MAX;
+ r.y1 = tree_g.line_height;
+ treeview__cw_invalidate_area(tree, &r);
}
/* Handle textarea related mouse action */
@@ -3878,7 +4654,7 @@ treeview_mouse_action(treeview *tree, browser_mouse_state mouse, int x, int y)
tree->move.target_pos = TV_TARGET_NONE;
treeview__cw_drag_status(tree, CORE_WINDOW_DRAG_NONE);
- cw_invalidate_area(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
return;
default:
/* No drag to end */
@@ -3886,7 +4662,7 @@ treeview_mouse_action(treeview *tree, browser_mouse_state mouse, int x, int y)
}
}
- if (y > tree->root->height) {
+ if (y > treeview__get_display_height(tree) + search_height) {
/* Below tree */
r.x0 = 0;
@@ -3953,7 +4729,7 @@ treeview_mouse_action(treeview *tree, browser_mouse_state mouse, int x, int y)
}
if (redraw) {
- cw_invalidate_area(tree, &r);
+ treeview__cw_invalidate_area(tree, &r);
}
} else {
@@ -3964,10 +4740,11 @@ treeview_mouse_action(treeview *tree, browser_mouse_state mouse, int x, int y)
ma.mouse = mouse;
ma.x = x;
ma.y = y;
- ma.current_y = 0;
+ ma.current_y = search_height;
- treeview_walk_internal(tree->root, false, NULL,
- treeview_node_mouse_action_cb, &ma);
+ treeview_walk_internal(tree, tree->root,
+ TREEVIEW_WALK_MODE_DISPLAY, NULL,
+ treeview_node_mouse_action_cb, &ma);
}
}
@@ -3975,12 +4752,16 @@ treeview_mouse_action(treeview *tree, browser_mouse_state mouse, int x, int y)
/* Exported interface, documented in treeview.h */
int treeview_get_height(treeview *tree)
{
+ int search_height = (tree->flags & TREEVIEW_SEARCHABLE) ?
+ tree_g.line_height : 0;
+ int height = treeview__get_display_height(tree);
+
assert(tree != NULL);
assert(tree->root != NULL);
- treeview__cw_update_size(tree, -1, tree->root->height);
+ treeview__cw_update_size(tree, -1, height);
- return tree->root->height;
+ return height + search_height;
}
@@ -4403,7 +5184,7 @@ nserror treeview_init(void)
return NSERROR_OK;
}
- LOG("Initialising treeview module");
+ NSLOG(netsurf, INFO, "Initialising treeview module");
font_pt_size = nsoption_int(treeview_font_size);
if (font_pt_size <= 0) {
@@ -4434,7 +5215,7 @@ nserror treeview_init(void)
tree_g.initialised++;
- LOG("Initialised treeview module");
+ NSLOG(netsurf, INFO, "Initialised treeview module");
return NSERROR_OK;
}
@@ -4450,11 +5231,12 @@ nserror treeview_fini(void)
return NSERROR_OK;
} else if (tree_g.initialised == 0) {
- LOG("Warning: tried to finalise uninitialised treeview module");
+ NSLOG(netsurf, INFO,
+ "Warning: tried to finalise uninitialised treeview module");
return NSERROR_OK;
}
- LOG("Finalising treeview module");
+ NSLOG(netsurf, INFO, "Finalising treeview module");
for (i = 0; i < TREE_RES_LAST; i++) {
hlcache_handle_release(treeview_res[i].c);
@@ -4471,7 +5253,7 @@ nserror treeview_fini(void)
tree_g.initialised--;
- LOG("Finalised treeview module");
+ NSLOG(netsurf, INFO, "Finalised treeview module");
return NSERROR_OK;
}
diff --git a/desktop/treeview.h b/desktop/treeview.h
index 45469b77f..a8cf29ac5 100644
--- a/desktop/treeview.h
+++ b/desktop/treeview.h
@@ -76,7 +76,8 @@ typedef enum {
TREEVIEW_NO_MOVES = (1 << 0), /**< No node drags */
TREEVIEW_NO_DELETES = (1 << 1), /**< No node deletes */
TREEVIEW_READ_ONLY = TREEVIEW_NO_MOVES | TREEVIEW_NO_DELETES,
- TREEVIEW_DEL_EMPTY_DIRS = (1 << 2) /**< Delete dirs on empty */
+ TREEVIEW_DEL_EMPTY_DIRS = (1 << 2), /**< Delete dirs on empty */
+ TREEVIEW_SEARCHABLE = (1 << 3), /**< Treeview has search bar */
} treeview_flags;
/**
@@ -113,11 +114,12 @@ struct treeview_node_msg {
* treeview field flags
*/
enum treeview_field_flags {
- TREE_FLAG_NONE = 0, /**< No flags set */
- TREE_FLAG_ALLOW_EDIT = (1 << 0), /**< Whether allow edit field */
- TREE_FLAG_DEFAULT = (1 << 1), /**< Whether field is default */
- TREE_FLAG_SHOW_NAME = (1 << 2), /**< Whether field name shown */
- TREE_FLAG_COPY_TEXT = (1 << 3) /**< Whether to copy to clipb */
+ TREE_FLAG_NONE = 0, /**< No flags set */
+ TREE_FLAG_ALLOW_EDIT = (1 << 0), /**< Whether allow edit field */
+ TREE_FLAG_DEFAULT = (1 << 1), /**< Whether field is default */
+ TREE_FLAG_SHOW_NAME = (1 << 2), /**< Whether field name shown */
+ TREE_FLAG_COPY_TEXT = (1 << 3), /**< Whether to copy to clipb */
+ TREE_FLAG_SEARCHABLE = (1 << 4), /**< Whether field is searchable */
};
diff --git a/desktop/version.c b/desktop/version.c
index 6126c5b99..bbe759f2e 100644
--- a/desktop/version.c
+++ b/desktop/version.c
@@ -20,11 +20,11 @@
#include "desktop/version.h"
-const char * const netsurf_version = "3.7 (Dev"
+const char * const netsurf_version = "3.8 (Dev"
#if defined(CI_BUILD)
" CI #" CI_BUILD
#endif
")"
;
const int netsurf_version_major = 3;
-const int netsurf_version_minor = 7;
+const int netsurf_version_minor = 8;