diff options
author | Marco Peereboom <marco@conformal.com> | 2011-12-28 13:38:37 -0600 |
---|---|---|
committer | Marco Peereboom <marco@conformal.com> | 2011-12-28 13:41:23 -0600 |
commit | 748728177d5afa65af189ca1b50523a6b0d431e3 (patch) | |
tree | e36688de737ab6140c28ac1b7c877320792fdb98 | |
parent | f6a3ffaf8264b9c7d5bfa2747fce9bdd5531dc1d (diff) | |
download | xombrero-748728177d5afa65af189ca1b50523a6b0d431e3.tar.gz |
Add link coloring after visiting it.
Work around for bug #51747 from Stevan Andjelkovic <stevan.andjelkovic@strath.ac.uk>
-rw-r--r-- | about.c | 5 | ||||
-rw-r--r-- | settings.c | 2 | ||||
-rw-r--r-- | xxxterm.1 | 17 | ||||
-rw-r--r-- | xxxterm.c | 230 | ||||
-rw-r--r-- | xxxterm.conf | 1 | ||||
-rw-r--r-- | xxxterm.h | 10 |
6 files changed, 209 insertions, 56 deletions
diff --git a/about.c b/about.c index 744a870..3df1795 100644 --- a/about.c +++ b/about.c @@ -1265,7 +1265,7 @@ xtp_page_hl(struct tab *t, struct karg *args) /* body */ body = g_strdup_printf("<table style='table-layout:fixed'><tr>" - "<th>URI</th><th>Title</th><th style='width: 40px'>Rm</th></tr>\n"); + "<th>URI</th><th>Title</th><th>Last visited</th><th style='width: 40px'>Rm</th></tr>\n"); RB_FOREACH_REVERSE(h, history_list, &hl) { tmp = body; @@ -1273,9 +1273,10 @@ xtp_page_hl(struct tab *t, struct karg *args) "%s\n<tr>" "<td><a href='%s'>%s</a></td>" "<td>%s</td>" + "<td>%s</td>" "<td style='text-align: center'>" "<a href='%s%d/%s/%d/%d'>X</a></td></tr>\n", - body, h->uri, h->uri, h->title, + body, h->uri, h->uri, h->title, ctime(&h->time), XT_XTP_STR, XT_XTP_HL, hl_session_key, XT_XTP_HL_REMOVE, i); diff --git a/settings.c b/settings.c index d1de255..04d8e91 100644 --- a/settings.c +++ b/settings.c @@ -68,6 +68,7 @@ char *http_proxy = NULL; char download_dir[PATH_MAX]; char runtime_settings[PATH_MAX]; /* override of settings */ int allow_volatile_cookies = 0; +int color_visited_uris = 1; int save_global_history = 0; /* save global history to disk */ char *user_agent = NULL; int save_rejected_cookies = 0; @@ -243,6 +244,7 @@ struct settings rs[] = { { "append_next", XT_S_INT, 0, &append_next, NULL, NULL }, { "autofocus_onload", XT_S_INT, 0, &autofocus_onload, NULL, NULL }, { "browser_mode", XT_S_INT, 0, NULL, NULL,&s_browser_mode }, + { "color_visited_uris", XT_S_INT, 0, &color_visited_uris, NULL, NULL }, { "cookie_policy", XT_S_INT, 0, NULL, NULL,&s_cookie }, { "cookies_enabled", XT_S_INT, 0, &cookies_enabled, NULL, NULL }, { "ctrl_click_focus", XT_S_INT, 0, &ctrl_click_focus, NULL, NULL }, diff --git a/xxxterm.1 b/xxxterm.1 index fdc0643..4e33ae2 100644 --- a/xxxterm.1 +++ b/xxxterm.1 @@ -940,6 +940,15 @@ See the default config file for more details. Set the command prompt font. E.g. .Pa cmd_font = monospace normal 9 . +.It Cm color_visited_uris +When enabled (the default) +.Nm +will color visited links. This is done while the web page loads using +JavaScript, rather than WebKit's (broken, see bug #51747) built-in +facility for coloring visited links. The JavaScript approach is +(probably) slower and is not consistent across tabs (unless the tabs are +reloaded), but has the advantage of not leaking history data to web +pages (see http://wtikay.com/docs/details.html). .It Cm cookie_policy This field delineates the cookie policy. Possible values are: no3rdparty, reject 3rd party cookies. @@ -1235,11 +1244,3 @@ was written by .An Raphael Graf Aq r@undefined.ch , and .An Michal Mazurek Aq akfaew@jasminek.net . -.Sh BUGS -When -.Cm save_global_history -is enabled -.Nm -is supposed to, in addition to restoring the global history, color the -visited links accordingly; however due to bug #51747 in WebKit this does -not happen. diff --git a/xxxterm.c b/xxxterm.c index bf2198c..fddf269 100644 --- a/xxxterm.c +++ b/xxxterm.c @@ -23,8 +23,9 @@ char *version = XXXTERM_VERSION; -#ifdef XT_DEBUG +/*#ifdef XT_DEBUG*/ u_int32_t swm_debug = 0 +/* | XT_D_MOVE | XT_D_KEY | XT_D_TAB @@ -41,6 +42,9 @@ u_int32_t swm_debug = 0 | XT_D_CLIP | XT_D_BUFFERCMD | XT_D_INSPECTOR +*/ + | XT_D_VISITED + | XT_D_HISTORY ; #endif @@ -95,6 +99,11 @@ TAILQ_HEAD(command_list, command_entry); #define XT_DLMAN_REFRESH "10" #define XT_MAX_URL_LENGTH (4096) /* 1 page is atomic, don't make bigger */ #define XT_MAX_UNDO_CLOSE_TAB (32) +#define XT_MAX_HL_PURGE_COUNT (1000) /* Purge the history for every + * MAX_HL_PURGE_COUNT items inserted into + * history and delete all items older + * than MAX_HISTORY_AGE. */ +#define XT_MAX_HISTORY_AGE (60.0 * 60.0 * 24 * 14) /* 14 days */ #define XT_RESERVED_CHARS "$&+,/:;=?@ \"<>#%%{}|^~[]`" #define XT_PRINT_EXTRA_MARGIN 10 #define XT_URL_REGEX ("^[[:blank:]]*[^[:blank:]]*([[:alnum:]-]+\\.)+[[:alnum:]-][^[:blank:]]*[[:blank:]]*$") @@ -223,6 +232,7 @@ GtkWidget *tab_bar; GtkWidget *arrow, *abtn; struct tab_list tabs; struct history_list hl; +int hl_purge_count = 0; struct session_list sessions; struct domain_list c_wl; struct domain_list js_wl; @@ -828,7 +838,7 @@ get_uri(struct tab *t) const gchar *uri = NULL; if (webkit_web_view_get_load_status(t->wv) == WEBKIT_LOAD_FAILED) - return NULL; + return (NULL); if (t->xtp_meaning == XT_XTP_TAB_MEANING_NORMAL) { uri = webkit_web_view_get_uri(t->wv); } else { @@ -1048,18 +1058,75 @@ userstyle(struct tab *t, struct karg *args) return (0); } -/* - * Doesn't work fully, due to the following bug: - * https://bugs.webkit.org/show_bug.cgi?id=51747 - */ +int +purge_history(void) +{ + struct history *h, *next; + double age = 0.0; + + DNPRINTF(XT_D_HISTORY, "%s: hl_purge_count = %d (%d is max)\n", + __func__, hl_purge_count, XT_MAX_HL_PURGE_COUNT); + + if (hl_purge_count == XT_MAX_HL_PURGE_COUNT) { + hl_purge_count = 0; + + for (h = RB_MIN(history_list, &hl); h != NULL; h = next) { + + next = RB_NEXT(history_list, &hl, h); + + age = difftime(time(NULL), h->time); + + if (age > XT_MAX_HISTORY_AGE) { + DNPRINTF(XT_D_HISTORY, "%s: removing %s (age %.1f)\n", + __func__, h->uri, age); + + RB_REMOVE(history_list, &hl, h); + g_free(h->uri); + g_free(h->title); + g_free(h); + } else { + DNPRINTF(XT_D_HISTORY, "%s: keeping %s (age %.1f)\n", + __func__, h->uri, age); + } + } + } + + return (0); +} + +int +insert_history_item(const gchar *uri, const gchar *title, time_t time) +{ + struct history *h; + + if (!(uri && strlen(uri) && title && strlen(title))) + return (1); + + h = g_malloc(sizeof(struct history)); + h->uri = g_strdup(uri); + h->title = g_strdup(title); + h->time = time; + + DNPRINTF(XT_D_HISTORY, "%s: adding %s\n", __func__, h->uri); + + RB_INSERT(history_list, &hl, h); + completion_add_uri(h->uri); + hl_purge_count++; + + purge_history(); + update_history_tabs(NULL); + + return (0); +} + int restore_global_history(void) { char file[PATH_MAX]; FILE *f; - struct history *h; - gchar *uri; - gchar *title; + gchar *uri, *title, *stime, *err = NULL; + time_t time; + struct tm tm; const char delim[3] = {'\\', '\\', '\0'}; snprintf(file, sizeof file, "%s/%s", work_dir, XT_HISTORY_FILE); @@ -1076,29 +1143,44 @@ restore_global_history(void) if ((title = fparseln(f, NULL, NULL, delim, 0)) == NULL) if (feof(f) || ferror(f)) { - free(uri); - warnx("%s: broken history file\n", __func__); - return (1); + err = "broken history file (title)"; + goto done; } - if (uri && strlen(uri) && title && strlen(title)) { - webkit_web_history_item_new_with_data(uri, title); - h = g_malloc(sizeof(struct history)); - h->uri = g_strdup(uri); - h->title = g_strdup(title); - RB_INSERT(history_list, &hl, h); - completion_add_uri(h->uri); - } else { - warnx("%s: failed to restore history\n", __func__); - free(uri); - free(title); - return (1); + if ((stime = fparseln(f, NULL, NULL, delim, 0)) == NULL) + if (feof(f) || ferror(f)) { + err = "broken history file (time)"; + goto done; + } + + if (strptime(stime, "%a %b %d %H:%M:%S %Y", &tm) == NULL) { + err = "strptime failed to parse time"; + goto done; + } + + time = mktime(&tm); + + if (insert_history_item(uri, title, time)) { + err = "failed to insert item"; + goto done; } free(uri); free(title); + free(stime); uri = NULL; title = NULL; + stime = NULL; + } + +done: + if (err && strlen(err)) { + warnx("%s: %s\n", __func__, err); + free(uri); + free(title); + free(stime); + + return (1); } return (0); @@ -1120,8 +1202,9 @@ save_global_history_to_disk(struct tab *t) } RB_FOREACH_REVERSE(h, history_list, &hl) { - if (h->uri && h->title) - fprintf(f, "%s\n%s\n", h->uri, h->title); + if (h->uri && h->title && h->time) + fprintf(f, "%s\n%s\n%s", h->uri, h->title, + ctime(&h->time)); } fclose(f); @@ -1311,6 +1394,62 @@ save_tabs_and_quit(struct tab *t, struct karg *args) return (1); } +/* Marshall the internal record of visited URIs into a Javascript hash table in + * string form. */ +char * +color_visited_helper(void) +{ + char *s = NULL; + struct history *h; + + RB_FOREACH_REVERSE(h, history_list, &hl) { + if (s == NULL) + s = g_strdup_printf("'%s':'dummy'", h->uri); + else + s = g_strjoin(",", s, + g_strdup_printf("'%s':'dummy'", h->uri), NULL); + } + + s = g_strdup_printf("{%s}", s); + + DNPRINTF(XT_D_VISITED, "%s: s = %s\n", __func__, s); + + return (s); +} + +int +color_visited(struct tab *t, char *visited) +{ + char *s; + + if (t == NULL || visited == NULL) { + show_oops(NULL, "%s: invalid parameters", __func__); + return (1); + } + + /* Create a string representing an annonymous Javascript function, which + * takes a hash table of visited URIs as an argument, goes through the + * links at the current web page and colors them if they indeed been + * visited. + */ + s = g_strconcat( + "(function(visitedUris) {", + " for (var i = 0; i < document.links.length; i++)", + " if (visitedUris[document.links[i].href])", + " document.links[i].style.color = 'purple';", + "})", + /* Apply the annonymous function to the hash table containing + * visited URIs. */ + g_strdup_printf("(%s);", visited), + NULL); + + run_script(t, s); + g_free(s); + g_free(visited); + + return (0); +} + int run_page_script(struct tab *t, struct karg *args) { @@ -3738,7 +3877,7 @@ notify_icon_loaded_cb(WebKitWebView *wv, gchar *uri, struct tab *t) void notify_load_status_cb(WebKitWebView* wview, GParamSpec* pspec, struct tab *t) { - const gchar *uri = NULL, *title = NULL; + const gchar *uri = NULL; struct history *h, find; struct karg a; GdkColor color; @@ -3817,28 +3956,33 @@ notify_load_status_cb(WebKitWebView* wview, GParamSpec* pspec, struct tab *t) case WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT: /* 3 */ + if (color_visited_uris) { + color_visited(t, color_visited_helper()); + + /* This colors the links you middle-click (open in new + * tab) in the current tab. */ + if (t->tab_id != gtk_notebook_get_current_page(notebook) && + (uri = get_uri(t)) != NULL) + color_visited(get_current_tab(), + g_strdup_printf("{'%s' : 'dummy'}", uri)); + } break; case WEBKIT_LOAD_FINISHED: /* 2 */ - uri = get_uri(t); - if (uri == NULL) + if ((uri = get_uri(t)) == NULL) return; if (!strncmp(uri, "http://", strlen("http://")) || !strncmp(uri, "https://", strlen("https://")) || !strncmp(uri, "file://", strlen("file://"))) { - find.uri = uri; + find.uri = (gchar *)uri; h = RB_FIND(history_list, &hl, &find); - if (!h) { - title = get_title(t, FALSE); - h = g_malloc(sizeof *h); - h->uri = g_strdup(uri); - h->title = g_strdup(title); - RB_INSERT(history_list, &hl, h); - completion_add_uri(h->uri); - update_history_tabs(NULL); - } + if (!h) + insert_history_item(uri, + get_title(t, FALSE), time(NULL)); + else + h->time = time(NULL); } set_status(t, (char *)uri, XT_STATUS_URI); @@ -4858,13 +5002,13 @@ wv_keypress_cb(GtkEntry *w, GdkEventKey *e, struct tab *t) /* don't use w directly; use t->whatever instead */ if (t == NULL) { - show_oops(NULL, "wv_keypress_after_cb"); + show_oops(NULL, "wv_keypress_cb"); return (XT_CB_PASSTHROUGH); } hide_oops(t); - DNPRINTF(XT_D_KEY, "wv_keypress_after_cb: mode %d keyval 0x%x mask " + DNPRINTF(XT_D_KEY, "wv_keypress_cb: mode %d keyval 0x%x mask " "0x%x tab %d\n", t->mode, e->keyval, e->state, t->tab_id); /* Hide buffers, if they are visible, with escape. */ @@ -4890,7 +5034,7 @@ wv_keypress_cb(GtkEntry *w, GdkEventKey *e, struct tab *t) /* XXX make sure cmd entry is enabled */ return (XT_CB_HANDLED); } else if (t->mode == XT_MODE_COMMAND) { - /* prefix input*/ + /* prefix input */ snprintf(s, sizeof s, "%c", e->keyval); if (CLEAN(e->state) == 0 && isdigit(s[0])) cmd_prefix = 10 * cmd_prefix + atoi(s); @@ -5923,7 +6067,7 @@ create_buffers(struct tab *t) gtk_tree_view_set_model (GTK_TREE_VIEW(view), GTK_TREE_MODEL(buffers_store)); - return view; + return (view); } void diff --git a/xxxterm.conf b/xxxterm.conf index 8fb1098..451ab89 100644 --- a/xxxterm.conf +++ b/xxxterm.conf @@ -20,6 +20,7 @@ # enable_socket = 0 # enable_localstorage = 0 # single_instance = 0 +# color_visited_uris = 1 # save_global_history = 0 # show_tabs = 1 # statusbar_elems = BP diff --git a/xxxterm.h b/xxxterm.h index 49b281b..a721183 100644 --- a/xxxterm.h +++ b/xxxterm.h @@ -108,7 +108,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*#define XT_DEBUG*/ +#define XT_DEBUG #ifdef XT_DEBUG #define DPRINTF(x...) do { if (swm_debug) fprintf(stderr, x); } while (0) #define DNPRINTF(n,x...) do { if (swm_debug & n) fprintf(stderr, x); } while (0) @@ -128,6 +128,8 @@ THE SOFTWARE. #define XT_D_CLIP 0x2000 #define XT_D_BUFFERCMD 0x4000 #define XT_D_INSPECTOR 0x8000 +#define XT_D_VISITED 0x10000 +#define XT_D_HISTORY 0x20000 extern u_int32_t swm_debug; #else #define DPRINTF(x...) @@ -252,8 +254,9 @@ RB_PROTOTYPE(download_list, download, entry, download_rb_cmp); struct history { RB_ENTRY(history) entry; - const gchar *uri; - const gchar *title; + gchar *uri; + gchar *title; + time_t time; /* When the item was added. */ }; RB_HEAD(history_list, history); RB_PROTOTYPE(history_list, history, entry, history_rb_cmp); @@ -511,6 +514,7 @@ extern char *http_proxy; extern char download_dir[PATH_MAX]; extern char runtime_settings[PATH_MAX]; extern int allow_volatile_cookies; +extern int color_visited_uris; extern int save_global_history; extern char *user_agent; extern int save_rejected_cookies; |