Summary Files Commits Branches @commit @diff @stats
path: root / badwolf.c
diff options
context:
space:
mode:
1 files changed, 201 insertions, 4 deletions
-rw-r--r--badwolf.c205
diff --git a/badwolf.c b/badwolf.c
index 475cc28..b91d4da 100644
--- a/badwolf.c
+++ b/badwolf.c
@@ -8,8 +8,12 @@
#include <glib/gprintf.h> /* g_fprintf() */
#include <gtk/gtk.h>
#include <locale.h> /* LC_* */
+#include <stdlib.h> /* realpath() */
#include <webkit2/webkit2.h>
+const gchar *homepage = "https://hacktivis.me/projects/badwolf";
+const gchar *version = "0.2.0";
+
struct Window
{
GtkWidget *main_window;
@@ -33,7 +37,15 @@ struct Client
GtkWidget *search;
};
+gchar *ensure_uri_scheme(gchar *text, gboolean try_file);
static gboolean WebViewCb_close(WebKitWebView *webView, gpointer user_data);
+static gboolean
+commonCb_key_press_event(struct Window *window, GdkEvent *event, struct Client *browser);
+static gboolean
+WebViewCb_key_press_event(WebKitWebView *webView, GdkEvent *event, gpointer user_data);
+static gboolean
+main_windowCb_key_press_event(GtkWidget *widget, GdkEvent *event, gpointer user_data);
+static gboolean boxCb_key_press_event(GtkWidget *widget, GdkEvent *event, gpointer user_data);
static gboolean WebViewCb_web_process_terminated(WebKitWebView *webView,
WebKitWebProcessTerminationReason reason,
gpointer user_data);
@@ -70,6 +82,49 @@ static void
notebookCb_switch__page(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data);
gint get_tab_position(GtkContainer *notebook, GtkWidget *child);
+gchar *
+ensure_uri_scheme(gchar *text, gboolean try_file)
+{
+ if(text == NULL) return "about:blank";
+
+ char *scheme = g_uri_parse_scheme(text);
+
+ if(scheme != NULL) return text;
+
+ if(try_file)
+ {
+ gchar *f;
+ char *path;
+ path = realpath(text, NULL);
+
+ if(path != NULL)
+ {
+ f = g_strdup_printf("file://%s", path);
+ free(path);
+ return f;
+ }
+ }
+
+ return g_strdup_printf("http://%s", text);
+}
+
+static void
+badwolf_about_dialog(GtkWindow *main_window)
+{
+ // clang-format off
+ gtk_show_about_dialog(
+ main_window,
+ "license", "SPDX-License-Identifier: BSD-3-Clause",
+ "copyright", "2019 Haelwenn (lanodan) Monnier <contact+badwolf@hacktivis.me>",
+ "website", homepage,
+ "comments", "Minimalist and privacy-oriented WebKitGTK+ browser",
+ "version", version,
+ //FIXME: "logo-icon-name", g_get_application_name(),
+ NULL
+ );
+ // clang-format on
+}
+
static gboolean
WebViewCb_close(WebKitWebView *webView, gpointer user_data)
{
@@ -86,6 +141,113 @@ WebViewCb_close(WebKitWebView *webView, gpointer user_data)
return TRUE;
}
+/* commonCb_key_press_event: Global callback for keybindings
+ *
+ * Theses shortcuts should be avoided as much as possible:
+ * - Single key shortcuts (ie. backspace and space)
+ * - Triple key shortcuts (except for Ctrl+Shift)
+ * - Unix Terminal shortcuts (specially Ctrl-W)
+ *
+ * loosely follows https://developer.gnome.org/hig/stable/keyboard-input.html
+ */
+static gboolean
+commonCb_key_press_event(struct Window *window, GdkEvent *event, struct Client *browser)
+{
+ GtkNotebook *notebook = GTK_NOTEBOOK(window->notebook);
+
+ if(((GdkEventKey *)event)->state & GDK_CONTROL_MASK)
+ {
+ if(browser != NULL)
+ {
+ switch(((GdkEventKey *)event)->keyval)
+ {
+ case GDK_KEY_F4: webkit_web_view_try_close(browser->webView); return TRUE;
+ case GDK_KEY_r:
+ if(((GdkEventKey *)event)->state & GDK_SHIFT_MASK)
+ webkit_web_view_reload_bypass_cache(browser->webView);
+ else
+ webkit_web_view_reload(browser->webView);
+
+ return TRUE;
+ case GDK_KEY_f: gtk_widget_grab_focus(browser->search); return TRUE;
+ case GDK_KEY_l: gtk_widget_grab_focus(browser->location); return TRUE;
+ case GDK_KEY_bracketleft: webkit_web_view_go_back(browser->webView); return TRUE;
+ case GDK_KEY_bracketright: webkit_web_view_go_forward(browser->webView); return TRUE;
+ case GDK_KEY_0:
+ webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(browser->webView), 1);
+ return TRUE;
+ }
+ }
+ else
+ {
+ switch(((GdkEventKey *)event)->keyval)
+ {
+ case GDK_KEY_Page_Down: gtk_notebook_next_page(notebook); return TRUE;
+ case GDK_KEY_Page_Up: gtk_notebook_prev_page(notebook); return TRUE;
+ case GDK_KEY_t: badwolf_new_tab(notebook, new_browser(window, NULL, NULL)); return TRUE;
+ }
+ }
+ }
+
+ if((((GdkEventKey *)event)->state & GDK_MOD1_MASK) && browser != NULL)
+ {
+ switch(((GdkEventKey *)event)->keyval)
+ {
+ case GDK_KEY_Left: gtk_notebook_prev_page(notebook); return TRUE;
+ case GDK_KEY_Right: gtk_notebook_next_page(notebook); return TRUE;
+ }
+ }
+
+ if(browser != NULL)
+ {
+ switch(((GdkEventKey *)event)->keyval)
+ {
+ case GDK_KEY_F5: webkit_web_view_reload(browser->webView); return TRUE;
+ }
+ }
+ else
+ {
+ switch(((GdkEventKey *)event)->keyval)
+ {
+ case GDK_KEY_F1: badwolf_about_dialog(GTK_WINDOW(window->main_window)); return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+WebViewCb_key_press_event(WebKitWebView *webView, GdkEvent *event, gpointer user_data)
+{
+ (void)webView;
+ struct Client *browser = (struct Client *)user_data;
+
+ if(commonCb_key_press_event(browser->window, event, browser)) return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+boxCb_key_press_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
+{
+ (void)widget;
+ struct Client *browser = (struct Client *)user_data;
+
+ if(commonCb_key_press_event(browser->window, event, browser)) return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+main_windowCb_key_press_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
+{
+ (void)widget;
+ struct Window *window = (struct Window *)user_data;
+
+ if(commonCb_key_press_event(window, event, NULL)) return TRUE;
+
+ return FALSE;
+}
static gboolean
WebViewCb_web_process_terminated(WebKitWebView *webView,
WebKitWebProcessTerminationReason reason,
@@ -124,6 +286,11 @@ WebViewCb_notify__uri(WebKitWebView *webView, GParamSpec *pspec, gpointer user_d
gtk_entry_set_text(GTK_ENTRY(browser->location), location_uri);
+ if(webkit_uri_for_display(location_uri) != location_uri)
+ gtk_widget_set_tooltip_text(browser->location, webkit_uri_for_display(location_uri));
+ else
+ gtk_widget_set_has_tooltip(browser->location, false);
+
return TRUE;
}
@@ -239,11 +406,31 @@ WebViewCb_mouse_target_changed(WebKitWebView *webView,
struct Client *browser = (struct Client *)user_data;
const gchar *link_uri = webkit_hit_test_result_get_link_uri(hit);
- gtk_label_set_text(GTK_LABEL(browser->statuslabel), link_uri);
+ gtk_label_set_text(GTK_LABEL(browser->statuslabel), webkit_uri_for_display(link_uri));
return TRUE;
}
+static gboolean
+WebViewCb_scroll_event(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ (void)widget;
+ struct Client *browser = (struct Client *)data;
+ gdouble delta_x, delta_y;
+ gfloat zoom;
+
+ if(((GdkEventScroll *)event)->state & GDK_CONTROL_MASK)
+ {
+ gdk_event_get_scroll_deltas(event, &delta_x, &delta_y);
+ zoom = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(browser->webView));
+ zoom -= delta_y * 0.1;
+ webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(browser->webView), zoom);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static WebKitWebView *
WebViewCb_create(WebKitWebView *related_web_view,
WebKitNavigationAction *navigation_action,
@@ -266,10 +453,10 @@ WebViewCb_create(WebKitWebView *related_web_view,
static gboolean
locationCb_activate(GtkEntry *location, gpointer user_data)
{
- const char *target_url;
+ char *target_url;
struct Client *browser = (struct Client *)user_data;
- target_url = gtk_entry_get_text(location);
+ target_url = ensure_uri_scheme((char *)gtk_entry_get_text(location), FALSE);
if(target_url != NULL) webkit_web_view_load_uri(browser->webView, target_url);
@@ -343,7 +530,7 @@ struct Client *
new_browser(struct Window *window, gchar *target_url, WebKitWebView *related_web_view)
{
struct Client *browser = g_malloc(sizeof(struct Client));
- if(target_url == NULL) target_url = "about:blank";
+ target_url = ensure_uri_scheme(target_url, (related_web_view != NULL));
browser->window = window;
browser->box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
@@ -437,6 +624,9 @@ new_browser(struct Window *window, gchar *target_url, WebKitWebView *related_web
browser);
g_signal_connect(browser->webView, "create", G_CALLBACK(WebViewCb_create), window);
g_signal_connect(browser->webView, "close", G_CALLBACK(WebViewCb_close), browser);
+ g_signal_connect(
+ browser->webView, "key-press-event", G_CALLBACK(WebViewCb_key_press_event), browser);
+ g_signal_connect(browser->webView, "scroll-event", G_CALLBACK(WebViewCb_scroll_event), browser);
g_signal_connect(browser->search, "next-match", G_CALLBACK(SearchEntryCb_next__match), browser);
g_signal_connect(
@@ -445,6 +635,8 @@ new_browser(struct Window *window, gchar *target_url, WebKitWebView *related_web
browser->search, "search-changed", G_CALLBACK(SearchEntryCb_search__changed), browser);
g_signal_connect(browser->search, "stop-search", G_CALLBACK(SearchEntryCb_stop__search), browser);
+ g_signal_connect(browser->box, "key-press-event", G_CALLBACK(boxCb_key_press_event), browser);
+
if(related_web_view == NULL) webkit_web_view_load_uri(browser->webView, target_url);
return browser;
@@ -523,6 +715,7 @@ main(int argc, char *argv[])
bind_textdomain_codeset(PACKAGE, "UTF-8");
textdomain(PACKAGE);
+ g_fprintf(stderr, _("Running Badwolf version: %s\n"), version);
g_fprintf(stderr,
_("Buildtime WebKit version: %d.%d.%d\n"),
WEBKIT_MAJOR_VERSION,
@@ -557,12 +750,16 @@ main(int argc, char *argv[])
badwolf_new_tab(GTK_NOTEBOOK(window->notebook), new_browser(window, target_url, NULL));
+ g_signal_connect(
+ window->main_window, "key-press-event", G_CALLBACK(main_windowCb_key_press_event), window);
+
g_signal_connect(window->main_window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(window->new_tab, "clicked", G_CALLBACK(new_tabCb_clicked), window);
g_signal_connect(window->notebook, "switch-page", G_CALLBACK(notebookCb_switch__page), window);
gtk_widget_show(window->new_tab);
gtk_widget_show_all(window->main_window);
+
gtk_main();
return 0;
}