commit: 5030dbfd170c3eb35eac9e2be08365f72f52161b
parent: 9a30193a956daea1a88a903437e01e4759a729c8
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Fri, 5 Jul 2019 08:31:23 +0200
Merge branch 'release-0.3' for 0.3.0
Diffstat:
3 files changed, 163 insertions(+), 7 deletions(-)
diff --git a/Makefile b/Makefile
@@ -11,7 +11,7 @@ OBJS = badwolf
TRANS = fr.mo
CC = cc
-CFLAGS = -g -Wall -Wextra
+CFLAGS = -g -Wall -Wextra -Wconversion -Wsign-conversion
CDEPS = `pkg-config --cflags $(DEPS)` -DDATADIR=\"$(DATADIR)\" -DPACKAGE=\"$(PACKAGE)\" -D_DEFAULT_SOURCE
LIBS = `pkg-config --libs $(DEPS)`
diff --git a/badwolf.1 b/badwolf.1
@@ -28,7 +28,7 @@ Zooms the webpage in/out.
Resets webpage zoom to 100%.
.It any C-t
Creates a new tab (in a new session, similar as pressing the button)
-.It browser C-F4
+.It browser C-F4, browser A-d
Closes the current tab
.It browser C-f
Focuses on the search entry
@@ -42,6 +42,8 @@ Go back/forward in current tab’s history
Go to the previous/next tab
.It any F1
Shows the about dialog
+.It any Alt-n
+Where n is any numeric-row key. Go to the n-th tab, 0 goes to the last one.
.El
.Ss DEFAULT ONES
Here is a incomplete list of the default Webkit/GTK keybindings:
@@ -53,6 +55,13 @@ When the search box is focused it goes to the Next/Previous search term.
.It search Escape
Cancels current search
.El
+.Sh ENVIRONMENT
+.Bl -width Ds -tag
+.It Ev BADWOLF_L10N
+A colon-separated list in the form lang_COUNTRY where lang is in ISO-639 and COUNTRY in ISO-3166. For example
+.Ic BADWOLF_L10N="en_GB:fr_FR:de_DE" .
+When this variable isn't set, spelling isn't activated. A more generic variable name is also intended to be used in the future.
+.El
.Sh BUGS
You can submit contributions or tickets to
.Lk https://gitlab.com/lanodan/badwolf
diff --git a/badwolf.c b/badwolf.c
@@ -8,11 +8,11 @@
#include <glib/gprintf.h> /* g_fprintf() */
#include <gtk/gtk.h>
#include <locale.h> /* LC_* */
-#include <stdlib.h> /* realpath() */
+#include <stdlib.h> /* realpath(), malloc() */
#include <webkit2/webkit2.h>
const gchar *homepage = "https://hacktivis.me/projects/badwolf";
-const gchar *version = "0.2.1";
+const gchar *version = "0.3.0";
struct Window
{
@@ -67,6 +67,19 @@ static gboolean WebViewCb_mouse_target_changed(WebKitWebView *webView,
static WebKitWebView *WebViewCb_create(WebKitWebView *related_web_view,
WebKitNavigationAction *navigation_action,
gpointer user_data);
+static gboolean WebViewCb_permission_request(WebKitWebView *web_view,
+ WebKitPermissionRequest *request,
+ gpointer user_data);
+static gboolean WebViewCb_decide_policy(WebKitWebView *web_view,
+ WebKitPolicyDecision *decision,
+ WebKitPolicyDecisionType decision_type,
+ gpointer user_data);
+static void web_contentCb_download_started(WebKitWebContext *context,
+ WebKitDownload *download,
+ gpointer user_data);
+static gboolean downloadCb_decide_destination(WebKitDownload *download,
+ gchar *suggested_filename,
+ gpointer user_data);
static gboolean locationCb_activate(GtkEntry *location, gpointer user_data);
static gboolean javascriptCb_toggled(GtkButton *javascript, gpointer user_data);
static gboolean SearchEntryCb_next__match(GtkSearchEntry *search, gpointer user_data);
@@ -82,6 +95,17 @@ static void
notebookCb_switch__page(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data);
gint get_tab_position(GtkContainer *notebook, GtkWidget *child);
+/* ensure_uri_scheme: tries to add a scheme on a pseudo-URL missing a scheme
+ * - gchar text: pseudo-URL missing a scheme
+ * - gboolean try_file: when TRUE check try first if it can be a file:// path
+ *
+ * When `text` isn't exploitable (ie. NULL), returns "about:blank",
+ * when the URL seems to be valid, return it,
+ * if try_file is TRUE, check if it can be file:// path,
+ * some other checks might be added.
+ * In the end use the fallback (`http://` for now, might get configuration),
+ * might get some safeguard.
+ */
gchar *
ensure_uri_scheme(gchar *text, gboolean try_file)
{
@@ -189,13 +213,22 @@ commonCb_key_press_event(struct Window *window, GdkEvent *event, struct Client *
}
}
- if((((GdkEventKey *)event)->state & GDK_MOD1_MASK) && browser != NULL)
+ if((((GdkEventKey *)event)->state & GDK_MOD1_MASK))
{
+ if((browser != NULL) && (((GdkEventKey *)event)->keyval == GDK_KEY_d))
+ {
+ webkit_web_view_try_close(browser->webView);
+ return TRUE;
+ }
+
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((((GdkEventKey *)event)->keyval >= GDK_KEY_0) &&
+ (((GdkEventKey *)event)->keyval <= GDK_KEY_9))
+ gtk_notebook_set_current_page(notebook, (gint)(((GdkEventKey *)event)->keyval - GDK_KEY_1));
}
if(browser != NULL)
@@ -425,7 +458,7 @@ WebViewCb_scroll_event(GtkWidget *widget, GdkEvent *event, gpointer data)
(void)widget;
struct Client *browser = (struct Client *)data;
gdouble delta_x, delta_y;
- gfloat zoom;
+ gdouble zoom;
if(((GdkEventScroll *)event)->state & GDK_CONTROL_MASK)
{
@@ -459,6 +492,94 @@ WebViewCb_create(WebKitWebView *related_web_view,
}
static gboolean
+WebViewCb_permission_request(WebKitWebView *web_view,
+ WebKitPermissionRequest *request,
+ gpointer user_data)
+{
+ (void)web_view;
+ (void)user_data;
+
+ webkit_permission_request_deny(request);
+
+ return TRUE; /* Stop other handlers */
+}
+
+static gboolean
+WebViewCb_decide_policy(WebKitWebView *web_view,
+ WebKitPolicyDecision *decision,
+ WebKitPolicyDecisionType decision_type,
+ gpointer user_data)
+{
+ WebKitResponsePolicyDecision *r;
+ (void)web_view;
+ (void)user_data;
+
+ switch(decision_type)
+ {
+ case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
+ r = WEBKIT_RESPONSE_POLICY_DECISION(decision);
+ if(!webkit_response_policy_decision_is_mime_type_supported(r))
+ webkit_policy_decision_download(decision);
+ else
+ webkit_policy_decision_use(decision);
+ break;
+ default:
+ /* Use whatever default there is. */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+web_contentCb_download_started(WebKitWebContext *context,
+ WebKitDownload *download,
+ gpointer user_data)
+{
+ (void)context;
+
+ g_signal_connect(G_OBJECT(download),
+ "decide-destination",
+ G_CALLBACK(downloadCb_decide_destination),
+ user_data);
+}
+
+static gboolean
+downloadCb_decide_destination(WebKitDownload *download,
+ gchar *suggested_filename,
+ gpointer user_data)
+{
+ struct Client *browser = (struct Client *)user_data;
+ gint chooser_response;
+ GtkWindow *parent_window = GTK_WINDOW(browser->window->main_window);
+
+ GtkWidget *file_dialog = gtk_file_chooser_dialog_new(NULL,
+ parent_window,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ _("_Cancel"),
+ GTK_RESPONSE_CANCEL,
+ _("_Save"),
+ GTK_RESPONSE_ACCEPT,
+ NULL);
+ GtkFileChooser *file_chooser = GTK_FILE_CHOOSER(file_dialog);
+
+ gtk_file_chooser_set_current_name(file_chooser, suggested_filename);
+ gtk_file_chooser_set_do_overwrite_confirmation(file_chooser, TRUE);
+ webkit_download_set_allow_overwrite(download, TRUE);
+
+ chooser_response = gtk_dialog_run(GTK_DIALOG(file_dialog));
+
+ if(chooser_response == GTK_RESPONSE_ACCEPT)
+ webkit_download_set_destination(download, gtk_file_chooser_get_uri(file_chooser));
+ else
+ webkit_download_cancel(download);
+
+ gtk_widget_destroy(file_dialog);
+
+ return FALSE; /* Let it propagate */
+}
+
+static gboolean
locationCb_activate(GtkEntry *location, gpointer user_data)
{
char *target_url;
@@ -537,8 +658,9 @@ SearchEntryCb_stop__search(GtkSearchEntry *search, gpointer user_data)
struct Client *
new_browser(struct Window *window, gchar *target_url, WebKitWebView *related_web_view)
{
- struct Client *browser = g_try_malloc(sizeof(struct Client));
+ struct Client *browser = malloc(sizeof(struct Client));
target_url = ensure_uri_scheme(target_url, (related_web_view == NULL));
+ char *badwolf_l10n = NULL;
if(browser == NULL) return NULL;
@@ -556,6 +678,17 @@ new_browser(struct Window *window, gchar *target_url, WebKitWebView *related_web
webkit_web_context_set_process_model(web_context,
WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);
+ badwolf_l10n = getenv("BADWOLF_L10N");
+
+ if(badwolf_l10n != NULL)
+ {
+ gchar **languages = g_strsplit(badwolf_l10n, ":", -1);
+ webkit_web_context_set_spell_checking_languages(web_context, (const gchar *const *)languages);
+ g_strfreev(languages);
+
+ webkit_web_context_set_spell_checking_enabled(web_context, TRUE);
+ }
+
WebKitSettings *settings = webkit_settings_new_with_settings(BADWOLF_WEBKIT_SETTINGS);
browser->webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
@@ -610,10 +743,13 @@ new_browser(struct Window *window, gchar *target_url, WebKitWebView *related_web
gtk_entry_set_placeholder_text(GTK_ENTRY(browser->search), _("search in current page"));
gtk_entry_set_has_frame(GTK_ENTRY(browser->search), FALSE);
+ /* signals for location entry widget */
g_signal_connect(browser->location, "activate", G_CALLBACK(locationCb_activate), browser);
+ /* signals for javacript toggle widget */
g_signal_connect(browser->javascript, "toggled", G_CALLBACK(javascriptCb_toggled), browser);
+ /* signals for WebView widget */
g_signal_connect(browser->webView,
"web-process-terminated",
G_CALLBACK(WebViewCb_web_process_terminated),
@@ -637,7 +773,17 @@ new_browser(struct Window *window, gchar *target_url, WebKitWebView *related_web
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->webView, "permission-request", G_CALLBACK(WebViewCb_permission_request), NULL);
+ g_signal_connect(browser->webView, "decide-policy", G_CALLBACK(WebViewCb_decide_policy), NULL);
+
+ /* signals for WebView's WebContext */
+ g_signal_connect(G_OBJECT(web_context),
+ "download-started",
+ G_CALLBACK(web_contentCb_download_started),
+ browser);
+ /* signals for search widget */
g_signal_connect(browser->search, "next-match", G_CALLBACK(SearchEntryCb_next__match), browser);
g_signal_connect(
browser->search, "previous-match", G_CALLBACK(SearchEntryCb_previous__match), browser);
@@ -645,6 +791,7 @@ 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);
+ /* signals for box container */
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);