From b88a81b9d9570c3219dc924c3dd2b424d99ee4c3 Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Thu, 23 Jun 2005 17:22:28 +0000 Subject: [project @ 2005-06-23 17:22:28 by rjw] Allow images to be unloaded to disk or compressed in memory. Provide thumbnails in all tree windows (hotlist, history). Optimise the application initialisation times. Part 1 of 2. svn path=/import/netsurf/; revision=1761 --- riscos/bitmap.c | 579 ++++++++++++++++++++++++++++++++++++++++++++++-- riscos/bitmap.h | 31 ++- riscos/global_history.c | 32 ++- 3 files changed, 609 insertions(+), 33 deletions(-) (limited to 'riscos') diff --git a/riscos/bitmap.c b/riscos/bitmap.c index 2f2416550..a29cc1229 100644 --- a/riscos/bitmap.c +++ b/riscos/bitmap.c @@ -1,8 +1,9 @@ /* * This file is part of NetSurf, http://netsurf.sourceforge.net/ * Licensed under the GNU General Public License, - * http://www.opensource.org/licenses/gpl-license + * http://www.opensource.org/licenses/gpl-license * Copyright 2004 James Bursa + * Copyright 2005 Richard Wilson */ /** \file @@ -15,14 +16,136 @@ #include #include #include +#include +#include "oslib/osfile.h" #include "oslib/osspriteop.h" #include "netsurf/content/content.h" #include "netsurf/image/bitmap.h" #include "netsurf/riscos/bitmap.h" +#include "netsurf/riscos/filename.h" #include "netsurf/riscos/image.h" +#include "netsurf/riscos/options.h" +#include "netsurf/riscos/tinct.h" #include "netsurf/utils/log.h" #include "netsurf/utils/utils.h" +#define MAINTENANCE_THRESHOLD 32 + +/** The head of the bitmap list +*/ +struct bitmap *bitmap_head = NULL; + +/** Whether maintenance of the pool states is needed +*/ +bool bitmap_maintenance = false; + +/** Whether maintenance of the pool is high priority +*/ +bool bitmap_maintenance_priority = false; + +/** Maximum amount of memory for direct images +*/ +unsigned int bitmap_direct_size; + +/** Current amount of memory for direct images +*/ +unsigned int bitmap_direct_used = 0; + +/** Total size of compressed area +*/ +unsigned int bitmap_compressed_size; + +/** Total size of compressed area +*/ +unsigned int bitmap_compressed_used = 0; + + +/** Compressed data header +*/ +struct bitmap_compressed_header { + int width; + int height; + char name[12]; + unsigned int flags; + unsigned int input_size; +}; + +char bitmap_filename[256]; + + +bool bitmap_initialise(struct bitmap *bitmap, bool clear); +void bitmap_decompress(struct bitmap *bitmap); +void bitmap_compress(struct bitmap *bitmap); +void bitmap_load_file(struct bitmap *bitmap); +void bitmap_save_file(struct bitmap *bitmap); +void bitmap_delete_file(struct bitmap *bitmap); + + +/** + * Initialise the bitmap memory pool. + */ + +void bitmap_initialise_memory(void) +{ + int available_memory, direct_size, compressed_size; + int next_slot, free_slot; + os_error *error; + + /* calculate how much memory is currently free */ + error = xwimp_slot_size(-1, -1, 0, &next_slot, &free_slot); + if (error) { + LOG(("xwimp_slot_size: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return; + } + available_memory = next_slot + free_slot; + + /* calculate our memory block sizes */ + if (option_image_memory_direct == -1) { + /* claim 20% of free memory - min 256KB, max 32768KB */ + direct_size = available_memory * 0.20; + if (direct_size < (256 << 10)) + direct_size = (256 << 10); + if (direct_size > (32768 << 10)) + direct_size = (32768 << 10); + } else { + direct_size = (option_image_memory_direct << 10); + } + if (option_image_memory_compressed == -1) { + /* claim 5% of free memory - min 256KB, max 4192KB */ + compressed_size = available_memory * 0.05; + if (compressed_size < (256 << 10)) + compressed_size = 0; + if (compressed_size > (4192 << 10)) + compressed_size = (4192 << 10); + } else { + compressed_size = (option_image_memory_compressed << 10); + } + + /* set our values. No fixed buffers here, ho hum. */ + bitmap_direct_size = direct_size; + bitmap_compressed_size = compressed_size; + LOG(("Allowing %iKB of memory for compressed images.", + (bitmap_compressed_size >> 10))); + LOG(("Allowing %iKB of memory for uncompressed images.", + (bitmap_direct_size >> 10))); +} + + +/** + * Prepare for the end of a session. + */ + +void bitmap_quit(void) +{ + struct bitmap *bitmap; + + for (bitmap = bitmap_head; bitmap; bitmap = bitmap->next) + if ((bitmap->persistent) && (bitmap->filename[0] == '\0')) + bitmap_save_file(bitmap); +} + /** * Create a bitmap. @@ -35,28 +158,100 @@ struct bitmap *bitmap_create(int width, int height, bool clear) { - unsigned int area_size; struct bitmap *bitmap; - osspriteop_area *sprite_area; - osspriteop_header *sprite; if (width == 0 || height == 0) return NULL; - area_size = 16 + 44 + width * height * 4; - if (clear) - bitmap = calloc(sizeof(struct bitmap) + area_size, 1); - else - bitmap = malloc(sizeof(struct bitmap) + area_size); + bitmap = calloc(sizeof(struct bitmap), 1); if (!bitmap) return NULL; - bitmap->width = width; bitmap->height = height; bitmap->opaque = false; + if (!bitmap_initialise(bitmap, clear)) { + free(bitmap); + return NULL; + } + + /* link into our list of bitmaps at the head */ + bitmap_maintenance = true; + bitmap_maintenance_priority |= + (bitmap_direct_used > bitmap_direct_size * 1.1); + if (bitmap_head) { + bitmap->next = bitmap_head; + bitmap_head->previous = bitmap; + } + bitmap_head = bitmap; + return bitmap; +} + + +/** + * Create a persistent, opaque bitmap from a file reference. + * + * \param width width of image in pixels + * \param height width of image in pixels + * \param file the file containing the image data + * \return an opaque struct bitmap, or NULL on memory exhaustion + */ + +struct bitmap *bitmap_create_file(int width, int height, char *file) +{ + struct bitmap *bitmap; + struct bitmap *link; + + if (width == 0 || height == 0) + return NULL; + + if (!ro_filename_claim(file)) + return NULL; + bitmap = calloc(sizeof(struct bitmap), 1); + if (!bitmap) + return NULL; + bitmap->width = width; + bitmap->height = height; + bitmap->opaque = true; + bitmap->persistent = true; + sprintf(bitmap->filename, file); + + /* link into our list of bitmaps at the tail */ + if (bitmap_head) { + for (link = bitmap_head; link->next; link = link->next); + link->next = bitmap; + bitmap->previous = link; + } else { + bitmap_head = bitmap; + } + return bitmap; +} + + +/** + * Initialise a bitmaps sprite area. + * + * \param bitmap the bitmap to initialise + * \param clear whether to clear the image ready for use + */ + +bool bitmap_initialise(struct bitmap *bitmap, bool clear) +{ + unsigned int area_size; + osspriteop_area *sprite_area; + osspriteop_header *sprite; + + area_size = 16 + 44 + bitmap->width * bitmap->height * 4; + if (clear) + bitmap->sprite_area = calloc(area_size, 1); + else + bitmap->sprite_area = malloc(area_size); + if (!bitmap->sprite_area) { + return false; + } + bitmap_direct_used += area_size; /* area control block */ - sprite_area = &bitmap->sprite_area; + sprite_area = bitmap->sprite_area; sprite_area->size = area_size; sprite_area->sprite_count = 1; sprite_area->first = 16; @@ -68,14 +263,13 @@ struct bitmap *bitmap_create(int width, int height, bool clear) if (!clear) memset(sprite->name, 0x00, 12); strncpy(sprite->name, "bitmap", 12); - sprite->width = width - 1; - sprite->height = height - 1; + sprite->width = bitmap->width - 1; + sprite->height = bitmap->height - 1; sprite->left_bit = 0; sprite->right_bit = 31; sprite->image = sprite->mask = 44; - sprite->mode = (os_mode) 0x301680b5; - - return bitmap; + sprite->mode = tinct_SPRITE_MODE; + return true; } @@ -102,9 +296,11 @@ bool bitmap_test_opaque(struct bitmap *bitmap) { assert(bitmap); char *sprite = bitmap_get_buffer(bitmap); + if (!sprite) + return false; unsigned int width = bitmap_get_rowstride(bitmap); osspriteop_header *sprite_header = - (osspriteop_header *) (&(bitmap->sprite_area) + 1); + (osspriteop_header *) (bitmap->sprite_area + 1); unsigned int height = (sprite_header->height + 1); unsigned int size = width * height; unsigned *p = (unsigned*)sprite; @@ -153,7 +349,36 @@ bool bitmap_get_opaque(struct bitmap *bitmap) char *bitmap_get_buffer(struct bitmap *bitmap) { assert(bitmap); - return ((char *) (&(bitmap->sprite_area))) + 16 + 44; + + /* move to the head of the list */ + if (bitmap_head != bitmap) { + if (bitmap->previous) + bitmap->previous->next = bitmap->next; + if (bitmap->next) + bitmap->next->previous = bitmap->previous; + bitmap->next = bitmap_head; + bitmap_head->previous = bitmap; + bitmap->previous = NULL; + bitmap_head = bitmap; + } + + /* image is already decompressed, no change to image states */ + if (bitmap->sprite_area) + return ((char *) (bitmap->sprite_area)) + 16 + 44; + + /* load and/or decompress the image */ + if (bitmap->filename[0]) + bitmap_load_file(bitmap); + if (bitmap->compressed) + bitmap_decompress(bitmap); + + bitmap_maintenance = true; + bitmap_maintenance_priority |= + (bitmap_direct_used > bitmap_direct_size * 1.1); + + if (bitmap->sprite_area) + return ((char *) (bitmap->sprite_area)) + 16 + 44; + return NULL; } @@ -166,10 +391,7 @@ char *bitmap_get_buffer(struct bitmap *bitmap) size_t bitmap_get_rowstride(struct bitmap *bitmap) { - osspriteop_header *sprite; - assert(bitmap); - sprite = (osspriteop_header *) (&(bitmap->sprite_area) + 1); - return (sprite->width + 1) * 4; + return bitmap->width * 4; } @@ -181,7 +403,29 @@ size_t bitmap_get_rowstride(struct bitmap *bitmap) void bitmap_destroy(struct bitmap *bitmap) { + unsigned int area_size; + assert(bitmap); + + /* delink from list */ + bitmap_maintenance = true; + if (bitmap_head == bitmap) + bitmap_head = bitmap->next; + if (bitmap->previous) + bitmap->previous->next = bitmap->next; + if (bitmap->next) + bitmap->next->previous = bitmap->previous; + + /* destroy bitmap */ + if (bitmap->sprite_area) { + area_size = 16 + 44 + bitmap->width * bitmap->height * 4; + bitmap_direct_used -= area_size; + free(bitmap->sprite_area); + } + if (bitmap->compressed) + free(bitmap->compressed); + if (bitmap->filename[0]) + bitmap_delete_file(bitmap); free(bitmap); } @@ -190,15 +434,19 @@ void bitmap_destroy(struct bitmap *bitmap) * Save a bitmap in the platform's native format. * * \param bitmap a bitmap, as returned by bitmap_create() - * \param path pathname for file + * \param path pathname for file * \return true on success, false on error and error reported */ bool bitmap_save(struct bitmap *bitmap, const char *path) { os_error *error; + if (!bitmap->sprite_area) + bitmap_get_buffer(bitmap); + if (!bitmap->sprite_area) + return false; error = xosspriteop_save_sprite_file(osspriteop_USER_AREA, - &(bitmap->sprite_area), path); + (bitmap->sprite_area), path); if (error) { LOG(("xosspriteop_save_sprite_file: 0x%x: %s", error->errnum, error->errmess)); @@ -207,3 +455,286 @@ bool bitmap_save(struct bitmap *bitmap, const char *path) } return true; } + + +/** + * The bitmap image has changed, so flush any persistant cache. + * + * \param bitmap a bitmap, as returned by bitmap_create() + */ +void bitmap_modified(struct bitmap *bitmap) { + bitmap->modified = true; +} + + +/** + * Performs routine maintenance. + */ +void bitmap_maintain(void) +{ + unsigned int memory; + struct bitmap *bitmap = bitmap_head; + struct bitmap_compressed_header *header; + unsigned int maintain_direct_size; + +// LOG(("Performing maintenance.")); + + if (!bitmap) { + bitmap_maintenance = false; + bitmap_maintenance_priority = false; + return; + } + maintain_direct_size = bitmap_direct_size; + if (!bitmap_maintenance_priority) + maintain_direct_size = maintain_direct_size * 0.7; + + /* we don't change the first bitmap_MEMORY entries as they + * will automatically be loaded/decompressed from whatever state + * they are in when neeeded. */ + for (memory = 0; bitmap && (memory < maintain_direct_size); + bitmap = bitmap->next) + if (bitmap->sprite_area) + memory += bitmap->width * bitmap->height * 4; + if (!bitmap) { + bitmap_maintenance = bitmap_maintenance_priority; + bitmap_maintenance_priority = false; + return; + } + + /* under heavy loads, we ignore compression */ + if (!bitmap_maintenance_priority) { + /* for the next section, up until bitmap_COMPRESSED we + * forcibly compress the data if it's currently held directly + * in memory */ + for (memory = 0; bitmap && (memory < bitmap_compressed_size); + bitmap = bitmap->next) { + if (bitmap->sprite_area) { + bitmap_compress(bitmap); + return; + } + if (bitmap->compressed) { + header = (struct bitmap_compressed_header *) + bitmap->compressed; + memory += header->input_size + + sizeof(struct bitmap_compressed_header); + } + } + if (!bitmap) { + bitmap_maintenance = false; + return; + } + } + + /* for the remaining entries we dump to disk */ + for (; bitmap; bitmap = bitmap->next) { + if ((bitmap->sprite_area) || (bitmap->compressed)) { + if (bitmap_maintenance_priority) { + if (bitmap->sprite_area) + bitmap_save_file(bitmap); + + } else { + bitmap_save_file(bitmap); + return; + } + } + } + bitmap_maintenance = bitmap_maintenance_priority; + bitmap_maintenance_priority = false; +} + + +void bitmap_decompress(struct bitmap *bitmap) +{ + unsigned int area_size; + _kernel_oserror *error; + int output_size; + struct bitmap_compressed_header *header; + + assert(bitmap->compressed); + + /* create the image memory/header to decompress to */ + if (!bitmap_initialise(bitmap, false)) + return; + + /* decompress the data */ + output_size = bitmap->width * bitmap->height * 4 + + sizeof(struct osspriteop_header); + error = _swix(Tinct_Decompress, _IN(0) | _IN(2) | _IN(3) | _IN(7), + bitmap->compressed, + (char *)(bitmap->sprite_area + 1), + output_size, + 0); + if (error) { + LOG(("Decompression error")); + free(bitmap->sprite_area); + bitmap->sprite_area = NULL; + } else { +// LOG(("Decompressed")); + header = (struct bitmap_compressed_header *)bitmap->compressed; + area_size = header->input_size + + sizeof(struct bitmap_compressed_header); + bitmap_compressed_used -= area_size; + free(bitmap->compressed); + bitmap->compressed = NULL; + area_size = 16 + 44 + bitmap->width * bitmap->height * 4; + bitmap_direct_used += area_size; + } +} + + +void bitmap_compress(struct bitmap *bitmap) +{ + unsigned int area_size; + _kernel_oserror *error; + char *output; + unsigned int output_size, new_size; + unsigned int flags = 0; + float calc; + + /* get the maximum output size (33/32 * size) */ + output_size = ((bitmap->width * bitmap->height * 4 * 33) >> 5) + + sizeof(struct bitmap_compressed_header); + output = malloc(output_size); + if (!output) + return; + + /* compress the data */ + if (bitmap->opaque) + flags |= tinct_OPAQUE_IMAGE; + error = _swix(Tinct_Compress, _IN(0) | _IN(2) | _IN(7) | _OUT(0), + (char *)(bitmap->sprite_area + 1), + output, + flags, + &new_size); + if (error) { + LOG(("Compression error")); + free(output); + } else { + bitmap->compressed = realloc(output, new_size); + if (!bitmap->compressed) { + free(output); + } else { + bitmap_compressed_used += new_size; + if (bitmap->sprite_area) { + area_size = 16 + 44 + bitmap->width * + bitmap->height * 4; + bitmap_direct_used -= area_size; + free(bitmap->sprite_area); + } + bitmap->sprite_area = NULL; + calc = (100 / (float)output_size) * new_size; +// LOG(("Compression: %i->%i, %.3f%%", +// output_size, new_size, calc)); + } + } +} + +void bitmap_load_file(struct bitmap *bitmap) +{ + unsigned int area_size; + int len; + fileswitch_object_type obj_type; + os_error *error; + + assert(bitmap->filename); + + sprintf(bitmap_filename, "%s.%s", CACHE_FILENAME_PREFIX, + bitmap->filename); + error = xosfile_read_stamped_no_path(bitmap_filename, + &obj_type, 0, 0, &len, 0, 0); + if ((error) || (obj_type != fileswitch_IS_FILE)) + return; + bitmap->compressed = malloc(len); + if (!bitmap->compressed) + return; + error = xosfile_load_stamped_no_path(bitmap_filename, + bitmap->compressed, 0, 0, 0, 0, 0); + if (error) { + free(bitmap->compressed); + bitmap->compressed = NULL; + return; + } else { +// LOG(("Loaded file from disk")); + if (strncmp(bitmap->compressed + 8, "bitmap", 6)) { + bitmap->sprite_area = + (osspriteop_area *)bitmap->compressed; + bitmap->compressed = NULL; + area_size = 16 + 44 + + bitmap->width * bitmap->height * 4; + bitmap_direct_used += area_size; + } else { + bitmap_compressed_used -= len; + } + if (bitmap->modified) + bitmap_delete_file(bitmap); + } +} + + +void bitmap_save_file(struct bitmap *bitmap) +{ + unsigned int area_size; + char *filename; + os_error *error; + struct bitmap_compressed_header *header; + + assert(bitmap->compressed || bitmap->sprite_area); + + /* unmodified bitmaps will still have their file available */ + if (!bitmap->modified && bitmap->filename[0]) { + if (bitmap->sprite_area) + free(bitmap->sprite_area); + bitmap->sprite_area = NULL; + if (bitmap->compressed) + free(bitmap->compressed); + bitmap->compressed = NULL; + return; + } + + /* dump the data (compressed or otherwise) to disk */ + filename = ro_filename_request(); + strcpy(bitmap->filename, filename); + sprintf(bitmap_filename, "%s.%s", CACHE_FILENAME_PREFIX, + bitmap->filename); + if (bitmap->compressed) { + header = (struct bitmap_compressed_header *)bitmap->compressed; + area_size = header->input_size + + sizeof(struct bitmap_compressed_header); + error = xosfile_save_stamped(bitmap_filename, 0xffd, + bitmap->compressed, + bitmap->compressed + area_size); + } else { + area_size = bitmap->width * bitmap->height * 4 + + sizeof(osspriteop_header) + + sizeof(osspriteop_area); + error = xosfile_save_stamped(bitmap_filename, 0xffd, + (char *)bitmap->sprite_area, + ((char *)bitmap->sprite_area) + area_size); + } + + if (error) { + LOG(("File save error")); + bitmap->filename[0] = 0; + } else { + if (bitmap->sprite_area) { + bitmap_direct_used -= area_size; + free(bitmap->sprite_area); + } + bitmap->sprite_area = NULL; + if (bitmap->compressed) { + bitmap_compressed_used -= area_size; + free(bitmap->compressed); + } + bitmap->compressed = NULL; + bitmap->modified = false; +// LOG(("Saved file to disk")); + } +} + + +void bitmap_delete_file(struct bitmap *bitmap) +{ + assert(bitmap->filename[0]); + ro_filename_release(bitmap->filename); + bitmap->filename[0] = 0; +} diff --git a/riscos/bitmap.h b/riscos/bitmap.h index 7a5fbf5c7..2ce8f04a9 100644 --- a/riscos/bitmap.h +++ b/riscos/bitmap.h @@ -1,20 +1,45 @@ /* * This file is part of NetSurf, http://netsurf.sourceforge.net/ * Licensed under the GNU General Public License, - * http://www.opensource.org/licenses/gpl-license + * http://www.opensource.org/licenses/gpl-license * Copyright 2004 James Bursa */ #ifndef _NETSURF_RISCOS_BITMAP_H_ #define _NETSURF_RISCOS_BITMAP_H_ +#include "oslib/osspriteop.h" + struct osspriteop_area; struct bitmap { int width; int height; - bool opaque; - osspriteop_area sprite_area; + bool opaque; + bool modified; + bool persistent; + + osspriteop_area *sprite_area; /** Uncompressed data, or NULL */ + char *compressed; /** Compressed data, or NULL */ + char filename[12]; /** Data filename, or '/0' */ + + struct bitmap *previous; /** Previous bitmap */ + struct bitmap *next; /** Next bitmap */ + }; +struct bitmap *bitmap_create_file(int width, int height, char *file); +void bitmap_initialise_memory(void); +void bitmap_quit(void); +void bitmap_maintain(void); + +/** Whether maintenance of the pool states is needed +*/ +extern bool bitmap_maintenance; + +/** Whether maintenance of the pool is high priority +*/ +extern bool bitmap_maintenance_priority; + + #endif diff --git a/riscos/global_history.c b/riscos/global_history.c index ac04a8141..307d021bd 100644 --- a/riscos/global_history.c +++ b/riscos/global_history.c @@ -45,6 +45,9 @@ static int global_history_base_node_count = 0; static char *global_history_recent_url[GLOBAL_HISTORY_RECENT_URLS]; static int global_history_recent_count = 0; +static bool global_history_init; + + static void ro_gui_global_history_initialise_nodes(void); static void ro_gui_global_history_initialise_node(const char *title, time_t base, int days_back); @@ -164,6 +167,7 @@ void ro_gui_global_history_initialise(void) { LOG(("Failed to open file '%s' for reading", GLOBAL_HISTORY_READ)); else { + global_history_init = true; while (fgets(s, MAXIMUM_URL_LENGTH, fp)) { if (s[strlen(s) - 1] == '\n') s[strlen(s) - 1] = '\0'; @@ -172,6 +176,7 @@ void ro_gui_global_history_initialise(void) { LOG(("Error reading global history")); warn_user("HistoryCorrupt", 0); fclose(fp); + global_history_init = false; return; } if (s[strlen(s) - 1] == '\n') @@ -181,12 +186,14 @@ void ro_gui_global_history_initialise(void) { LOG(("No memory to read global history node")); warn_user("NoMemory", 0); fclose(fp); + global_history_init = false; return; } if (!fgets(s, MAXIMUM_URL_LENGTH, fp)) { LOG(("Error reading global history")); warn_user("HistoryCorrupt", 0); fclose(fp); + global_history_init = false; return; } node_filetype = atoi(s); @@ -194,6 +201,7 @@ void ro_gui_global_history_initialise(void) { LOG(("Error reading global history")); warn_user("HistoryCorrupt", 0); fclose(fp); + global_history_init = false; return; } node_visited = atoi(s); @@ -204,6 +212,7 @@ void ro_gui_global_history_initialise(void) { free(node_url); node_url = NULL; } + global_history_init = false; fclose(fp); } } @@ -367,14 +376,24 @@ int ro_gui_global_history_help(int x, int y) { * \param g the gui_window to add to the global history */ void global_history_add(struct gui_window *g) { + url_func_result res; + char *norm_url = NULL; + assert(g); if ((!g->bw->current_content) || (!global_history_tree)) return; + res = url_normalize(g->bw->current_content->url, &norm_url); + if (res != URL_FUNC_OK) { + warn_user("NoMemory", 0); + return; + } + ro_gui_global_history_add(g->bw->current_content->title, - g->bw->current_content->url, time(NULL), + norm_url, time(NULL), ro_content_filetype(g->bw->current_content)); + free(norm_url); } @@ -412,8 +431,9 @@ void ro_gui_global_history_add(char *title, char *url, int visit_date, tree_link_node(link, parent, before); tree_recalculate_node_positions( global_history_tree->root); - tree_redraw_area(global_history_tree, - 0, 0, 16384, 16384); + if (!global_history_init) + tree_redraw_area(global_history_tree, + 0, 0, 16384, 16384); break; } } @@ -423,13 +443,13 @@ void ro_gui_global_history_add(char *title, char *url, int visit_date, */ node = tree_create_URL_node_brief(parent, title, url, filetype, visit_date); - if (node) { + if (node && !global_history_init) tree_redraw_area(global_history_tree, node->box.x - NODE_INSTEP, 0, NODE_INSTEP, 16384); + if (!global_history_init) tree_handle_node_changed(global_history_tree, node, - false, true); - } + true, false); /* Remove any duplicate URL from within the parent node. * This must be done after the duplicate has been created as -- cgit v1.2.3