commit: 762f699595ad4d340d89434d0e2260e7329b7a2b
parent: f365a16b73bc181f503278e2e0523891187d5394
author: Chris Noxz <chris@noxz.tech>
date: Sat, 20 Jan 2024 20:20:00 +0100
add about:(config|memory) feature
3 files changed, 185 insertions(+), 23 deletions(-)
diff --git a/browser.c b/browser.c
@@ -20,6 +20,93 @@
#include "config.h"
+void
+about_scheme_request(WebKitURISchemeRequest *request,
+ gpointer data)
+{
+ (void) data;
+
+ GError *e; /* error holder */
+ GInputStream *s; /* stream to send */
+ GString *m; /* message of stream */
+ const gchar *p; /* path holder eg. 'config' */
+ gchar **w; /* temporary word holder */
+ gsize sl; /* size of stream */
+ int st[4] = {0}; /* memory stats */
+
+ p = webkit_uri_scheme_request_get_path(request);
+
+ /* about:config */
+ if (!strcmp(p, "config")) {
+ g_string_append_printf((m = g_string_new(NULL)), "<html><body>"
+ "<table style=\"width:100%%;\">"
+ "<tr>"
+ "<th align=\"left\">Configurable Name</th>"
+ "<th align=\"left\">Value</th>"
+ "</tr>"
+ "<tr><td>"__NAME__" version</td><td>%s</td></tr>"
+ "<tr><td>WebKit version</td><td>%u.%u.%u</td></tr>",
+ VERSION,
+ webkit_get_major_version(),
+ webkit_get_minor_version(),
+ webkit_get_micro_version());
+ for (int i = 0; i < LastConfig; i++) {
+ if (cfg[i].e == NULL)
+ continue;
+ g_string_append_printf(m, "<tr><td>%s</td><td>", cfg[i].e);
+ switch (cfg[i].t) {
+ case CFG_STRING:
+ g_string_append_printf(m, "%s", cfg[i].v.s);
+ break;
+ case CFG_INT:
+ g_string_append_printf(m, "%d", cfg[i].v.i);
+ break;
+ case CFG_FLOAT:
+ g_string_append_printf(m, "%f", cfg[i].v.f);
+ break;
+ case CFG_BOOL:
+ g_string_append_printf(m, "%s", cfg[i].v.b ? "TRUE" : "FALSE");
+ break;
+ case CFG_LIST:
+ for (w = cfg[i].v.l; w && *w; w++)
+ g_string_append_printf(m, "%s%s", w == cfg[i].v.l
+ ? "" : "; ", *w);
+ break;
+ }
+ g_string_append_printf(m, "</td></tr>");
+ }
+ g_string_append_printf(m, "</table>");
+ g_string_append_printf(m, "</body></html>");
+ /* about:memory (only exists if memory can be read) */
+ } else if (!strcmp(p, "memory")
+ && get_memory(&(st[0]), &(st[1]), &(st[2]), &(st[3]))) {
+ g_string_append_printf((m = g_string_new(NULL)), "<html><body>"
+ "<table style=\"width:100%%;\">"
+ "<tr><td>current real memory</td><td>%'d kB</tr>"
+ "<tr><td>peak real memory</td><td>%'d kB</tr>"
+ "<tr><td>current virt memory</td><td>%'d kB</tr>"
+ "<tr><td>peak virt memory</td><td>%'d kB</tr>"
+ "</table>"
+ "</body></html>",
+ st[0], st[1], st[2], st[3]
+ );
+ } else {
+ webkit_uri_scheme_request_finish_error(request, (e = g_error_new(
+ BROWSER_ERROR,
+ BROWSER_ERROR_INVALID_ABOUT_PATH,
+ "Invalid 'about:%s' page", p)));
+ g_error_free(e);
+ return;
+ }
+
+ sl = strlen(m->str);
+ s = g_memory_input_stream_new_from_data(m->str, sl, NULL);
+ webkit_uri_scheme_request_finish(request, s, sl, "text/html");
+ g_object_unref(s);
+ g_string_free(m, TRUE);
+}
+
+
struct Client*
client_create(const gchar *uri,
WebKitWebView *related_wv,
@@ -288,6 +375,48 @@ die(const char *msg)
exit(EXIT_FAILURE);
}
+int
+get_memory(int *cr, /* current real memory */
+ int *pr, /* peak real memory */
+ int *cv, /* current virtual memory */
+ int *pv) /* peak virtual memory */
+{
+ char b[256] = {0};
+ FILE *f;
+
+ *cr = *pr = *cv = *pv = -1;
+
+ if (!(f = fopen("/proc/self/status", "r")))
+ return 0;
+
+ while (fscanf(f, " %255s", b) == 1)
+ if (!strcmp(b, "VmRSS:"))
+ fscanf(f, " %d", cr);
+ else if (!strcmp(b, "VmHWM:"))
+ fscanf(f, " %d", pr);
+ else if (!strcmp(b, "VmSize:"))
+ fscanf(f, " %d", cv);
+ else if (!strcmp(b, "VmPeak:"))
+ fscanf(f, " %d", pv);
+ fclose(f);
+
+ return (*cr != -1 && *pr != -1 && *cv != -1 && *pv != -1);
+}
+
+gchar*
+get_uri(GtkWidget* wv)
+{
+ const gchar *u;
+
+ if (!(u = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(wv))))
+ return NULL;
+
+ if (!strncmp(u, ABOUT_SCHEME":", strlen(ABOUT_SCHEME":")))
+ return g_strconcat("about:", u + strlen(ABOUT_SCHEME":"), NULL);
+
+ return g_strdup(u);
+}
+
gboolean
ipc_request(GIOChannel *src,
GIOCondition condition,
@@ -512,9 +641,9 @@ gboolean
key_entry(struct Client *c,
GdkEventKey *event)
{
- const gchar *t,
- *l;
- gchar *u = NULL;
+ const gchar *t;
+ gchar *u = NULL,
+ *l = NULL;
int p,
m;
@@ -546,22 +675,25 @@ key_entry(struct Client *c,
return TRUE;
if (t[0] != ':') { /* if not a command */
/* store current uri before loading new uri */
- l = WV_GET_URI(c->wv);
+ l = get_uri(c->wv);
if ((u = resolve_uri(t)) != NULL)
webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->wv), u);
g_free(u);
/* fix: notify::uri won't be raised if current uri is unchanged */
- if (g_strcmp0(l, WV_GET_URI(c->wv)) == 0)
+ if (!strcmp(l, (u = get_uri(c->wv))))
uri_changed(c);
+ g_free(u);
+ g_free(l);
return TRUE;
} else if (command(c, t + 1)) { /* if command */
return TRUE;
} /* FALL THROUGH */
case GDK_KEY_Escape:
gtk_widget_grab_focus(c->wv);
- t = WV_GET_URI(c->wv);
- gtk_entry_set_text(GTK_ENTRY(c->entry), (t == NULL ? __NAME__ : t));
+ u = get_uri(c->wv);
+ gtk_entry_set_text(GTK_ENTRY(c->entry), (u == NULL ? __NAME__ : u));
gtk_editable_set_position(GTK_EDITABLE(c->entry), -1);
+ g_free(u);
return TRUE;
}
return FALSE;
@@ -1053,6 +1185,7 @@ save_state(void)
FILE *fp;
WebKitWebView *wv;
WebKitSettings *s;
+ gchar *u = NULL;
/* only save state for ipc host, when state isn't locked for loading */
if (CFG_S(StateFile) == NULL || gl.ipc != IPC_HOST || gl.state_lock)
@@ -1068,7 +1201,7 @@ save_state(void)
c = gtk_container_get_children(
GTK_CONTAINER(gtk_notebook_get_nth_page(GTK_NOTEBOOK(mw.nb), i))
);
- if (strcmp(gtk_widget_get_name((c->data)), "WebKitWebView") != 0)
+ if (strcmp(gtk_widget_get_name((c->data)), "WebKitWebView"))
continue;
wv = WEBKIT_WEB_VIEW(c->data);
s = webkit_web_view_get_settings(wv);
@@ -1077,7 +1210,8 @@ save_state(void)
x |= STATE_CURRENT;
if (webkit_settings_get_enable_javascript_markup(s))
x |= STATE_JAVASCRIPT;
- fprintf(fp, "%d:%s\n", x, WV_GET_URI(wv));
+ fprintf(fp, "%d:%s\n", x, (u = get_uri((GtkWidget*)wv)));
+ g_free(u);
}
fclose(fp);
@@ -1173,6 +1307,10 @@ set_default_web_context(void)
CB(c, "download-started", cb_download_start, NULL);
webkit_web_context_set_favicon_database_directory(c, NULL);
+ webkit_web_context_register_uri_scheme(
+ c, ABOUT_SCHEME, (WebKitURISchemeRequestCallback)about_scheme_request,
+ NULL, NULL
+ );
g_free(p);
}
@@ -1182,6 +1320,7 @@ set_hover_uri(struct Client *c,
WebKitHitTestResult *hit_test_result)
{
const char *t; /* entry text holder */
+ gchar *u = NULL; /* uri text holder */
g_free(c->hover_uri);
@@ -1190,12 +1329,14 @@ set_hover_uri(struct Client *c,
t = webkit_hit_test_result_get_link_uri(hit_test_result);
c->hover_uri = g_strdup(t);
} else {
- t = WV_GET_URI(c->wv);
+ u = get_uri(c->wv);
c->hover_uri = NULL;
}
if (!gtk_widget_is_focus(c->entry))
- gtk_entry_set_text(GTK_ENTRY(c->entry), t);
+ gtk_entry_set_text(GTK_ENTRY(c->entry), u ? u : t);
+
+ g_free(u);
}
void
@@ -1288,11 +1429,14 @@ resolve_uri(const gchar *t)
int r = -1; /* result holder for wordexp */
/* cannot expand string in file scheme, so try without scheme */
- if (strncmp("file://", t, 6) == 0 && (t[7] == '~' || t[7] == '$'))
+ if (!strncmp("file://", t, 7) && (t[7] == '~' || t[7] == '$'))
return resolve_uri(t + 7);
+ /* use internal about page so that about: prefix is ignored by WebKit */
+ if (!strncmp(t, "about:", 6) && strcmp(t, "about:blank"))
+ u = g_strdup_printf(ABOUT_SCHEME":%s", t + 6);
/* check if valid scheme, and if so just create a copy of the text */
- if ((s = g_uri_peek_scheme(t)) && g_strv_contains(CFG_L(UriSchemes), s))
+ else if ((s = g_uri_peek_scheme(t)) && g_strv_contains(CFG_L(UriSchemes), s))
u = g_strdup(t);
/* if no match, then test xdg schemes (schemes that are redirected) */
else if (s && CFG_L(XdgSchemes) && g_strv_contains(CFG_L(XdgSchemes), s))
@@ -1422,11 +1566,11 @@ update_load_progress(struct Client *c)
void
update_title(struct Client *c)
{
- const gchar *t,
+ const gchar *t;
+ gchar *m = NULL,
*u;
- gchar *m = NULL;
- u = WV_GET_URI(c->wv);
+ u = get_uri(c->wv);
t = webkit_web_view_get_title(WEBKIT_WEB_VIEW(c->wv));
/* title priority: title, url, __NAME__ */
@@ -1455,31 +1599,36 @@ update_title(struct Client *c)
gtk_widget_set_tooltip_text(c->tab_label, t);
set_window_title(gtk_notebook_get_current_page(GTK_NOTEBOOK(mw.nb)));
g_free(m);
+ g_free(u);
}
void
uri_changed(struct Client *c)
{
- const gchar *t;
+ gchar *t = NULL;
/* make sure to not overwrite the "WEB PROCESS CRASHED" message */
- if ((t = WV_GET_URI(c->wv)) != NULL && strlen(t) > 0) {
+ if ((t = get_uri(c->wv)) != NULL && strlen(t) > 0) {
gtk_entry_set_text(GTK_ENTRY(c->entry), t);
save_history(t);
save_state();
}
+
+ g_free(t);
}
void
web_view_crashed(struct Client *c)
{
- gchar *t = NULL;
+ gchar *t = NULL,
+ *u = NULL;
gtk_entry_set_text(
GTK_ENTRY(c->entry),
- (t = g_strdup_printf("WEB PROCESS CRASHED: %s", WV_GET_URI(c->wv)))
+ (t = g_strdup_printf("WEB PROCESS CRASHED: %s", (u = get_uri(c->wv))))
);
g_free(t);
+ g_free(u);
}
void
@@ -1522,7 +1671,7 @@ main(int argc, char **argv)
if (optind >= argc && gl.clients == 0)
client_create(CFG_S(HomeUri), NULL, TRUE, TRUE);
/* load stdin if first argument is '-' */
- if (optind < argc && strcmp(argv[optind], "-") == 0)
+ if (optind < argc && !strcmp(argv[optind], "-"))
load_stdin();
/* load remaining command line arguments as uris into new clients */
else if (optind < argc)
diff --git a/browser.h b/browser.h
@@ -57,7 +57,6 @@
#define CFG_I(X) cfg[(X)].v.i
#define CFG_L(X) (const gchar* const*)cfg[(X)].v.l
#define CFG_S(X) cfg[(X)].v.s
-#define WV_GET_URI(X) webkit_web_view_get_uri(WEBKIT_WEB_VIEW((X)))
#define TLS_MSG_FORMAT "<h2>Could not validate TLS for: %s</h2><pre>%s" \
"</pre><pre>s:%s\ni:%s\nv:NotBefore:%s; NotAfter:" \
@@ -87,6 +86,8 @@
#define XDG_OPEN "xdg-open"
#define STATE_CURRENT 1 << 0
#define STATE_JAVASCRIPT 1 << 1
+#define BROWSER_ERROR (browser_error_quark())
+#define ABOUT_SCHEME __NAME__"-about"
enum javascript_policy {
JSP_DISABLE = 0,
@@ -157,6 +158,15 @@ enum config_name {
LastConfig
};
+enum browser_error {
+ BROWSER_ERROR_INVALID_ABOUT_PATH
+};
+
+static GQuark browser_error_quark()
+{
+ return g_quark_from_string(__NAME__"-quark");
+}
+
typedef union {
gint i; /* union integer */
gdouble f; /* union float/double */
@@ -206,6 +216,7 @@ struct MainWindow
} mw;
/* "normal" functions */
+static void about_scheme_request(WebKitURISchemeRequest *, gpointer);
static struct Client *client_create(const gchar *, WebKitWebView *, gboolean,
gboolean);
static void client_destroy(struct Client *);
@@ -215,6 +226,8 @@ static void create_context_menu(struct Client *, WebKitContextMenu *,
static void create_context_menu_item(struct Client *, WebKitContextMenu *,
const gchar *, const gchar *, void *);
static void die(const char *);
+static int get_memory(int *, int *, int *, int *);
+static gchar *get_uri(GtkWidget*);
static gboolean ipc_request(GIOChannel *, GIOCondition, gpointer);
static ssize_t ipc_send(char *);
static void ipc_setup(void);
diff --git a/config.h b/config.h
@@ -52,7 +52,7 @@ static Config cfg[LastConfig] = {
[SmoothScrolling] = { __NAME_UPPERCASE__"_ENABLE_SMOOTH_SCROLLING", "enable-smooth-scrolling", CFG_BOOL, FALSE, {.b = FALSE }},
[StateFile] = { __NAME_UPPERCASE__"_STATE_FILE", NULL, CFG_STRING, FALSE, {.s = NULL }},
[UcDir] = { NULL, NULL, CFG_STRING, FALSE, {.s = "styles" }},
- [UriSchemes] = { NULL, NULL, CFG_LIST, FALSE, {.l = (gchar*[]){ "http", "https", "file", "about", "data", "webkit", NULL } }},
+ [UriSchemes] = { NULL, NULL, CFG_LIST, FALSE, {.l = (gchar*[]){ "http", "https", "file", "about", __NAME__"-about", "data", "webkit", NULL } }},
[UsDir] = { NULL, NULL, CFG_STRING, FALSE, {.s = "scripts" }},
[UserAgent] = { __NAME_UPPERCASE__"_USER_AGENT", "user-agent", CFG_STRING, FALSE, {.s = NULL }},
[WeDir] = { NULL, NULL, CFG_STRING, FALSE, {.s = "web_extensions" }},