diff options
| Commit | a49df8ad9869a47a10138738b38fd0ffdb95e402 (patch) | |
|---|---|---|
| Author | 2020-05-18 04:50:42 +0200 | |
| Committer | 2020-05-18 04:50:42 +0200 | |
| Files | 08a4eee2a5110415214e5f70f572c3c47e5c3b08 /badwolf.c | |
| goodwolf-1.0.0.tar goodwolf-1.0.0.tar.gz goodwolf-1.0.0.zip | ||
| Parent | c3cadbabf760fd86a0b21bf1869e01653fa5dbbe (diff) | |
| Parent | 1dbcade1d73cc2e45c61663cc97da17ddec7eb04 (diff) | |
Merge branch 'release-1.0' for v1.0.0 v1.0.0
1 files changed, 242 insertions, 64 deletions
| -rw-r--r-- | badwolf.c | 306 |
@@ -5,6 +5,7 @@ #include "badwolf.h" #include "config.h" +#include "downloads.h" #include "keybindings.h" #include "uri.h" @@ -13,12 +14,12 @@ #include <locale.h> /* LC_* */ #include <stdio.h> /* perror(), fprintf() */ #include <stdlib.h> /* malloc() */ +#include <unistd.h> /* access() */ +gchar *web_extensions_directory; const gchar *homepage = "https://hacktivis.me/projects/badwolf"; const gchar *version = VERSION; -gchar *web_extensions_directory; - static gboolean WebViewCb_close(WebKitWebView *webView, gpointer user_data); static gboolean WebViewCb_web_process_terminated(WebKitWebView *webView, WebKitWebProcessTerminationReason reason, @@ -46,14 +47,17 @@ static gboolean WebViewCb_decide_policy(WebKitWebView *web_view, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decision_type, gpointer user_data); +static void +WebViewCb_load_changed(WebKitWebView *webView, WebKitLoadEvent load_event, gpointer user_data); static void web_contextCb_download_started(WebKitWebContext *web_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 auto_load_imagesCb_toggled(GtkButton *auto_load_images, gpointer user_data); +static void backCb_clicked(GtkButton *back, gpointer user_data); +static void forwardCb_clicked(GtkButton *forward, gpointer user_data); +static void printCb_clicked(GtkButton *forward, gpointer user_data); static gboolean SearchEntryCb_next__match(GtkSearchEntry *search, gpointer user_data); static gboolean SearchEntryCb_previous__match(GtkSearchEntry *search, gpointer user_data); static gboolean SearchEntryCb_search__changed(GtkSearchEntry *search, gpointer user_data); @@ -131,11 +135,15 @@ badwolf_new_tab_box(const gchar *title, struct Client *browser) { (void)browser; GtkWidget *tab_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_name(tab_box, "browser__tabbox"); GtkWidget *close = - gtk_button_new_from_icon_name("window-close-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_button_new_from_icon_name("window-close-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_widget_set_name(close, "browser__tabbox__close"); GtkWidget *label = gtk_label_new(title); + gtk_widget_set_name(label, "browser__tabbox__label"); GtkWidget *playing = gtk_image_new_from_icon_name("audio-volume-high-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_widget_set_name(playing, "browser__tabbox__playing"); #ifdef BADWOLF_TAB_BOX_WIDTH gtk_widget_set_size_request(label, BADWOLF_TAB_BOX_WIDTH, -1); @@ -193,7 +201,7 @@ webView_tab_label_change(struct Client *browser, const gchar *title) { GtkWidget *notebook = browser->window->notebook; -#define title_IS_EMPTY (title == NULL) || (title == (const gchar *)"") +#define title_IS_EMPTY (title == NULL) || strnlen(title, 2) == 0 if(title_IS_EMPTY) title = webkit_web_view_get_title(browser->webView); if(title_IS_EMPTY) title = webkit_web_view_get_uri(browser->webView); @@ -325,6 +333,17 @@ WebViewCb_decide_policy(WebKitWebView *web_view, return TRUE; } +static void +WebViewCb_load_changed(WebKitWebView *webView, WebKitLoadEvent load_event, gpointer user_data) +{ + (void)webView; + (void)load_event; + struct Client *browser = (struct Client *)user_data; + + gtk_widget_set_sensitive(browser->back, webkit_web_view_can_go_back(browser->webView)); + gtk_widget_set_sensitive(browser->forward, webkit_web_view_can_go_forward(browser->webView)); +} + static char * detail_tls_certificate_flags(GTlsCertificateFlags tls_errors) { @@ -381,7 +400,7 @@ WebViewCb_load_failed_with_tls_errors(WebKitWebView *web_view, _("TLS Error for %s."), failing_text); gtk_dialog_add_buttons( - GTK_DIALOG(dialog), _("Temporarly Add Exception"), 1, _("Continue"), 0, NULL); + GTK_DIALOG(dialog), _("Temporarily Add Exception"), 1, _("Continue"), 0, NULL); gtk_dialog_set_default_response(GTK_DIALOG(dialog), 0); gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s\n", error_details); @@ -403,72 +422,106 @@ WebViewCb_load_failed_with_tls_errors(WebKitWebView *web_view, static void web_contextCb_download_started(WebKitWebContext *web_context, - WebKitDownload *download, + WebKitDownload *webkit_download, gpointer user_data) { (void)web_context; + struct Client *browser = (struct Client *)user_data; + struct Download *download = malloc(sizeof(struct Client)); + + if(download != NULL) + { + download->window = browser->window; + + download_new_entry(webkit_download, download); + + g_signal_connect( + G_OBJECT(webkit_download), "received-data", G_CALLBACK(downloadCb_received_data), download); + g_signal_connect(G_OBJECT(webkit_download), + "created-destination", + G_CALLBACK(downloadCb_created_destination), + download); + g_signal_connect(G_OBJECT(webkit_download), "failed", G_CALLBACK(downloadCb_failed), download); + g_signal_connect( + G_OBJECT(webkit_download), "finished", G_CALLBACK(downloadCb_finished), download); + } - g_signal_connect(G_OBJECT(download), + g_signal_connect(G_OBJECT(webkit_download), "decide-destination", G_CALLBACK(downloadCb_decide_destination), user_data); } static gboolean -downloadCb_decide_destination(WebKitDownload *download, - gchar *suggested_filename, - gpointer user_data) +locationCb_activate(GtkEntry *location, gpointer user_data) { struct Client *browser = (struct Client *)user_data; - gint chooser_response; - GtkWindow *parent_window = GTK_WINDOW(browser->window->main_window); - - GtkFileChooserNative *file_dialog = - gtk_file_chooser_native_new(NULL, parent_window, GTK_FILE_CHOOSER_ACTION_SAVE, NULL, 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_native_dialog_run(GTK_NATIVE_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); - - g_object_unref(file_dialog); + webkit_web_view_load_uri(browser->webView, + badwolf_ensure_uri_scheme(gtk_entry_get_text(location), TRUE)); - return FALSE; /* Let it propagate */ + return TRUE; } static gboolean -locationCb_activate(GtkEntry *location, gpointer user_data) +javascriptCb_toggled(GtkButton *javascript, gpointer user_data) { struct Client *browser = (struct Client *)user_data; - webkit_web_view_load_uri(browser->webView, - badwolf_ensure_uri_scheme(gtk_entry_get_text(location), TRUE)); + WebKitSettings *settings = webkit_web_view_get_settings(browser->webView); + + webkit_settings_set_enable_javascript_markup( + settings, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(javascript))); + + webkit_web_view_set_settings(browser->webView, settings); return TRUE; } static gboolean -javascriptCb_toggled(GtkButton *javascript, gpointer user_data) +auto_load_imagesCb_toggled(GtkButton *auto_load_images, gpointer user_data) { struct Client *browser = (struct Client *)user_data; WebKitSettings *settings = webkit_web_view_get_settings(browser->webView); - webkit_settings_set_enable_javascript_markup( - settings, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(javascript))); + webkit_settings_set_auto_load_images( + settings, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(auto_load_images))); webkit_web_view_set_settings(browser->webView, settings); return TRUE; } +static void +backCb_clicked(GtkButton *back, gpointer user_data) +{ + (void)back; + struct Client *browser = (struct Client *)user_data; + + webkit_web_view_go_back(browser->webView); +} + +static void +forwardCb_clicked(GtkButton *forward, gpointer user_data) +{ + (void)forward; + struct Client *browser = (struct Client *)user_data; + + webkit_web_view_go_forward(browser->webView); +} + +static void +printCb_clicked(GtkButton *print, gpointer user_data) +{ + (void)print; + struct Client *browser = (struct Client *)user_data; + + WebKitPrintOperation *print_operation = webkit_print_operation_new(browser->webView); + + webkit_print_operation_run_dialog(print_operation, GTK_WINDOW(browser->window)); +} + static gboolean SearchEntryCb_next__match(GtkSearchEntry *search, gpointer user_data) { @@ -517,6 +570,16 @@ SearchEntryCb_stop__search(GtkSearchEntry *search, gpointer user_data) return TRUE; } +static gboolean +widgetCb_drop_button3_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) +{ + (void)widget; + (void)user_data; + + // Button3 being right-click on right-handed mode, left-click on left-handed mode + return ((GdkEventButton *)event)->button == 3; +} + struct Client * new_browser(struct Window *window, const gchar *target_url, WebKitWebView *related_web_view) { @@ -526,15 +589,47 @@ new_browser(struct Window *window, const gchar *target_url, WebKitWebView *relat if(browser == NULL) return NULL; - browser->window = window; - browser->box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - browser->toolbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - browser->location = gtk_entry_new(); - browser->javascript = gtk_check_button_new(); + browser->window = window; + browser->box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_name(browser->box, "browser__box"); + + browser->toolbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_name(browser->toolbar, "browser__toolbar"); + + browser->back = + gtk_button_new_from_icon_name("go-previous-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_widget_set_name(browser->back, "browser__back"); + + browser->forward = gtk_button_new_from_icon_name("go-next-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_widget_set_name(browser->forward, "browser__forward"); + + GtkWidget *toolbar_separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL); + + browser->javascript = gtk_toggle_button_new_with_mnemonic(_("_JS")); + gtk_widget_set_name(browser->javascript, "browser__javascript"); + gtk_widget_set_tooltip_text(browser->javascript, _("Toggle javascript")); + gtk_button_set_relief(GTK_BUTTON(browser->javascript), GTK_RELIEF_NONE); + + browser->auto_load_images = gtk_toggle_button_new_with_mnemonic(_("_IMG")); + gtk_widget_set_name(browser->auto_load_images, "browser__load_images"); + gtk_widget_set_tooltip_text(browser->auto_load_images, _("Toggle loading images automatically")); + gtk_button_set_relief(GTK_BUTTON(browser->auto_load_images), GTK_RELIEF_NONE); + + browser->location = gtk_entry_new(); + gtk_widget_set_name(browser->location, "browser__location"); - browser->statusbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + GtkWidget *print = + gtk_button_new_from_icon_name("document-print-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_widget_set_name(browser->back, "browser__print"); + + browser->statusbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_name(browser->statusbar, "browser__statusbar"); + browser->search = gtk_search_entry_new(); + gtk_widget_set_name(browser->search, "browser__search"); browser->statuslabel = gtk_label_new(NULL); - browser->search = gtk_search_entry_new(); + gtk_widget_set_name(browser->statuslabel, "browser__statuslabel"); + + setenv("GTK_THEME", ":light", 0); WebKitWebContext *web_context = webkit_web_context_new_ephemeral(); webkit_web_context_set_sandbox_enabled(web_context, TRUE); @@ -558,6 +653,8 @@ new_browser(struct Window *window, const gchar *target_url, WebKitWebView *relat gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(browser->javascript), webkit_settings_get_enable_javascript_markup(settings)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(browser->auto_load_images), + webkit_settings_get_auto_load_images(settings)); browser->webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, "web-context", @@ -567,19 +664,39 @@ new_browser(struct Window *window, const gchar *target_url, WebKitWebView *relat "settings", settings, NULL)); + gtk_widget_set_name(GTK_WIDGET(browser->webView), "browser__webView"); - gtk_widget_set_tooltip_text(browser->javascript, _("Toggle javascript")); - + gtk_box_pack_start( + GTK_BOX(browser->toolbar), GTK_WIDGET(browser->back), FALSE, FALSE, BADWOLF_TOOLBAR_PADDING); + gtk_box_pack_start(GTK_BOX(browser->toolbar), + GTK_WIDGET(browser->forward), + FALSE, + FALSE, + BADWOLF_TOOLBAR_PADDING); + gtk_box_pack_start(GTK_BOX(browser->toolbar), + toolbar_separator, + FALSE, + FALSE, + BADWOLF_TOOLBAR_SEPARATOR_PADDING); gtk_box_pack_start(GTK_BOX(browser->toolbar), GTK_WIDGET(browser->javascript), FALSE, FALSE, BADWOLF_TOOLBAR_PADDING); gtk_box_pack_start(GTK_BOX(browser->toolbar), + GTK_WIDGET(browser->auto_load_images), + FALSE, + FALSE, + BADWOLF_TOOLBAR_PADDING); + gtk_box_pack_start(GTK_BOX(browser->toolbar), GTK_WIDGET(browser->location), TRUE, TRUE, BADWOLF_TOOLBAR_PADDING); + gtk_box_pack_start(GTK_BOX(browser->toolbar), print, FALSE, FALSE, BADWOLF_TOOLBAR_PADDING); + + gtk_container_set_focus_child(GTK_CONTAINER(browser->box), browser->toolbar); + gtk_container_set_focus_child(GTK_CONTAINER(browser->toolbar), browser->location); gtk_box_pack_start( GTK_BOX(browser->box), GTK_WIDGET(browser->toolbar), FALSE, FALSE, BADWOLF_BOX_PADDING); @@ -606,17 +723,52 @@ new_browser(struct Window *window, const gchar *target_url, WebKitWebView *relat gtk_label_set_ellipsize(GTK_LABEL(browser->statuslabel), BADWOLF_STATUSLABEL_ELLIPSIZE); gtk_entry_set_text(GTK_ENTRY(browser->location), target_url); - gtk_entry_set_has_frame(GTK_ENTRY(browser->location), FALSE); gtk_entry_set_input_purpose(GTK_ENTRY(browser->location), GTK_INPUT_PURPOSE_URL); 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 back/forward buttons */ + g_signal_connect(browser->back, "clicked", G_CALLBACK(backCb_clicked), browser); + g_signal_connect(browser->forward, "clicked", G_CALLBACK(forwardCb_clicked), browser); + /* prevents GtkNotebook from spawning it's context-menu */ + g_signal_connect( + browser->back, "button-press-event", G_CALLBACK(widgetCb_drop_button3_event), NULL); + g_signal_connect( + browser->back, "button-release-event", G_CALLBACK(widgetCb_drop_button3_event), NULL); + g_signal_connect( + browser->forward, "button-press-event", G_CALLBACK(widgetCb_drop_button3_event), NULL); + g_signal_connect( + browser->forward, "button-release-event", G_CALLBACK(widgetCb_drop_button3_event), NULL); /* signals for javacript toggle widget */ g_signal_connect(browser->javascript, "toggled", G_CALLBACK(javascriptCb_toggled), browser); + /* prevents GtkNotebook from spawning it's context-menu */ + g_signal_connect( + browser->javascript, "button-press-event", G_CALLBACK(widgetCb_drop_button3_event), NULL); + g_signal_connect( + browser->javascript, "button-release-event", G_CALLBACK(widgetCb_drop_button3_event), NULL); + + /* signals for auto_load_images toggle widget */ + g_signal_connect( + browser->auto_load_images, "toggled", G_CALLBACK(auto_load_imagesCb_toggled), browser); + /* prevents GtkNotebook from spawning it's context-menu */ + g_signal_connect(browser->auto_load_images, + "button-press-event", + G_CALLBACK(widgetCb_drop_button3_event), + NULL); + g_signal_connect(browser->auto_load_images, + "button-release-event", + G_CALLBACK(widgetCb_drop_button3_event), + NULL); + + /* signals for location entry widget */ + g_signal_connect(browser->location, "activate", G_CALLBACK(locationCb_activate), browser); + + /* signals for print button */ + g_signal_connect(print, "clicked", G_CALLBACK(printCb_clicked), browser); + /* prevents GtkNotebook from spawning it's context-menu */ + g_signal_connect(print, "button-press-event", G_CALLBACK(widgetCb_drop_button3_event), NULL); + g_signal_connect(print, "button-release-event", G_CALLBACK(widgetCb_drop_button3_event), NULL); /* signals for WebView widget */ g_signal_connect(browser->webView, @@ -649,6 +801,7 @@ new_browser(struct Window *window, const gchar *target_url, WebKitWebView *relat "load-failed-with-tls-errors", G_CALLBACK(WebViewCb_load_failed_with_tls_errors), browser); + g_signal_connect(browser->webView, "load-changed", G_CALLBACK(WebViewCb_load_changed), browser); /* signals for WebView's WebContext */ g_signal_connect(G_OBJECT(web_context), @@ -744,7 +897,7 @@ badwolf_get_tab_position(GtkContainer *notebook, GtkWidget *child) int main(int argc, char *argv[]) { - struct Window *window = &(struct Window){NULL}; + struct Window *window = &(struct Window){NULL, NULL, NULL, NULL}; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, DATADIR "/locale"); bind_textdomain_codeset(PACKAGE, "UTF-8"); @@ -752,13 +905,6 @@ main(int argc, char *argv[]) gtk_init(&argc, &argv); -#ifdef BADWOLF_PREFER_DARK_THEME - g_object_set(gtk_settings_get_default(), - "gtk-application-prefer-dark-theme", - BADWOLF_PREFER_DARK_THEME, - NULL); -#endif - fprintf(stderr, _("Running Badwolf version: %s\n"), version); fprintf(stderr, _("Buildtime WebKit version: %d.%d.%d\n"), @@ -778,10 +924,37 @@ main(int argc, char *argv[]) window->main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); window->notebook = gtk_notebook_new(); window->new_tab = gtk_button_new_from_icon_name("tab-new-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR); + window->downloads_tab = badwolf_downloads_tab_new(); gtk_window_set_default_size( GTK_WINDOW(window->main_window), BADWOLF_DEFAULT_WIDTH, BADWOLF_DEFAULT_HEIGHT); gtk_window_set_role(GTK_WINDOW(window->main_window), "browser"); + gtk_window_set_icon_name(GTK_WINDOW(window->main_window), "badwolf"); + + GtkCssProvider *css_provider_app = gtk_css_provider_new(); + gchar *provider_path_app = g_build_filename(DATADIR, "interface.css", NULL); + if(access(provider_path_app, R_OK) == 0) + { + gtk_css_provider_load_from_path(css_provider_app, provider_path_app, NULL); + gtk_style_context_add_provider_for_screen( + gtk_widget_get_screen(GTK_WIDGET(window->main_window)), + GTK_STYLE_PROVIDER(css_provider_app), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + } + g_free(provider_path_app); + + GtkCssProvider *css_provider_user = gtk_css_provider_new(); + gchar *provider_path_user = + g_build_filename(g_get_user_data_dir(), "badwolf", "interface.css", NULL); + if(access(provider_path_user, R_OK) == 0) + { + gtk_css_provider_load_from_path(css_provider_user, provider_path_user, NULL); + gtk_style_context_add_provider_for_screen( + gtk_widget_get_screen(GTK_WIDGET(window->main_window)), + GTK_STYLE_PROVIDER(css_provider_user), + GTK_STYLE_PROVIDER_PRIORITY_USER); + } + g_free(provider_path_user); gtk_widget_set_tooltip_text(window->new_tab, _("Open new tab")); @@ -791,12 +964,9 @@ main(int argc, char *argv[]) gtk_notebook_popup_enable(GTK_NOTEBOOK(window->notebook)); gtk_container_add(GTK_CONTAINER(window->main_window), window->notebook); + gtk_widget_queue_draw(window->notebook); - if(argc == 1) - badwolf_new_tab(GTK_NOTEBOOK(window->notebook), new_browser(window, NULL, NULL)); - else - for(int i = 1; i < argc; ++i) - badwolf_new_tab(GTK_NOTEBOOK(window->notebook), new_browser(window, argv[i], NULL)); + badwolf_downloads_tab_attach(window); g_signal_connect( window->main_window, "key-press-event", G_CALLBACK(main_windowCb_key_press_event), window); @@ -808,6 +978,14 @@ main(int argc, char *argv[]) gtk_widget_show(window->new_tab); gtk_widget_show_all(window->main_window); + if(argc == 1) + badwolf_new_tab(GTK_NOTEBOOK(window->notebook), new_browser(window, NULL, NULL)); + else + for(int i = 1; i < argc; ++i) + badwolf_new_tab(GTK_NOTEBOOK(window->notebook), new_browser(window, argv[i], NULL)); + + gtk_notebook_set_current_page(GTK_NOTEBOOK(window->notebook), 1); + gtk_main(); #if 0 |