From d6875fba63cc674d2d9cac64a66c3b4c9f3eaba1 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 8 Aug 2020 08:06:22 +0300 Subject: Moved recent URLs history to DocumentWidget App maintains the visited URLs database, but each DocumentWidget has its own stack of recent URLs for timeline navigation. --- CMakeLists.txt | 2 + src/app.c | 41 +++++++--------- src/app.h | 4 +- src/gmdocument.c | 4 +- src/history.c | 111 ++--------------------------------------- src/history.h | 46 ++++++----------- src/ui/documentwidget.c | 23 +++++++-- src/ui/documentwidget.h | 5 ++ src/ui/window.c | 5 +- src/visited.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++ src/visited.h | 25 ++++++++++ 11 files changed, 224 insertions(+), 170 deletions(-) create mode 100644 src/visited.c create mode 100644 src/visited.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 573bf09b..1f0014bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,8 @@ set (SOURCES src/history.h src/stb_image.h src/stb_truetype.h + src/visited.c + src/visited.h # User interface: src/ui/color.c src/ui/color.h diff --git a/src/app.c b/src/app.c index 0d15bce1..5b31faa7 100644 --- a/src/app.c +++ b/src/app.c @@ -3,6 +3,7 @@ #include "gmcerts.h" #include "gmutil.h" #include "history.h" +#include "visited.h" #include "ui/command.h" #include "ui/window.h" #include "ui/inputwidget.h" @@ -55,7 +56,8 @@ struct Impl_App { iSortedArray tickers; iBool pendingRefresh; iGmCerts * certs; - iHistory * history; +// iHistory * history; + iVisited * visited; /* Preferences: */ iBool retainWindowSize; float uiScale; @@ -149,9 +151,9 @@ static void init_App_(iApp *d, int argc, char **argv) { d->retainWindowSize = iTrue; d->pendingRefresh = iFalse; d->certs = new_GmCerts(dataDir_App_); - d->history = new_History(); + d->visited = new_Visited(); loadPrefs_App_(d); - load_History(d->history, dataDir_App_); + load_Visited(d->visited, dataDir_App_); #if defined (iHaveLoadEmbed) /* Load the resources from a file. */ { if (!load_Embed(concatPath_CStr(cstr_String(execPath_App()), "../resources.bin"))) { @@ -170,8 +172,8 @@ static void init_App_(iApp *d, int argc, char **argv) { static void deinit_App(iApp *d) { savePrefs_App_(d); - save_History(d->history, dataDir_App_); - delete_History(d->history); + save_Visited(d->visited, dataDir_App_); + delete_Visited(d->visited); delete_GmCerts(d->certs); deinit_SortedArray(&d->tickers); delete_Window(d->window); @@ -313,8 +315,8 @@ iGmCerts *certs_App(void) { return app_.certs; } -iHistory *history_App(void) { - return app_.history; +iVisited *visited_App(void) { + return app_.visited; } static iBool handlePrefsCommands_(iWidget *d, const char *cmd) { @@ -332,40 +334,43 @@ iDocumentWidget *document_App(void) { } iDocumentWidget *document_Command(const char *cmd) { + /* Explicitly referenced. */ iAnyObject *obj = pointerLabel_Command(cmd, "doc"); if (obj) { return obj; } + /* Implicit via source widget. */ obj = pointer_Command(cmd); if (obj && isInstance_Object(obj, &Class_DocumentWidget)) { return obj; } + /* Currently visible document. */ return document_App(); } iBool handleCommand_App(const char *cmd) { iApp *d = &app_; - iWidget *root = d->window->root; if (equal_Command(cmd, "open")) { const iString *url = collect_String(newCStr_String(suffixPtr_Command(cmd, "url"))); iUrl parts; init_Url(&parts, url); if (equalCase_Rangecc(&parts.protocol, "http") || equalCase_Rangecc(&parts.protocol, "https")) { - visitUrl_History(d->history, url); openInDefaultBrowser_App(url); return iTrue; } + iDocumentWidget *doc = document_Command(cmd); + iHistory *history = history_DocumentWidget(doc); const iBool isHistory = argLabel_Command(cmd, "history") != 0; if (!isHistory) { if (argLabel_Command(cmd, "redirect")) { - replace_History(d->history, url); + replace_History(history, url); } else { - addUrl_History(d->history, url); + add_History(history, url); } } - iDocumentWidget *doc = findChild_Widget(root, "document"); + visitUrl_Visited(d->visited, url); setInitialScroll_DocumentWidget(doc, argLabel_Command(cmd, "scroll") * gap_UI); setUrlFromCache_DocumentWidget(doc, url, isHistory); } @@ -403,18 +408,6 @@ iBool handleCommand_App(const char *cmd) { const iInt2 pos = coord_Command(cmd); SDL_SetWindowPosition(d->window->win, pos.x, pos.y); } - else if (equal_Command(cmd, "document.changed")) { - /* TODO: Update current history item with this actual/redirected URL. */ - return iFalse; - } - else if (equal_Command(cmd, "navigate.back")) { - goBack_History(d->history); - return iTrue; - } - else if (equal_Command(cmd, "navigate.forward")) { - goForward_History(d->history); - return iTrue; - } else if (equal_Command(cmd, "navigate.home")) { iString *homePath = newCStr_String(dataDir_App_); clean_Path(homePath); diff --git a/src/app.h b/src/app.h index cdfc387d..64c1f64d 100644 --- a/src/app.h +++ b/src/app.h @@ -6,7 +6,7 @@ #include iDeclareType(GmCerts) -iDeclareType(History) +iDeclareType(Visited) iDeclareType(Window) enum iAppEventMode { @@ -27,7 +27,7 @@ iBool handleCommand_App (const char *cmd); void refresh_App (void); iGmCerts * certs_App (void); -iHistory * history_App (void); +iVisited * visited_App (void); iAny * findWidget_App (const char *id); void addTicker_App (void (*ticker)(iAny *), iAny *context); diff --git a/src/gmdocument.c b/src/gmdocument.c index 4c0ca86e..bdf30807 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c @@ -4,7 +4,7 @@ #include "ui/text.h" #include "ui/metrics.h" #include "ui/window.h" -#include "history.h" +#include "visited.h" #include "app.h" #include @@ -212,7 +212,7 @@ static iRangecc addLink_GmDocument_(iGmDocument *d, iRangecc line, iGmLinkId *li } /* Check if visited. */ if (cmpString_String(&link->url, &d->url)) { - link->when = urlVisitTime_History(history_App(), &link->url); + link->when = urlVisitTime_Visited(visited_App(), &link->url); if (isValid_Time(&link->when)) { link->flags |= visited_GmLinkFlag; } diff --git a/src/history.c b/src/history.c index a2c4271f..c009f484 100644 --- a/src/history.c +++ b/src/history.c @@ -3,10 +3,8 @@ #include #include -#include -static const size_t maxStack_History_ = 50; /* back/forward navigable items */ -static const size_t maxAgeVisited_History_ = 3600 * 24 * 30; /* one month */ +static const size_t maxStack_History_ = 50; /* back/forward navigable items */ void init_RecentUrl(iRecentUrl *d) { init_String(&d->url); @@ -19,30 +17,11 @@ void deinit_RecentUrl(iRecentUrl *d) { delete_GmResponse(d->cachedResponse); } -void init_VisitedUrl(iVisitedUrl *d) { - initCurrent_Time(&d->when); - init_String(&d->url); -} - -void deinit_VisitedUrl(iVisitedUrl *d) { - deinit_String(&d->url); -} - -static int cmpUrl_VisitedUrl_(const void *a, const void *b) { - return cmpString_String(&((const iVisitedUrl *) a)->url, &((const iVisitedUrl *) b)->url); -} - -static int cmpNewer_VisitedUrl_(const void *insert, const void *existing) { - return seconds_Time(&((const iVisitedUrl *) insert )->when) > - seconds_Time(&((const iVisitedUrl *) existing)->when); -} - /*----------------------------------------------------------------------------------------------*/ struct Impl_History { - iArray recent; /* TODO: should be specific to a DocumentWidget */ - size_t recentPos; /* zero at the latest item */ - iSortedArray visited; + iArray recent; /* TODO: should be specific to a DocumentWidget */ + size_t recentPos; /* zero at the latest item */ }; iDefineTypeConstruction(History) @@ -50,13 +29,11 @@ iDefineTypeConstruction(History) void init_History(iHistory *d) { init_Array(&d->recent, sizeof(iRecentUrl)); d->recentPos = 0; - init_SortedArray(&d->visited, sizeof(iVisitedUrl), cmpUrl_VisitedUrl_); } void deinit_History(iHistory *d) { clear_History(d); deinit_Array(&d->recent); - deinit_SortedArray(&d->visited); } void save_History(const iHistory *d, const char *dirPath) { @@ -70,25 +47,6 @@ void save_History(const iHistory *d, const char *dirPath) { } } iRelease(f); - f = newCStr_File(concatPath_CStr(dirPath, "visited.txt")); - if (open_File(f, writeOnly_FileMode | text_FileMode)) { - iConstForEach(Array, i, &d->visited.values) { - const iVisitedUrl *item = i.value; - iDate date; - init_Date(&date, &item->when); - format_String(line, - "%04d-%02d-%02dT%02d:%02d:%02d %s\n", - date.year, - date.month, - date.day, - date.hour, - date.minute, - date.second, - cstr_String(&item->url)); - writeData_File(f, cstr_String(line), size_String(line)); - } - } - iRelease(f); delete_String(line); } @@ -111,29 +69,6 @@ void load_History(iHistory *d, const char *dirPath) { } } iRelease(f); - f = newCStr_File(concatPath_CStr(dirPath, "visited.txt")); - if (open_File(f, readOnly_FileMode | text_FileMode)) { - const iRangecc src = range_Block(collect_Block(readAll_File(f))); - iRangecc line = iNullRange; - iTime now; - initCurrent_Time(&now); - while (nextSplit_Rangecc(&src, "\n", &line)) { - int y, m, D, H, M, S; - sscanf(line.start, "%04d-%02d-%02dT%02d:%02d:%02d ", &y, &m, &D, &H, &M, &S); - if (!y) break; - iVisitedUrl item; - init_VisitedUrl(&item); - init_Time( - &item.when, - &(iDate){ .year = y, .month = m, .day = D, .hour = H, .minute = M, .second = S }); - if (secondsSince_Time(&now, &item.when) > maxAgeVisited_History_) { - continue; /* Too old. */ - } - initRange_String(&item.url, (iRangecc){ line.start + 20, line.end }); - insert_SortedArray(&d->visited, &item); - } - } - iRelease(f); } void clear_History(iHistory *d) { @@ -141,10 +76,6 @@ void clear_History(iHistory *d) { deinit_RecentUrl(s.value); } clear_Array(&d->recent); - iForEach(Array, v, &d->visited.values) { - deinit_VisitedUrl(v.value); - } - clear_SortedArray(&d->visited); } iRecentUrl *recentUrl_History(iHistory *d, size_t pos) { @@ -173,32 +104,15 @@ const iString *url_History(const iHistory *d, size_t pos) { return collectNew_String(); } -static void addVisited_History_(iHistory *d, const iString *url) { - iVisitedUrl visit; - init_VisitedUrl(&visit); - set_String(&visit.url, url); - size_t pos; - if (locate_SortedArray(&d->visited, &visit, &pos)) { - iVisitedUrl *old = at_SortedArray(&d->visited, pos); - if (cmpNewer_VisitedUrl_(&visit, old)) { - old->when = visit.when; - deinit_VisitedUrl(&visit); - return; - } - } - insert_SortedArray(&d->visited, &visit); -} - void replace_History(iHistory *d, const iString *url) { /* Update in the history. */ iRecentUrl *item = mostRecentUrl_History(d); if (item) { set_String(&item->url, url); } - addVisited_History_(d, url); } -void addUrl_History(iHistory *d, const iString *url ){ +void add_History(iHistory *d, const iString *url ){ /* Cut the trailing history items. */ if (d->recentPos > 0) { for (size_t i = 0; i < d->recentPos - 1; i++) { @@ -220,11 +134,6 @@ void addUrl_History(iHistory *d, const iString *url ){ remove_Array(&d->recent, 0); } } - addVisited_History_(d, url); -} - -void visitUrl_History(iHistory *d, const iString *url) { - addVisited_History_(d, url); } iBool goBack_History(iHistory *d) { @@ -247,18 +156,6 @@ iBool goForward_History(iHistory *d) { return iFalse; } -iTime urlVisitTime_History(const iHistory *d, const iString *url) { - iVisitedUrl item; - size_t pos; - iZap(item); - initCopy_String(&item.url, url); - if (locate_SortedArray(&d->visited, &item, &pos)) { - item.when = ((const iVisitedUrl *) constAt_SortedArray(&d->visited, pos))->when; - } - deinit_String(&item.url); - return item.when; -} - const iGmResponse *cachedResponse_History(const iHistory *d) { const iRecentUrl *item = constMostRecentUrl_History(d); return item ? item->cachedResponse : NULL; diff --git a/src/history.h b/src/history.h index 8593a7ad..bb7f5c88 100644 --- a/src/history.h +++ b/src/history.h @@ -15,42 +15,28 @@ struct Impl_RecentUrl { iGmResponse *cachedResponse; /* kept in memory for quicker back navigation */ }; -iDeclareType(VisitedUrl) -iDeclareTypeConstruction(VisitedUrl) - -struct Impl_VisitedUrl { - iString url; - iTime when; -}; - /*----------------------------------------------------------------------------------------------*/ iDeclareType(History) iDeclareTypeConstruction(History) -void clear_History (iHistory *); - -void load_History (iHistory *, const char *dirPath); -void save_History (const iHistory *, const char *dirPath); - -iRecentUrl * - recentUrl_History (iHistory *, size_t pos); -iRecentUrl * - mostRecentUrl_History (iHistory *); - +void clear_History (iHistory *); +void load_History (iHistory *, const char *dirPath); +void add_History (iHistory *, const iString *url); +void replace_History (iHistory *, const iString *url); +void setCachedResponse_History (iHistory *, const iGmResponse *response); +iBool goBack_History (iHistory *); +iBool goForward_History (iHistory *); +iRecentUrl *recentUrl_History (iHistory *, size_t pos); +iRecentUrl *mostRecentUrl_History (iHistory *); + +void save_History (const iHistory *, const char *dirPath); const iString * - url_History (const iHistory *, size_t pos); + url_History (const iHistory *, size_t pos); const iRecentUrl * - constRecentUrl_History (const iHistory *d, size_t pos); + constRecentUrl_History (const iHistory *d, size_t pos); const iRecentUrl * - constMostRecentUrl_History (const iHistory *); -iTime urlVisitTime_History (const iHistory *, const iString *url); + constMostRecentUrl_History (const iHistory *); const iGmResponse * - cachedResponse_History (const iHistory *); - -void addUrl_History (iHistory *, const iString *url); /* adds to the stack of recents */ -void setCachedResponse_History (iHistory *, const iGmResponse *response); -void visitUrl_History (iHistory *, const iString *url); /* adds URL to the visited URLs set */ -void replace_History (iHistory *, const iString *url); -iBool goBack_History (iHistory *); -iBool goForward_History (iHistory *); + cachedResponse_History (const iHistory *); + diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 661a9d46..a1299727 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -76,6 +76,7 @@ iDefineClass(MediaRequest) struct Impl_DocumentWidget { iWidget widget; + iHistory *history; enum iDocumentState state; iString *url; iString *titleUser; @@ -98,7 +99,7 @@ struct Impl_DocumentWidget { int initialScrollY; iScrollWidget *scroll; iWidget *menu; - SDL_Cursor *arrowCursor; + SDL_Cursor *arrowCursor; /* TODO: cursors belong in Window */ SDL_Cursor *beamCursor; SDL_Cursor *handCursor; }; @@ -110,6 +111,7 @@ void init_DocumentWidget(iDocumentWidget *d) { init_Widget(w); setId_Widget(w, "document"); iZap(d->certExpiry); + d->history = new_History(); d->state = blank_DocumentState; d->url = new_String(); d->titleUser = new_String(); @@ -153,6 +155,7 @@ void deinit_DocumentWidget(iDocumentWidget *d) { SDL_FreeCursor(d->arrowCursor); SDL_FreeCursor(d->beamCursor); SDL_FreeCursor(d->handCursor); + delete_History(d->history); } static int documentWidth_DocumentWidget_(const iDocumentWidget *d) { @@ -258,7 +261,7 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { render_GmDocument(d->doc, visRange, addVisibleLink_DocumentWidget_, d); updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window())); /* Remember scroll positions of recently visited pages. */ { - iRecentUrl *recent = mostRecentUrl_History(history_App()); + iRecentUrl *recent = mostRecentUrl_History(d->history); if (recent) { recent->scrollY = d->scrollY / gap_UI; } @@ -424,6 +427,10 @@ static void updateTrust_DocumentWidget_(iDocumentWidget *d, const iGmResponse *r } } +iHistory *history_DocumentWidget(iDocumentWidget *d) { + return d->history; +} + void setUrlFromCache_DocumentWidget(iDocumentWidget *d, const iString *url, iBool isFromCache) { if (cmpStringSc_String(d->url, url, &iCaseInsensitive)) { set_String(d->url, url); @@ -439,7 +446,7 @@ void setUrlFromCache_DocumentWidget(iDocumentWidget *d, const iString *url, iBoo iRelease(userPats[i]); } } - const iRecentUrl *recent = mostRecentUrl_History(history_App()); + const iRecentUrl *recent = mostRecentUrl_History(d->history); if (isFromCache && recent && recent->cachedResponse) { const iGmResponse *resp = recent->cachedResponse; d->state = fetching_DocumentState; @@ -764,7 +771,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e pointerLabel_Command(command_UserEvent(ev), "request") == d->request) { checkResponse_DocumentWidget_(d); d->state = ready_DocumentState; - setCachedResponse_History(history_App(), response_GmRequest(d->request)); + setCachedResponse_History(d->history, response_GmRequest(d->request)); iReleasePtr(&d->request); postCommandf_App("document.changed url:%s", cstr_String(d->url)); return iFalse; @@ -788,6 +795,14 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e fetch_DocumentWidget_(d); return iTrue; } + else if (isCommand_UserEvent(ev, "navigate.back")) { + goBack_History(d->history); + return iTrue; + } + else if (isCommand_UserEvent(ev, "navigate.forward")) { + goForward_History(d->history); + return iTrue; + } else if (isCommand_Widget(w, ev, "scroll.moved")) { d->scrollY = arg_Command(command_UserEvent(ev)); updateVisible_DocumentWidget_(d); diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h index 7064d0d7..5ce28f4e 100644 --- a/src/ui/documentwidget.h +++ b/src/ui/documentwidget.h @@ -2,10 +2,15 @@ #include "widget.h" +iDeclareType(History) + iDeclareWidgetClass(DocumentWidget) iDeclareObjectConstruction(DocumentWidget) +iHistory * history_DocumentWidget (iDocumentWidget *); + void setUrl_DocumentWidget (iDocumentWidget *, const iString *url); void setUrlFromCache_DocumentWidget (iDocumentWidget *d, const iString *url, iBool isFromCache); void setInitialScroll_DocumentWidget (iDocumentWidget *, int scrollY); /* set after content received */ + iBool isRequestOngoing_DocumentWidget (const iDocumentWidget *); diff --git a/src/ui/window.c b/src/ui/window.c index 2661fd3f..defe998f 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -6,6 +6,7 @@ #include "paint.h" #include "text.h" #include "util.h" +#include "../visited.h" #include "labelwidget.h" #include "inputwidget.h" #include "documentwidget.h" @@ -108,7 +109,9 @@ static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) { } else if (equal_Command(cmd, "document.changed")) { iInputWidget *url = findWidget_App("url"); - setTextCStr_InputWidget(url, suffixPtr_Command(cmd, "url")); + const iString *urlStr = collect_String(suffix_Command(cmd, "url")); + visitUrl_Visited(visited_App(), urlStr); + setText_InputWidget(url, urlStr); updateTextCStr_LabelWidget(findChild_Widget(navBar, "reload"), reloadCStr_); return iFalse; } diff --git a/src/visited.c b/src/visited.c new file mode 100644 index 00000000..af976be5 --- /dev/null +++ b/src/visited.c @@ -0,0 +1,128 @@ +#include "visited.h" +#include "app.h" + +#include +#include +#include + +static const size_t maxAgeVisited_Visited_ = 3600 * 24 * 30; /* one month */ + +void init_VisitedUrl(iVisitedUrl *d) { + initCurrent_Time(&d->when); + init_String(&d->url); +} + +void deinit_VisitedUrl(iVisitedUrl *d) { + deinit_String(&d->url); +} + +static int cmpUrl_VisitedUrl_(const void *a, const void *b) { + return cmpString_String(&((const iVisitedUrl *) a)->url, &((const iVisitedUrl *) b)->url); +} + +static int cmpNewer_VisitedUrl_(const void *insert, const void *existing) { + return seconds_Time(&((const iVisitedUrl *) insert )->when) > + seconds_Time(&((const iVisitedUrl *) existing)->when); +} + +/*----------------------------------------------------------------------------------------------*/ + +struct Impl_Visited { + iSortedArray visited; +}; + +iDefineTypeConstruction(Visited) + +void init_Visited(iVisited *d) { + init_SortedArray(&d->visited, sizeof(iVisitedUrl), cmpUrl_VisitedUrl_); +} + +void deinit_Visited(iVisited *d) { + clear_Visited(d); + deinit_SortedArray(&d->visited); +} + +void save_Visited(const iVisited *d, const char *dirPath) { + iString *line = new_String(); + iFile *f = newCStr_File(concatPath_CStr(dirPath, "visited.txt")); + if (open_File(f, writeOnly_FileMode | text_FileMode)) { + iConstForEach(Array, i, &d->visited.values) { + const iVisitedUrl *item = i.value; + iDate date; + init_Date(&date, &item->when); + format_String(line, + "%04d-%02d-%02dT%02d:%02d:%02d %s\n", + date.year, + date.month, + date.day, + date.hour, + date.minute, + date.second, + cstr_String(&item->url)); + writeData_File(f, cstr_String(line), size_String(line)); + } + } + iRelease(f); + delete_String(line); +} + +void load_Visited(iVisited *d, const char *dirPath) { + iFile *f = newCStr_File(concatPath_CStr(dirPath, "visited.txt")); + if (open_File(f, readOnly_FileMode | text_FileMode)) { + const iRangecc src = range_Block(collect_Block(readAll_File(f))); + iRangecc line = iNullRange; + iTime now; + initCurrent_Time(&now); + while (nextSplit_Rangecc(&src, "\n", &line)) { + int y, m, D, H, M, S; + sscanf(line.start, "%04d-%02d-%02dT%02d:%02d:%02d ", &y, &m, &D, &H, &M, &S); + if (!y) break; + iVisitedUrl item; + init_VisitedUrl(&item); + init_Time( + &item.when, + &(iDate){ .year = y, .month = m, .day = D, .hour = H, .minute = M, .second = S }); + if (secondsSince_Time(&now, &item.when) > maxAgeVisited_Visited_) { + continue; /* Too old. */ + } + initRange_String(&item.url, (iRangecc){ line.start + 20, line.end }); + insert_SortedArray(&d->visited, &item); + } + } + iRelease(f); +} + +void clear_Visited(iVisited *d) { + iForEach(Array, v, &d->visited.values) { + deinit_VisitedUrl(v.value); + } + clear_SortedArray(&d->visited); +} + +void visitUrl_Visited(iVisited *d, const iString *url) { + iVisitedUrl visit; + init_VisitedUrl(&visit); + set_String(&visit.url, url); + size_t pos; + if (locate_SortedArray(&d->visited, &visit, &pos)) { + iVisitedUrl *old = at_SortedArray(&d->visited, pos); + if (cmpNewer_VisitedUrl_(&visit, old)) { + old->when = visit.when; + deinit_VisitedUrl(&visit); + return; + } + } + insert_SortedArray(&d->visited, &visit); +} + +iTime urlVisitTime_Visited(const iVisited *d, const iString *url) { + iVisitedUrl item; + size_t pos; + iZap(item); + initCopy_String(&item.url, url); + if (locate_SortedArray(&d->visited, &item, &pos)) { + item.when = ((const iVisitedUrl *) constAt_SortedArray(&d->visited, pos))->when; + } + deinit_String(&item.url); + return item.when; +} diff --git a/src/visited.h b/src/visited.h new file mode 100644 index 00000000..2f8382c7 --- /dev/null +++ b/src/visited.h @@ -0,0 +1,25 @@ +#pragma once + +#include "gmrequest.h" + +#include +#include +#include + +iDeclareType(VisitedUrl) +iDeclareTypeConstruction(VisitedUrl) + +struct Impl_VisitedUrl { + iString url; + iTime when; +}; + +iDeclareType(Visited) +iDeclareTypeConstruction(Visited) + +void clear_Visited (iVisited *); +void load_Visited (iVisited *, const char *dirPath); +void save_Visited (const iVisited *, const char *dirPath); + +iTime urlVisitTime_Visited (const iVisited *, const iString *url); +void visitUrl_Visited (iVisited *, const iString *url); /* adds URL to the visited URLs set */ -- cgit v1.2.3