diff options
author | Sven Weidauer <sven@5sw.de> | 2017-12-23 10:55:59 +0100 |
---|---|---|
committer | Sven Weidauer <sven@5sw.de> | 2017-12-23 10:55:59 +0100 |
commit | cb452810b98273f1bf3275321386c8393d5c5134 (patch) | |
tree | af32263647bad0f8573c93fd9e426aeec2a57057 /desktop | |
parent | d0549e7a5b14959097a1e8696dce1b1f40c6ba54 (diff) | |
parent | 3c0ff81be45968e1c9d9b989243c975dfeab4cb0 (diff) | |
download | netsurf-cb452810b98273f1bf3275321386c8393d5c5134.tar.gz netsurf-cb452810b98273f1bf3275321386c8393d5c5134.tar.bz2 |
Merge remote-tracking branch 'origin/master' into svenw/cocoa
Diffstat (limited to 'desktop')
-rw-r--r-- | desktop/browser.c | 113 | ||||
-rw-r--r-- | desktop/browser_history.c | 255 | ||||
-rw-r--r-- | desktop/browser_history.h | 26 | ||||
-rw-r--r-- | desktop/browser_private.h | 17 | ||||
-rw-r--r-- | desktop/cookie_manager.c | 19 | ||||
-rw-r--r-- | desktop/font_haru.c | 24 | ||||
-rw-r--r-- | desktop/frames.c | 6 | ||||
-rw-r--r-- | desktop/global_history.c | 22 | ||||
-rw-r--r-- | desktop/hotlist.c | 35 | ||||
-rw-r--r-- | desktop/knockout.c | 8 | ||||
-rw-r--r-- | desktop/local_history.c | 4 | ||||
-rw-r--r-- | desktop/mouse.c | 2 | ||||
-rw-r--r-- | desktop/netsurf.c | 30 | ||||
-rw-r--r-- | desktop/options.h | 5 | ||||
-rw-r--r-- | desktop/print.c | 6 | ||||
-rw-r--r-- | desktop/save_complete.c | 26 | ||||
-rw-r--r-- | desktop/save_pdf.c | 43 | ||||
-rw-r--r-- | desktop/save_text.c | 8 | ||||
-rw-r--r-- | desktop/searchweb.c | 20 | ||||
-rw-r--r-- | desktop/sslcert_viewer.c | 8 | ||||
-rw-r--r-- | desktop/textarea.c | 42 | ||||
-rw-r--r-- | desktop/textarea.h | 10 | ||||
-rw-r--r-- | desktop/treeview.c | 1274 | ||||
-rw-r--r-- | desktop/treeview.h | 14 | ||||
-rw-r--r-- | desktop/version.c | 4 |
25 files changed, 1528 insertions, 493 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..640302773 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,11 @@ nserror browser_window_history_go(struct browser_window *bw, url, NULL, bw, NULL); history->current = current; } else { + 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 +615,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 +633,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..54cc5451a 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; } 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/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..149ca26b1 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; } @@ -1835,13 +1836,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; } @@ -1888,7 +1889,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 +1901,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 +1976,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 +2063,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 +2074,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 +2861,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; diff --git a/desktop/textarea.h b/desktop/textarea.h index 898609730..b386e50e8 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 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; |