-BasedOnStyle: llvm
-AlwaysBreakAfterReturnType: AllDefinitions
-IndentWidth: 4
\ No newline at end of file
+# SPDX-License-Identifier: GPL-2.0, Linux Kernel, Armaan Bhojwani
+AccessModifierOffset: -4
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlines: Left # Unknown to clang-format-4.0
+AlignOperands: true
+AlignTrailingComments: false
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: true
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: false
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: true
+ AfterNamespace: true
+ AfterStruct: false
+ AfterUnion: false
+ AfterExternBlock: false # Unknown to clang-format-5.0
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+ SplitEmptyFunction: true # Unknown to clang-format-4.0
+ SplitEmptyRecord: true # Unknown to clang-format-4.0
+ SplitEmptyNamespace: true # Unknown to clang-format-4.0
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
+BreakBeforeTernaryOperators: false
+BreakConstructorInitializersBeforeComma: false
+BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: false
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+CompactNamespaces: false # Unknown to clang-format-4.0
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 8
+ContinuationIndentWidth: 8
+Cpp11BracedListStyle: false
+DerivePointerAlignment: false
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: false # Unknown to clang-format-4.0
+IncludeBlocks: Preserve # Unknown to clang-format-5.0
+IncludeCategories:
+ - Regex: '.*'
+ Priority: 1
+IncludeIsMainRegex: '(Test)?$'
+IndentCaseLabels: false
+IndentPPDirectives: None # Unknown to clang-format-5.0
+IndentWidth: 8
+IndentWrappedFunctionNames: false
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+
+PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
+PenaltyBreakBeforeFirstCallParameter: 30
+PenaltyBreakComment: 10
+PenaltyBreakFirstLessLess: 0
+PenaltyBreakString: 10
+PenaltyExcessCharacter: 100
+PenaltyReturnTypeOnItsOwnLine: 60
+
+PointerAlignment: Right
+ReflowComments: false
+SortIncludes: false
+SortUsingDeclarations: false # Unknown to clang-format-4.0
+SpaceAfterCStyleCast: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
+SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
+SpaceBeforeParens: ControlStatements
+SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: false
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp03
+TabWidth: 8
+UseTab: Always
chorizo
*.so
-darkreader.js
-*.1
-*.5
\ No newline at end of file
-CFLAGS += -Wall -Wextra -Wno-unused-parameter -O3
-
+CFLAGS += -std=c11 -Wall -Wextra -Wno-unused-parameter -D_XOPEN_SOURCE="700"
+LIBS = `pkg-config --cflags --libs gtk+-3.0 glib-2.0 webkit2gtk-4.0`
PREFIX = /usr/local
bindir = $(DESTDIR)$(PREFIX)/bin
libdir = $(DESTDIR)$(PREFIX)/lib
datadir = $(DESTDIR)$(PREFIX)/share
-mandir = $(datadir)/man
-docdir = $(datadir)/doc
-
-.PHONY: man clean uninstall install extensions
+mandir = $(DESTDIR)/$(PREFIX)/man
-all: man chorizo extensions darkreader
+.PHONY: chorizo clean uninstall install extensions update-darkreader
-man:
- for i in man/*.scd; do \
- printf "SCDOC\t%s\n" $$i; \
- scdoc < $$i > $$(echo "$$i" | rev | cut -f 2- -d '.' | rev); \
- done
+all: extensions chorizo
chorizo:
- $(CC) $(CFLAGS) $(LDFLAGS) \
- -D__NAME__=\"chorizo\" \
- -D__NAME_UPPERCASE__=\"CHORIZO\" \
- -DVERSION=\"v1.0.0\" \
- -o chorizo src/*.c \
- `pkg-config --cflags --libs gtk+-3.0 glib-2.0 webkit2gtk-4.0`
+ $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) -o chorizo *.c
+
+format:
+ for i in *.c *.h; do clang-format $$i > tmp; mv tmp $$i; done
extensions:
for i in extensions/*.c; do \
outp=$$(echo "$$i" | sed 's/\$\.c/.so/g'); \
- $(CC) $(CFLAGS) $(LDFLAGS) \
- -D__NAME__=\"chorizo\" \
- -D__NAME_UPPERCASE__=\"CHORIZO\" \
- -shared -o $$outp -fPIC $$i \
- `pkg-config --cflags --libs glib-2.0 webkit2gtk-4.0`; \
+ $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $$outp -fPIC $$i $(LIBS); \
done
install: all
mkdir -p $(bindir) \
$(mandir)/man1 \
- $(mandir)/man5 \
+ $(mandir)/man7 \
$(libdir)/chorizo/web-extensions \
- $(datadir)/chorizo/user-scripts \
- $(datadir)/applications \
- $(docdir)/chorizo
+ $(datadir)/chorizo/user-scripts
cp chorizo $(bindir)/
- cp man/*.1 $(mandir)/man1/
- cp man/*.5 $(mandir)/man5/
- cp chorizo.ini $(docdir)/chorizo/
- cp chorizo.desktop $(datadir)/applications/
+
+ cp chorizo.1 $(mandir)/man1/
+ cp chorizo-usage.7 $(mandir)/man7/
+ makewhatis /usr/local/man
+
cp -r extensions/*.so $(libdir)/chorizo/web-extensions/
cp -r user-scripts/* $(datadir)/chorizo/user-scripts/
rm -rf $(bindir)/chorizo \
$(libdir)/chorizo \
$(mandir)/man1/chorizo* \
- $(mandir)/man5/chorizo* \
- $(datadir)/chorizo \
- $(datadir)/applications/chorizo.desktop \
- $(docdir)/chorizo
+ $(mandir)/man7/chorizo* \
+ $(datadir)/chorizo
reinstall: uninstall install
-darkreader:
+update-darkreader:
curl -L "https://cdn.jsdelivr.net/npm/darkreader/darkreader.min.js" \
-o user-scripts/darkreader.js
echo >> user-scripts/darkreader.js
>> user-scripts/darkreader.js
clean:
- rm -fv chorizo \
- extensions/*.so \
- man/*.1 \
- man/*.5 \
- user-scripts/darkreader.js
+ rm -fv chorizo extensions/*.so
- _ _
- ___| |__ ___ _ __(_)_______
- / __| '_ \ / _ \| '__| |_ / _ \
- | (__| | | | (_) | | | |/ / (_) |
- \___|_| |_|\___/|_| |_/___\___/
- https://sr.ht/~armaan/chorizo
+chorizo
+======
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+http://armaanb.net/chorizo.html
A simple web browser using GTK+ 3, GLib and WebKit2GTK+.
-Features:
- - A WebKit2 viewport
- - An input box to change the URI, search the current page, or
- search the web
- - Tab management
- - Full keyboard control
- - An ini configuration file
- - Built-in download manager
- - Web feeds indicator
- - Global content zoom
- - Cooperative instances using FIFOs
- - Certificate trust store
- - User script support
- - Extensions
-
-Refer to the manpages chorizo(1), chorizo-usage(1), and
-chorizo-config(5), for more information.
+Refer to the manpages chorizo(1), and chorizo-usage(1) for more information.
Installation
------------
- GTK+ 3
- WebKit2 API for GTK+ 3
- - gst-libav, gst-plugins-good - for media playback
+ - gst-libav, gst-plugins-good (for media playback)
-To generate the manpages, scdoc is required. This isn't necesary on
-release tarballs.
+The following programs are required:
+ - A C compiler supporting C11
+ - make
+ - pkg-config
chorizo expects to be run on a POSIX-ish operating system.
# make install
-Background information
-----------------------
-
-What chorizo is and what it's not
-
- chorizo does what I need. It won't do other things. I'm open for
- contributions but please don't be upset if I turn them down -- which
- might happen if it's a feature that I simply don't need.
-
- chorizo does not compete with powerful browsers like dwb or luakit, nor
- with monstrous applications like Firefox or Chromium. Because under
- the hood chorizo is powered by WebKit, however, it is on par with
- browsers like Safari for page rendering features.
-
How is chorizo related to lariza?
+---------------------------------
chorizo is a fork of the lariza browser by Peter Hofmann. I wanted
to take it in a slightly different direction (mostly just adding
features not considered to be in the spirit of lariza), so I forked
it. The name was changed in order to reduce confusion between the
- two browsers as they grew apart. The versioning scheme was also
- moved away from being calendar-based.
+ two browsers as they grew apart.
- Features that this fork has that lariza is missing:
- - Configuration file
+ Differences:
+ - New versioning scheme
- Revamped download manager
- - New, ergonomic keybindings inspire by both Emacs and Vim
+ - New keybindings
- Better default directories
- - Easily togglable images and JavaScript
+ - Easily togglable JavaScript
- Cleaned up source code
- Easy web searching
- User stylesheet support
- A variety of tweaks and adjustments that make the experience nicer
-
-Migrating from another browser
-------------------------------
-
-From lariza:
- 1. Copy the relevant paths from ~/.config/lariza to
- ~/.local/share/chorizo. Read chorizo(1) for full details on the
- correct paths.
-
- 2. Your symlinks from /usr will broken, so you should relink everything.
-
- 3. Read lariza-config(5), as the keybindings are radically different
- out of the box. Everything is configurable, however, and you can
- reconfigure the bindings to act just like your previous browser.
-
-From Firefox/Chromium/Brave/etc:
- 1. Set your expectations right. Read the background information
- section of the README.
-
- 2. Copy the cookie database into ~/.local/share/lariza/cookies.db.
-
- 3. Read all the manpages.
-
-Copyright
----------
-MIT License, see the LICENSE file for more information.
--- /dev/null
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <webkit2/webkit2.h>
+
+#include "config.h"
+#include "downloads.h"
+
+WebKitWebView *client_new_request(WebKitWebView *, WebKitNavigationAction *,
+ gpointer);
+gboolean crashed_web_view(WebKitWebView *, gpointer);
+gboolean decide_policy(WebKitWebView *, WebKitPolicyDecision *,
+ WebKitPolicyDecisionType, gpointer);
+gboolean key_location(GtkWidget *, GdkEvent *, gpointer);
+gboolean key_tablabel(GtkWidget *, GdkEvent *, gpointer);
+gboolean key_web_view(GtkWidget *, GdkEvent *, gpointer);
+gboolean remote_msg(GIOChannel *, GIOCondition, gpointer);
+gchar *ensure_uri_scheme(const gchar *);
+void changed_favicon(GObject *, GParamSpec *, gpointer);
+void changed_load_progress(GObject *, GParamSpec *, gpointer);
+void changed_title(GObject *, GParamSpec *, gpointer);
+void changed_uri(GObject *, GParamSpec *, gpointer);
+void grab_feeds_finished(GObject *, GAsyncResult *, gpointer);
+void hover_web_view(WebKitWebView *, WebKitHitTestResult *, guint, gpointer);
+void icon_location(GtkEntry *, GtkEntryIconPosition, GdkEvent *, gpointer);
+void mainwindow_title(gint);
+void notebook_switch_page(GtkNotebook *, GtkWidget *, guint, gpointer);
+void show_web_view(WebKitWebView *, gpointer);
+void trust_user_certs(WebKitWebContext *);
+
+struct Client {
+ GtkWidget *jsbutton;
+ GtkWidget *location;
+ GtkWidget *tabicon;
+ GtkWidget *tablabel;
+ GtkWidget *vbox;
+ GtkWidget *web_view;
+ WebKitSettings *settings;
+ gboolean focus_new_tab;
+ gchar *external_handler_uri;
+ gchar *feed_html;
+ gchar *hover_uri;
+};
+
+struct MainWindow {
+ GtkWidget *notebook;
+ GtkWidget *win;
+} mw;
+
+struct Configuration {
+ gboolean cooperative_alone;
+ gboolean noncooperative_instances;
+ gboolean private;
+ gboolean verbose;
+} cfg;
+
+gint clients = 0;
+struct Client **client_arr;
+
+int cooperative_pipe_fp = 0;
+gchar *search_text;
+gchar *fifopath;
+char **closed_tabs;
+
+void
+togglejs(GtkButton *jsbutton, gpointer data)
+{
+ struct Client *c = (struct Client *)data;
+ webkit_settings_set_enable_javascript(
+ c->settings,
+ !webkit_settings_get_enable_javascript(c->settings));
+ webkit_web_view_set_settings(WEBKIT_WEB_VIEW(c->web_view), c->settings);
+}
+
+void
+client_destroy(GtkWidget *widget, gpointer data)
+{
+ struct Client *c = (struct Client *)data;
+ gint idx;
+ g_signal_handlers_disconnect_by_func(G_OBJECT(c->web_view),
+ changed_load_progress, c);
+
+ idx = gtk_notebook_page_num(GTK_NOTEBOOK(mw.notebook), c->vbox);
+ if (idx == -1)
+ fprintf(stderr, "chorizo: Tab index was -1, bamboozled\n");
+ else
+ gtk_notebook_remove_page(GTK_NOTEBOOK(mw.notebook), idx);
+
+ if (!cfg.private && WEBKIT_IS_WEB_VIEW(c->web_view)) {
+ int len = sizeof(closed_tabs) / sizeof(char *);
+ const char *uri =
+ webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
+ closed_tabs = (char **)realloc(closed_tabs,
+ len * sizeof(closed_tabs[0]));
+ closed_tabs[len] = strdup(uri);
+ }
+
+ free(c);
+ clients--;
+
+ quit_if_nothing_active();
+}
+
+void
+set_uri(const char *uri, struct Client *c)
+{
+ if (!gtk_widget_is_focus(c->location))
+ gtk_entry_set_text(GTK_ENTRY(c->location),
+ (uri != NULL) ? uri : "");
+}
+
+WebKitWebView *
+client_new(const gchar *uri, WebKitWebView *related_wv, gboolean show,
+ gboolean focus_tab)
+{
+ struct Client *c;
+ gchar *f;
+ GtkWidget *evbox, *tabbox;
+ if (uri != NULL && !cfg.noncooperative_instances &&
+ !cfg.cooperative_alone) {
+ f = ensure_uri_scheme(uri);
+ write(cooperative_pipe_fp, f, strlen(f));
+ write(cooperative_pipe_fp, "\n", 1);
+ g_free(f);
+ return NULL;
+ }
+ c = calloc(1, sizeof(struct Client));
+ if (!c) {
+ fprintf(stderr, "chorizo: fatal: calloc failed\n");
+ exit(EXIT_FAILURE);
+ }
+ c->focus_new_tab = focus_tab;
+
+ if (related_wv == NULL) {
+ WebKitUserContentManager *ucm =
+ webkit_user_content_manager_new();
+ WebKitUserScript *wkscript;
+ WebKitUserStyleSheet *wkstyle;
+ gchar *path = NULL, *source, *base;
+ const gchar *entry = NULL;
+ GDir *dir = NULL;
+ base = g_build_filename(g_get_user_data_dir(), "chorizo",
+ "user-scripts", NULL);
+ dir = g_dir_open(base, 0, NULL);
+ if (dir != NULL) {
+ while ((entry = g_dir_read_name(dir)) != NULL) {
+ path = g_build_filename(base, entry, NULL);
+ if (g_str_has_suffix(path, ".js")) {
+ g_file_get_contents(path, &source, NULL,
+ NULL);
+ wkscript = webkit_user_script_new(
+ source,
+ WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
+ WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START,
+ NULL, NULL);
+ webkit_user_content_manager_add_script(
+ ucm, wkscript);
+ webkit_user_script_unref(wkscript);
+ }
+ g_free(path);
+ if (source)
+ g_free(source);
+ }
+ g_dir_close(dir);
+ }
+ base = g_build_filename(g_get_user_data_dir(), "chorizo",
+ "user-styles", NULL);
+ dir = g_dir_open(base, 0, NULL);
+ if (dir != NULL) {
+ while ((entry = g_dir_read_name(dir)) != NULL) {
+ path = g_build_filename(base, entry, NULL);
+ if (g_str_has_suffix(path, ".css")) {
+ g_file_get_contents(path, &source, NULL,
+ NULL);
+ wkstyle = webkit_user_style_sheet_new(
+ source,
+ WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
+ WEBKIT_USER_STYLE_LEVEL_USER,
+ NULL, NULL);
+ webkit_user_content_manager_add_style_sheet(
+ ucm, wkstyle);
+ webkit_user_style_sheet_unref(wkstyle);
+ }
+ g_free(path);
+ g_free(source);
+ }
+ g_dir_close(dir);
+ }
+ g_free(base);
+
+ c->web_view =
+ webkit_web_view_new_with_user_content_manager(ucm);
+ } else {
+ c->web_view = webkit_web_view_new_with_related_view(related_wv);
+ }
+
+ c->settings =
+ webkit_web_view_get_settings(WEBKIT_WEB_VIEW(c->web_view));
+ webkit_settings_set_enable_javascript(c->settings, cfg_js_default);
+ if (cfg.verbose) {
+ webkit_settings_set_enable_write_console_messages_to_stdout(
+ c->settings, true);
+ }
+ webkit_settings_set_enable_developer_extras(c->settings, TRUE);
+
+ g_signal_connect(G_OBJECT(c->web_view), "notify::favicon",
+ G_CALLBACK(changed_favicon), c);
+ g_signal_connect(G_OBJECT(c->web_view), "notify::title",
+ G_CALLBACK(changed_title), c);
+ g_signal_connect(G_OBJECT(c->web_view), "notify::uri",
+ G_CALLBACK(changed_uri), c);
+ g_signal_connect(G_OBJECT(c->web_view),
+ "notify::estimated-load-progress",
+ G_CALLBACK(changed_load_progress), c);
+ g_signal_connect(G_OBJECT(c->web_view), "create",
+ G_CALLBACK(client_new_request), NULL);
+ g_signal_connect(G_OBJECT(c->web_view), "close",
+ G_CALLBACK(client_destroy), c);
+ g_signal_connect(G_OBJECT(c->web_view), "decide-policy",
+ G_CALLBACK(decide_policy), NULL);
+ g_signal_connect(G_OBJECT(c->web_view), "key-press-event",
+ G_CALLBACK(key_web_view), c);
+ g_signal_connect(G_OBJECT(c->web_view), "button-release-event",
+ G_CALLBACK(key_web_view), c);
+ g_signal_connect(G_OBJECT(c->web_view), "scroll-event",
+ G_CALLBACK(key_web_view), c);
+ g_signal_connect(G_OBJECT(c->web_view), "mouse-target-changed",
+ G_CALLBACK(hover_web_view), c);
+ g_signal_connect(G_OBJECT(c->web_view), "web-process-crashed",
+ G_CALLBACK(crashed_web_view), c);
+
+ GtkWidget *locbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+ c->jsbutton = gtk_toggle_button_new_with_label("JS");
+ gtk_widget_set_tooltip_text(c->jsbutton, "Toggle JavaScript execution");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(c->jsbutton),
+ cfg_js_default);
+ g_signal_connect(G_OBJECT(c->jsbutton), "toggled", G_CALLBACK(togglejs),
+ c);
+
+ c->location = gtk_entry_new();
+ gtk_box_pack_start(GTK_BOX(locbox), c->location, TRUE, TRUE, 0);
+
+ if (cfg.private) {
+ GtkWidget *privindicator = gtk_label_new("Private mode");
+ gtk_widget_set_tooltip_text(
+ privindicator,
+ "You are in private mode. No history, caches, or "
+ "cookies will be saved beyond this session.");
+ gtk_box_pack_end(GTK_BOX(locbox), privindicator, FALSE, FALSE,
+ 5);
+ }
+ gtk_box_pack_start(GTK_BOX(locbox), c->jsbutton, FALSE, FALSE, 5);
+
+ g_signal_connect(G_OBJECT(c->location), "key-press-event",
+ G_CALLBACK(key_location), c);
+ g_signal_connect(G_OBJECT(c->location), "icon-release",
+ G_CALLBACK(icon_location), c);
+ /*
+ * XXX This is a workaround. Setting this to NULL (which is done in
+ * grab_feeds_finished() if no feed has been detected) adds a little
+ * padding left of the text. Not sure why. The point of this call
+ * right here is to have that padding right from the start. This
+ * avoids a graphical artifact.
+ */
+
+ gtk_entry_set_icon_from_icon_name(GTK_ENTRY(c->location),
+ GTK_ENTRY_ICON_SECONDARY, NULL);
+
+ c->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ gtk_box_pack_start(GTK_BOX(c->vbox), locbox, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(c->vbox), c->web_view, TRUE, TRUE, 0);
+ gtk_container_set_focus_child(GTK_CONTAINER(c->vbox), c->web_view);
+
+ c->tabicon = gtk_image_new_from_icon_name("text-html",
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+
+ c->tablabel = gtk_label_new("chorizo");
+ gtk_label_set_ellipsize(GTK_LABEL(c->tablabel), PANGO_ELLIPSIZE_END);
+ gtk_label_set_width_chars(GTK_LABEL(c->tablabel), 20);
+ gtk_widget_set_has_tooltip(c->tablabel, TRUE);
+
+ /*
+ * XXX I don't own a HiDPI screen, so I don't know if scale_factor
+ * does the right thing.
+ */
+ tabbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
+ 5 * gtk_widget_get_scale_factor(mw.win));
+ gtk_box_pack_start(GTK_BOX(tabbox), c->tabicon, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(tabbox), c->tablabel, TRUE, TRUE, 0);
+
+ evbox = gtk_event_box_new();
+ gtk_container_add(GTK_CONTAINER(evbox), tabbox);
+ g_signal_connect(G_OBJECT(evbox), "button-release-event",
+ G_CALLBACK(key_tablabel), c);
+
+ gtk_widget_add_events(evbox, GDK_SCROLL_MASK);
+ g_signal_connect(G_OBJECT(evbox), "scroll-event",
+ G_CALLBACK(key_tablabel), c);
+
+ //For easy access, store a reference to our label.
+ g_object_set_data(G_OBJECT(evbox), "chorizo-tab-label", c->tablabel);
+
+ /*
+ * This only shows the event box and the label inside, nothing else.
+ * Needed because the evbox/label is "internal" to the notebook and
+ * not part of the normal "widget tree" (IIUC).
+ */
+ gtk_widget_show_all(evbox);
+
+ int page = gtk_notebook_get_current_page(GTK_NOTEBOOK(mw.notebook)) + 1;
+ gtk_notebook_insert_page(GTK_NOTEBOOK(mw.notebook), c->vbox, evbox,
+ page);
+ gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(mw.notebook), c->vbox,
+ TRUE);
+
+ if (show)
+ show_web_view(NULL, c);
+ else
+ g_signal_connect(G_OBJECT(c->web_view), "ready-to-show",
+ G_CALLBACK(show_web_view), c);
+
+ if (uri != NULL) {
+ f = ensure_uri_scheme(uri);
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view), f);
+ g_free(f);
+ }
+ set_uri(uri, c);
+
+ clients++;
+ client_arr = realloc(client_arr, (clients + 1) * sizeof(client_arr[0]));
+ client_arr[clients] = c;
+
+ if (clients == 1 || uri == NULL)
+ gtk_widget_grab_focus(c->location);
+
+ return WEBKIT_WEB_VIEW(c->web_view);
+}
+
+WebKitWebView *
+client_new_request(WebKitWebView *web_view,
+ WebKitNavigationAction *navigation_action, gpointer data)
+{
+ return client_new(NULL, web_view, FALSE, FALSE);
+}
+
+void
+mkdirp(const char *dir, mode_t mode)
+{
+ char tmp[256];
+ char *p = NULL;
+ size_t len;
+ snprintf(tmp, sizeof(tmp), "%s", dir);
+ len = strlen(tmp);
+ if (tmp[len - 1] == '/')
+ tmp[len - 1] = 0;
+ for (p = tmp + 1; *p; p++)
+ if (*p == '/') {
+ *p = 0;
+ mkdir(tmp, mode);
+ *p = '/';
+ }
+ mkdir(tmp, S_IRWXU);
+}
+
+void
+cooperation_setup(void)
+{
+ GIOChannel *towatch;
+ gchar *fifofilename;
+
+ gchar *priv = (cfg.private) ? "-private" : "";
+ const gchar *fifo_suffix_env = g_getenv("CHORIZO_FIFO_SUFFIX");
+ const gchar *fifo_suffix = (fifo_suffix_env) ? fifo_suffix_env : "";
+ fifofilename = g_strdup_printf("%s%s%s%s", "chorizo", priv, ".fifo",
+ fifo_suffix);
+ fifopath = g_build_filename(g_get_user_runtime_dir(), "chorizo",
+ fifofilename, NULL);
+ mkdirp(dirname(fifopath), 0600);
+ g_free(fifofilename);
+
+ if (!g_file_test(fifopath, G_FILE_TEST_EXISTS))
+ mkfifo(fifopath, 0600);
+
+ cooperative_pipe_fp = open(fifopath, O_WRONLY | O_NONBLOCK);
+ if (!cooperative_pipe_fp) {
+ fprintf(stderr, "chorizo: Can't open FIFO at all.\n");
+ } else {
+ if (write(cooperative_pipe_fp, "", 0) == -1) {
+ /*
+ * Could not do an empty write to the FIFO which
+ * means there's no one listening.
+ */
+ close(cooperative_pipe_fp);
+ towatch = g_io_channel_new_file(fifopath, "r+", NULL);
+ g_io_add_watch(towatch, G_IO_IN, (GIOFunc)remote_msg,
+ NULL);
+ } else {
+ cfg.cooperative_alone = FALSE;
+ }
+ }
+}
+
+void
+changed_load_progress(GObject *obj, GParamSpec *pspec, gpointer data)
+{
+ struct Client *c = (struct Client *)data;
+ gdouble p;
+ gchar *grab_feeds =
+ "a = document.querySelectorAll('"
+ " html > head > "
+ "link[rel=\"alternate\"][href][type=\"application/atom+xml\"],"
+ " html > head > "
+ "link[rel=\"alternate\"][href][type=\"application/rss+xml\"]"
+ "');"
+ "if (a.length == 0)"
+ " null;"
+ "else {"
+ " out = '';"
+ " for (i = 0; i < a.length; i++) {"
+ " url = encodeURIComponent(a[i].href);"
+ " if ('title' in a[i] && a[i].title != '')"
+ " title = encodeURIComponent(a[i].title);"
+ " else"
+ " title = url;"
+ " out += '<li><a href=\"' + url + '\">' + title + "
+ "'</a></li>';"
+ " }"
+ " out;"
+ "}";
+ p = webkit_web_view_get_estimated_load_progress(
+ WEBKIT_WEB_VIEW(c->web_view));
+ if (p == 1) {
+ p = 0;
+
+ /*
+ * The page has loaded fully. We now run the short JavaScript
+ * snippet above that operates on the DOM. It tries to grab
+ * all occurences of <link rel="alternate" ...>, i.e.
+ * RSS/Atom feed references.
+ */
+ webkit_web_view_run_javascript(WEBKIT_WEB_VIEW(c->web_view),
+ grab_feeds, NULL,
+ grab_feeds_finished, c);
+ }
+ gtk_entry_set_progress_fraction(GTK_ENTRY(c->location), p);
+}
+
+void
+changed_favicon(GObject *obj, GParamSpec *pspec, gpointer data)
+{
+ struct Client *c = (struct Client *)data;
+ cairo_surface_t *f;
+ int w, h, w_should, h_should;
+ GdkPixbuf *pb, *pb_scaled;
+ f = webkit_web_view_get_favicon(WEBKIT_WEB_VIEW(c->web_view));
+ if (f == NULL) {
+ gtk_image_set_from_icon_name(GTK_IMAGE(c->tabicon), "text-html",
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ } else {
+ w = cairo_image_surface_get_width(f);
+ h = cairo_image_surface_get_height(f);
+ pb = gdk_pixbuf_get_from_surface(f, 0, 0, w, h);
+ if (pb != NULL) {
+ w_should = 16 * gtk_widget_get_scale_factor(c->tabicon);
+ h_should = 16 * gtk_widget_get_scale_factor(c->tabicon);
+ pb_scaled = gdk_pixbuf_scale_simple(
+ pb, w_should, h_should, GDK_INTERP_BILINEAR);
+ gtk_image_set_from_pixbuf(GTK_IMAGE(c->tabicon),
+ pb_scaled);
+
+ g_object_unref(pb_scaled);
+ g_object_unref(pb);
+ }
+ }
+}
+
+void
+changed_title(GObject *obj, GParamSpec *pspec, gpointer data)
+{
+ const gchar *t, *u;
+ struct Client *c = (struct Client *)data;
+ u = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
+ t = webkit_web_view_get_title(WEBKIT_WEB_VIEW(c->web_view));
+
+ u = u == NULL ? "chorizo" : u;
+ u = u[0] == 0 ? "chorizo" : u;
+
+ t = t == NULL ? u : t;
+ t = t[0] == 0 ? u : t;
+
+ gchar *name = malloc(strlen(t) + 4);
+ gboolean mute =
+ webkit_web_view_get_is_muted(WEBKIT_WEB_VIEW(c->web_view));
+ gchar *muted = (mute) ? "[m] " : "";
+ sprintf(name, "%s%s", muted, t);
+ gtk_label_set_text(GTK_LABEL(c->tablabel), name);
+ g_free(name);
+
+ gtk_widget_set_tooltip_text(c->tablabel, t);
+ mainwindow_title(
+ gtk_notebook_get_current_page(GTK_NOTEBOOK(mw.notebook)));
+}
+
+void
+changed_uri(GObject *obj, GParamSpec *pspec, gpointer data)
+{
+ const gchar *t;
+ struct Client *c = (struct Client *)data;
+ FILE *fp;
+ t = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
+
+ /*
+ * When a web process crashes, we get a "notify::uri" signal, but we
+ * can no longer read a meaningful URI. It's just an empty string
+ * now. Not updating the location bar in this scenario is important,
+ * because we would override the "WEB PROCESS CRASHED" message.
+ */
+ if (t != NULL && strlen(t) > 0) {
+ set_uri(t, c);
+
+ //No g_get_user_state_dir unfortunately
+ gchar *state_env = getenv("XDG_STATE_DIR");
+ gchar *state_dir = (state_env) ?
+ state_env :
+ g_build_filename(g_get_home_dir(),
+ ".local", "state",
+ "chorizo", NULL);
+
+ gchar *history_file =
+ g_build_filename(state_dir, "history", NULL);
+ if (!cfg.private) {
+ mkdirp(state_dir, 0700);
+ fp = fopen(history_file, "a");
+ if (fp != NULL) {
+ fprintf(fp, "%s\n", t);
+ fclose(fp);
+ } else {
+ perror("chorizo: Error opening history file");
+ }
+ }
+ g_free(history_file);
+ g_free(state_dir);
+ }
+}
+gboolean
+crashed_web_view(WebKitWebView *web_view, gpointer data)
+{
+ gchar *t;
+ struct Client *c = (struct Client *)data;
+ t = g_strdup_printf("WEB PROCESS CRASHED: %s",
+ webkit_web_view_get_uri(WEBKIT_WEB_VIEW(web_view)));
+ gtk_entry_set_text(GTK_ENTRY(c->location), t);
+ g_free(t);
+
+ return TRUE;
+}
+gboolean
+decide_policy(WebKitWebView *web_view, WebKitPolicyDecision *decision,
+ WebKitPolicyDecisionType type, gpointer data)
+{
+ WebKitResponsePolicyDecision *r;
+ switch (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;
+}
+
+gchar *
+ensure_uri_scheme(const gchar *t)
+{
+ gchar *f, *fabs;
+ f = g_ascii_strdown(t, -1);
+ if (!g_str_has_prefix(f, "http:") && !g_str_has_prefix(f, "https:") &&
+ !g_str_has_prefix(f, "file:") && !g_str_has_prefix(f, "about:") &&
+ !g_str_has_prefix(f, "data:") && !g_str_has_prefix(f, "webkit:")) {
+ g_free(f);
+ fabs = realpath(t, NULL);
+ if (fabs != NULL) {
+ f = g_strdup_printf("file://%s", fabs);
+ free(fabs);
+ } else {
+ f = g_strdup_printf("http://%s", t);
+ }
+ return f;
+ } else
+ return g_strdup(t);
+}
+
+void
+grab_feeds_finished(GObject *object, GAsyncResult *result, gpointer data)
+{
+ struct Client *c = (struct Client *)data;
+ WebKitJavascriptResult *js_result;
+ JSCValue *value;
+ JSCException *exception;
+ GError *err = NULL;
+ gchar *str_value;
+ g_free(c->feed_html);
+ c->feed_html = NULL;
+
+ /*
+ * This was taken almost verbatim from the example in WebKit's
+ * documentation:
+ *
+ * https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebView.html
+ */
+
+ js_result = webkit_web_view_run_javascript_finish(
+ WEBKIT_WEB_VIEW(object), result, &err);
+ if (!js_result) {
+ fprintf(stderr, "chorizo: Error running javascript: %s\n",
+ err->message);
+ g_error_free(err);
+ return;
+ }
+ value = webkit_javascript_result_get_js_value(js_result);
+ if (jsc_value_is_string(value)) {
+ str_value = jsc_value_to_string(value);
+ exception =
+ jsc_context_get_exception(jsc_value_get_context(value));
+ if (exception != NULL) {
+ fprintf(stderr,
+ "chorizo: Error running javascript: %s\n",
+ jsc_exception_get_message(exception));
+ } else {
+ c->feed_html = str_value;
+ }
+
+ gtk_entry_set_icon_from_icon_name(
+ GTK_ENTRY(c->location), GTK_ENTRY_ICON_SECONDARY,
+ "application-rss+xml-symbolic");
+ gtk_entry_set_icon_activatable(GTK_ENTRY(c->location),
+ GTK_ENTRY_ICON_SECONDARY, TRUE);
+ } else {
+ gtk_entry_set_icon_from_icon_name(
+ GTK_ENTRY(c->location), GTK_ENTRY_ICON_SECONDARY, NULL);
+ }
+
+ webkit_javascript_result_unref(js_result);
+}
+
+void
+hover_web_view(WebKitWebView *web_view, WebKitHitTestResult *ht,
+ guint modifiers, gpointer data)
+{
+ struct Client *c = (struct Client *)data;
+ const char *to_show;
+ g_free(c->hover_uri);
+
+ if (webkit_hit_test_result_context_is_link(ht)) {
+ to_show = webkit_hit_test_result_get_link_uri(ht);
+ c->hover_uri = g_strdup(to_show);
+ } else {
+ to_show = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
+ c->hover_uri = NULL;
+ }
+
+ if (!gtk_widget_is_focus(c->location))
+ set_uri(to_show, c);
+}
+
+void
+icon_location(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEvent *event,
+ gpointer data)
+{
+ struct Client *c = (struct Client *)data;
+ gchar *d;
+ gchar *data_template = "data:text/html,"
+ "<!DOCTYPE html>"
+ "<html>"
+ " <head>"
+ " <meta charset=\"UTF-8\">"
+ " <title>Feeds</title>"
+ " </head>"
+ " <body>"
+ " <p>Feeds found on this page:</p>"
+ " <ul>"
+ " %s"
+ " </ul>"
+ " </body>"
+ "</html>";
+ if (c->feed_html != NULL) {
+ /*
+ * What we're actually trying to do is show a simple HTML
+ * page that lists all the feeds on the current page. The
+ * function webkit_web_view_load_html() looks like the proper
+ * way to do that. Sad thing is, it doesn't create a history
+ * entry, but instead simply replaces the content of the
+ * current page. This is not what we want.
+ *
+ * RFC 2397 [0] defines the data URI scheme [1]. We abuse this
+ * mechanism to show my custom HTML snippet* and*create a
+ * history entry.
+ *
+ * [0]: https://tools.ietf.org/html/rfc2397 [1]:
+ * https://en.wikipedia.org/wiki/Data_URI_scheme
+ */
+
+ d = g_strdup_printf(data_template, c->feed_html);
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view), d);
+ g_free(d);
+ }
+}
+
+void
+init_default_web_context(void)
+{
+ gchar *p;
+ WebKitWebContext *wc;
+ WebKitCookieManager *cm;
+ wc = (cfg.private) ? webkit_web_context_new_ephemeral() :
+ webkit_web_context_get_default();
+
+ p = g_build_filename(g_get_user_config_dir(), "chorizo", "adblock",
+ NULL);
+ webkit_web_context_set_sandbox_enabled(wc, TRUE);
+ webkit_web_context_add_path_to_sandbox(wc, p, TRUE);
+ g_free(p);
+
+ WebKitProcessModel model =
+ WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES;
+ webkit_web_context_set_process_model(wc, model);
+
+ p = g_build_filename(g_get_user_data_dir(), "chorizo", "web-extensions",
+ NULL);
+ webkit_web_context_set_web_extensions_directory(wc, p);
+ g_free(p);
+
+ char *xdg_down = getenv("XDG_DOWNLOAD_DIR");
+ g_signal_connect(G_OBJECT(wc), "download-started",
+ G_CALLBACK(download_start),
+ (xdg_down) ? xdg_down : "/var/tmp");
+
+ trust_user_certs(wc);
+
+ cm = webkit_web_context_get_cookie_manager(wc);
+ webkit_cookie_manager_set_accept_policy(cm, cfg_cookie_policy);
+
+ if (!cfg.private) {
+ webkit_web_context_set_favicon_database_directory(wc, NULL);
+
+ gchar *fname = g_build_filename("/", g_get_user_data_dir(),
+ "chorizo", "cookies.db", NULL);
+ mkdirp(dirname(fname), 0700);
+ WebKitCookiePersistentStorage type =
+ WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE;
+ webkit_cookie_manager_set_persistent_storage(cm, fname, type);
+ g_free(fname);
+ }
+ webkit_web_context_set_spell_checking_enabled(wc, TRUE);
+}
+
+void
+search(gpointer data, gint direction)
+{
+ struct Client *c = (struct Client *)data;
+ WebKitWebView *web_view = WEBKIT_WEB_VIEW(c->web_view);
+ WebKitFindController *fc =
+ webkit_web_view_get_find_controller(web_view);
+ if (search_text == NULL)
+ return;
+
+ switch (direction) {
+ case 0:
+ webkit_find_controller_search(
+ fc, search_text,
+ WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE |
+ WEBKIT_FIND_OPTIONS_WRAP_AROUND,
+ G_MAXUINT);
+ break;
+ case 1:
+ webkit_find_controller_search_next(fc);
+ break;
+ case -1:
+ webkit_find_controller_search_previous(fc);
+ break;
+ case 2:
+ webkit_find_controller_search_finish(fc);
+ break;
+ }
+}
+
+void
+search_init(struct Client *c, int direction)
+{
+ gtk_widget_grab_focus(c->location);
+ const gchar *contents = gtk_entry_get_text(GTK_ENTRY(c->location));
+ if (strcspn(contents, "s/")) {
+ gtk_entry_set_text(GTK_ENTRY(c->location), "s/");
+ gtk_editable_set_position(GTK_EDITABLE(c->location), -1);
+ } else {
+ search(c, 0);
+ search(c, -1);
+ search(c, direction);
+ }
+}
+gboolean
+key_common(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ struct Client *c = (struct Client *)data;
+ gdouble now;
+ if (event->type == GDK_KEY_PRESS) {
+ if (((GdkEventKey *)event)->state & GDK_CONTROL_MASK) {
+ const char *uri = webkit_web_view_get_uri(
+ WEBKIT_WEB_VIEW(c->web_view));
+ int key = ((GdkEventKey *)event)->keyval;
+ if (GDK_KEY_y == key) {
+ downloadmanager_show();
+ return TRUE;
+ } else if (GDK_KEY_h == key) {
+ webkit_web_view_go_back(
+ WEBKIT_WEB_VIEW(c->web_view));
+ return TRUE;
+ } else if (GDK_KEY_l == key) {
+ webkit_web_view_go_forward(
+ WEBKIT_WEB_VIEW(c->web_view));
+ return TRUE;
+ } else if (GDK_KEY_o == key) {
+ gtk_widget_grab_focus(c->location);
+ return TRUE;
+ } else if (GDK_KEY_Print == key) {
+ WebKitPrintOperation *operation =
+ webkit_print_operation_new(
+ WEBKIT_WEB_VIEW(c->web_view));
+ GtkWidget *toplevel =
+ gtk_widget_get_toplevel(mw.win);
+ webkit_print_operation_run_dialog(
+ operation, GTK_WINDOW(toplevel));
+ return TRUE;
+ } else if (GDK_KEY_g == key) {
+ search(c, 2);
+ gtk_widget_grab_focus(c->web_view);
+ gtk_editable_set_position(
+ GTK_EDITABLE(c->location), -1);
+ if (uri)
+ gtk_entry_set_text(
+ GTK_ENTRY(c->location), uri);
+ webkit_web_view_run_javascript(
+ WEBKIT_WEB_VIEW(c->web_view),
+ "window.getSelection().removeAllRanges();"
+ "document.activeElement.blur();",
+ NULL, NULL, c);
+ return TRUE;
+ } else if (GDK_KEY_r == key) {
+ webkit_web_view_reload_bypass_cache(
+ WEBKIT_WEB_VIEW(c->web_view));
+ return TRUE;
+ } else if (GDK_KEY_j == key) {
+ for (int i = 0; i <= cfg_scroll_lines - 1;
+ i++) {
+ event->key.keyval = GDK_KEY_Down;
+ gdk_event_put(event);
+ }
+ return TRUE;
+ } else if (GDK_KEY_k == key) {
+ for (int i = 0; i <= cfg_scroll_lines - 1;
+ i++) {
+ event->key.keyval = GDK_KEY_Up;
+ gdk_event_put(event);
+ }
+ return TRUE;
+ } else if (GDK_KEY_f == key) {
+ event->key.keyval = GDK_KEY_Page_Down;
+ gdk_event_put(event);
+ return TRUE;
+ } else if (GDK_KEY_b == key) {
+ event->key.keyval = GDK_KEY_Page_Up;
+ gdk_event_put(event);
+ return TRUE;
+ } else if (GDK_KEY_s == key) {
+ search_init(c, 1);
+ return TRUE;
+ } else if (GDK_KEY_r == key) {
+ search_init(c, -1);
+ return TRUE;
+ } else if (GDK_KEY_q == key) {
+ client_destroy(NULL, c);
+ return TRUE;
+ } else if (GDK_KEY_1 == key) {
+ gtk_notebook_set_current_page(
+ GTK_NOTEBOOK(mw.notebook), 0);
+ return TRUE;
+ } else if (GDK_KEY_2 == key) {
+ gtk_notebook_set_current_page(
+ GTK_NOTEBOOK(mw.notebook), 1);
+ return TRUE;
+ } else if (GDK_KEY_3 == key) {
+ gtk_notebook_set_current_page(
+ GTK_NOTEBOOK(mw.notebook), 2);
+ return TRUE;
+ } else if (GDK_KEY_4 == key) {
+ gtk_notebook_set_current_page(
+ GTK_NOTEBOOK(mw.notebook), 3);
+ return TRUE;
+ } else if (GDK_KEY_5 == key) {
+ gtk_notebook_set_current_page(
+ GTK_NOTEBOOK(mw.notebook), 4);
+ return TRUE;
+ } else if (GDK_KEY_6 == key) {
+ gtk_notebook_set_current_page(
+ GTK_NOTEBOOK(mw.notebook), 5);
+ return TRUE;
+ } else if (GDK_KEY_7 == key) {
+ gtk_notebook_set_current_page(
+ GTK_NOTEBOOK(mw.notebook), 6);
+ return TRUE;
+ } else if (GDK_KEY_8 == key) {
+ gtk_notebook_set_current_page(
+ GTK_NOTEBOOK(mw.notebook), 7);
+ return TRUE;
+ } else if (GDK_KEY_9 == key) {
+ gtk_notebook_set_current_page(
+ GTK_NOTEBOOK(mw.notebook), 8);
+ return TRUE;
+ } else if (GDK_KEY_u == key) {
+ gtk_notebook_prev_page(
+ GTK_NOTEBOOK(mw.notebook));
+ return TRUE;
+ } else if (GDK_KEY_m == key) {
+ gboolean muted = webkit_web_view_get_is_muted(
+ WEBKIT_WEB_VIEW(c->web_view));
+ webkit_web_view_set_is_muted(
+ WEBKIT_WEB_VIEW(c->web_view), !muted);
+ changed_title(G_OBJECT(c->web_view), NULL, c);
+ return TRUE;
+ } else if (GDK_KEY_t == key) {
+ client_new(cfg_home_uri, NULL, TRUE, TRUE);
+ return TRUE;
+ } else if (GDK_KEY_bracketleft == key) {
+ if (!closed_tabs)
+ return TRUE;
+ int len = sizeof(closed_tabs) / sizeof(char *);
+ if (len < 1)
+ return TRUE;
+ client_new(closed_tabs[len], NULL, TRUE, TRUE);
+ free(closed_tabs[len]);
+ closed_tabs = (char **)realloc(
+ closed_tabs,
+ (len - 1) * sizeof(closed_tabs[0]));
+ return TRUE;
+ } else if (GDK_KEY_i == key) {
+ gtk_notebook_next_page(
+ GTK_NOTEBOOK(mw.notebook));
+ return TRUE;
+ } else if (GDK_KEY_p == key) {
+ gboolean on =
+ webkit_settings_get_enable_javascript(
+ c->settings);
+ webkit_settings_set_enable_javascript(
+ c->settings, !on);
+ webkit_web_view_set_settings(
+ WEBKIT_WEB_VIEW(c->web_view),
+ c->settings);
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(c->jsbutton), !on);
+ } else if (GDK_KEY_d == key) {
+ gtk_widget_grab_focus(c->location);
+ gtk_entry_set_text(GTK_ENTRY(c->location),
+ "w/");
+ gtk_editable_set_position(
+ GTK_EDITABLE(c->location), -1);
+ return TRUE;
+ } else if (GDK_KEY_equal == key) {
+ now = webkit_web_view_get_zoom_level(
+ WEBKIT_WEB_VIEW(c->web_view));
+ webkit_web_view_set_zoom_level(
+ WEBKIT_WEB_VIEW(c->web_view),
+ now + 0.1);
+ return TRUE;
+ } else if (GDK_KEY_minus == key) {
+ now = webkit_web_view_get_zoom_level(
+ WEBKIT_WEB_VIEW(c->web_view));
+ webkit_web_view_set_zoom_level(
+ WEBKIT_WEB_VIEW(c->web_view),
+ now - 0.1);
+ return TRUE;
+ } else if (GDK_KEY_0 == key) {
+ webkit_web_view_set_zoom_level(
+ WEBKIT_WEB_VIEW(c->web_view), 1);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+gboolean
+key_location(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ struct Client *c = (struct Client *)data;
+ const gchar *t;
+ if (key_common(widget, event, data))
+ return TRUE;
+
+ if (event->type == GDK_KEY_PRESS) {
+ int key = ((GdkEventKey *)event)->keyval;
+ if ((GDK_KEY_KP_Enter == key) || (GDK_KEY_Return == key)) {
+ gtk_widget_grab_focus(c->web_view);
+ t = gtk_entry_get_text(GTK_ENTRY(c->location));
+ if (t != NULL && t[0] == 's' && t[1] == '/') {
+ if (search_text != NULL)
+ g_free(search_text);
+ search_text = g_strdup(t + 2);
+ search(c, 0);
+ } else if (t != NULL && t[0] == 'w' && t[1] == '/') {
+ int len = strlen(cfg_search_engine) +
+ strlen(t) - 2;
+ gchar *f = malloc(len + 1);
+ snprintf(f, len + 1, "%s%s", cfg_search_engine,
+ t + 2);
+ webkit_web_view_load_uri(
+ WEBKIT_WEB_VIEW(c->web_view), f);
+ g_free(f);
+ } else {
+ webkit_web_view_load_uri(
+ WEBKIT_WEB_VIEW(c->web_view),
+ ensure_uri_scheme(t));
+ }
+ return TRUE;
+ } else if (GDK_KEY_Escape == key) {
+ t = webkit_web_view_get_uri(
+ WEBKIT_WEB_VIEW(c->web_view));
+ gtk_entry_set_text(GTK_ENTRY(c->location),
+ (t == NULL) ? "" : t);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+gboolean
+key_tablabel(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ GdkScrollDirection direction;
+ if (event->type == GDK_BUTTON_RELEASE) {
+ switch (((GdkEventButton *)event)->button) {
+ case 2:
+ client_destroy(NULL, data);
+ return TRUE;
+ }
+ } else if (event->type == GDK_SCROLL) {
+ gdk_event_get_scroll_direction(event, &direction);
+ switch (direction) {
+ case GDK_SCROLL_UP:
+ gtk_notebook_prev_page(GTK_NOTEBOOK(mw.notebook));
+ break;
+ case GDK_SCROLL_DOWN:
+ gtk_notebook_next_page(GTK_NOTEBOOK(mw.notebook));
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+gboolean
+key_web_view(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ struct Client *c = (struct Client *)data;
+ gdouble dx, dy;
+ gfloat z;
+ if (key_common(widget, event, data))
+ return TRUE;
+
+ if (event->type == GDK_KEY_PRESS) {
+ if (((GdkEventKey *)event)->keyval == GDK_KEY_Escape) {
+ webkit_web_view_stop_loading(
+ WEBKIT_WEB_VIEW(c->web_view));
+ gtk_entry_set_progress_fraction(GTK_ENTRY(c->location),
+ 0);
+ }
+ } else if (event->type == GDK_BUTTON_RELEASE) {
+ GdkModifierType modifiers =
+ gtk_accelerator_get_default_mod_mask();
+ switch (((GdkEventButton *)event)->button) {
+ case 1:
+ if ((((GdkEventButton *)event)->state & modifiers) ==
+ GDK_CONTROL_MASK &&
+ c->hover_uri != NULL) {
+ client_new(c->hover_uri, NULL, TRUE, FALSE);
+ return TRUE;
+ }
+ break;
+ case 8:
+ webkit_web_view_go_back(WEBKIT_WEB_VIEW(c->web_view));
+ return TRUE;
+ case 9:
+ webkit_web_view_go_forward(
+ WEBKIT_WEB_VIEW(c->web_view));
+ return TRUE;
+ }
+ } else if (event->type == GDK_SCROLL) {
+ event->scroll.delta_y *= cfg_scroll_lines;
+ if (((GdkEventScroll *)event)->state & GDK_CONTROL_MASK) {
+ gdk_event_get_scroll_deltas(event, &dx, &dy);
+ z = webkit_web_view_get_zoom_level(
+ WEBKIT_WEB_VIEW(c->web_view));
+ z += -dy * 0.1;
+ z = dx != 0 ? 1 : z;
+ webkit_web_view_set_zoom_level(
+ WEBKIT_WEB_VIEW(c->web_view), z);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void
+mainwindow_setup(void)
+{
+ mw.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size(GTK_WINDOW(mw.win), 800, 600);
+ g_signal_connect(G_OBJECT(mw.win), "destroy", gtk_main_quit, NULL);
+
+ gchar *priv = (cfg.private) ? "-private" : "";
+ gchar *title = malloc(strlen(priv) + 7);
+ sprintf(title, "%s%s", "chorizo", priv);
+ gtk_window_set_title(GTK_WINDOW(mw.win), title);
+ g_free(title);
+
+ mw.notebook = gtk_notebook_new();
+ gtk_notebook_set_scrollable(GTK_NOTEBOOK(mw.notebook), TRUE);
+ gtk_container_add(GTK_CONTAINER(mw.win), mw.notebook);
+ g_signal_connect(G_OBJECT(mw.notebook), "switch-page",
+ G_CALLBACK(notebook_switch_page), NULL);
+}
+
+void
+mainwindow_title(gint idx)
+{
+ GtkWidget *child, *widg, *tablabel;
+ const gchar *text;
+ child = gtk_notebook_get_nth_page(GTK_NOTEBOOK(mw.notebook), idx);
+ if (child == NULL)
+ return;
+
+ widg = gtk_notebook_get_tab_label(GTK_NOTEBOOK(mw.notebook), child);
+ tablabel = (GtkWidget *)g_object_get_data(G_OBJECT(widg),
+ "chorizo-tab-label");
+ text = gtk_label_get_text(GTK_LABEL(tablabel));
+ gtk_window_set_title(GTK_WINDOW(mw.win), text);
+}
+
+void
+notebook_switch_page(GtkNotebook *nb, GtkWidget *p, guint idx, gpointer data)
+{
+ mainwindow_title(idx);
+}
+gboolean
+quit_if_nothing_active(void)
+{
+ if (clients == 0) {
+ if (downloads == 0) {
+ gtk_main_quit();
+ return TRUE;
+ } else {
+ downloadmanager_show();
+ }
+ }
+ return FALSE;
+}
+gboolean
+remote_msg(GIOChannel *channel, GIOCondition condition, gpointer data)
+{
+ gchar *uri = NULL;
+ g_io_channel_read_line(channel, &uri, NULL, NULL, NULL);
+ if (uri) {
+ g_strstrip(uri);
+ client_new(uri, NULL, TRUE, TRUE);
+ g_free(uri);
+ }
+ return TRUE;
+}
+
+void
+show_web_view(WebKitWebView *web_view, gpointer data)
+{
+ struct Client *c = (struct Client *)data;
+ gint idx;
+ (void)web_view;
+
+ gtk_widget_show_all(mw.win);
+
+ if (c->focus_new_tab) {
+ idx = gtk_notebook_page_num(GTK_NOTEBOOK(mw.notebook), c->vbox);
+ if (idx != -1)
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(mw.notebook),
+ idx);
+
+ gtk_widget_grab_focus(c->web_view);
+ }
+}
+
+void
+trust_user_certs(WebKitWebContext *wc)
+{
+ GTlsCertificate *cert;
+ gchar *basedir, *absfile;
+ const gchar *file;
+ GDir *dir = NULL;
+ basedir = g_build_filename(g_get_user_data_dir(), "chorizo", "certs",
+ NULL);
+ dir = g_dir_open(basedir, 0, NULL);
+ g_free(basedir);
+ if (dir != NULL) {
+ file = g_dir_read_name(dir);
+ while (file != NULL) {
+ absfile = g_build_filename(g_get_user_data_dir(),
+ "chorizo", "certs", file,
+ NULL);
+ cert = g_tls_certificate_new_from_file(absfile, NULL);
+ g_free(absfile);
+ if (cert == NULL)
+ fprintf(stderr,
+ "chorizo: Could not load trusted cert '%s'\n",
+ file);
+ else
+ webkit_web_context_allow_tls_certificate_for_host(
+ wc, cert, file);
+ file = g_dir_read_name(dir);
+ }
+ g_dir_close(dir);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int opt, i;
+
+ //TODO:pretty this
+ cfg.noncooperative_instances = FALSE;
+ cfg.cooperative_alone = TRUE;
+
+ while ((opt = getopt(argc, argv, "cpvV")) != -1) {
+ switch (opt) {
+ case 'c':
+ cfg.noncooperative_instances = TRUE;
+ break;
+ case 'p':
+ cfg.private = TRUE;
+ break;
+ case 'v':
+ cfg.verbose = TRUE;
+ break;
+ case 'V':
+ printf("%s %s\n", "chorizo", VERSION);
+ exit(0);
+ default:
+ fprintf(stderr,
+ "Usage: chorizo [OPTION]... [URI]...\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ gtk_init(&argc, &argv);
+
+ //Keep clipboard contents after program closes
+ gtk_clipboard_store(gtk_clipboard_get_for_display(
+ gdk_display_get_default(), GDK_SELECTION_CLIPBOARD));
+
+ if (!cfg.noncooperative_instances)
+ cooperation_setup();
+
+ if (cfg.noncooperative_instances || cfg.cooperative_alone)
+ init_default_web_context();
+
+ downloadmanager_setup();
+ mainwindow_setup();
+
+ client_arr = malloc(sizeof(struct Client *));
+ if (optind >= argc) {
+ client_new(cfg_home_uri, NULL, TRUE, TRUE);
+ } else {
+ for (i = optind; i < argc; i++)
+ client_new(argv[i], NULL, TRUE, TRUE);
+ }
+
+ if (cfg.noncooperative_instances || cfg.cooperative_alone) {
+ gtk_main();
+ remove(fifopath);
+ }
+ for (int i = 0; i < clients; i++) {
+ free(&(client_arr[i]));
+ }
+
+ exit(EXIT_SUCCESS);
+}
--- /dev/null
+.TH "chorizo-usage" "7" "2021-10-11"
+.P
+.SH NAME
+chorizo-usage - extended usage hints
+.P
+.SH DESCRIPTION
+\fBchorizo\fR is a simple web browser using GTK+ 3, GLib and WebKit2GTK+.\& This
+manpage contains additional hints and pointers regarding its usage.\&
+.P
+.SH DOWNLOAD MANAGER
+Open the download manager using the appropriate hotkey.\& A new window listing
+your downloads will appear.\& Clicking on an item will remove it from the list and
+\fB\fRif needed\fB\fR cancel the download.\&
+.P
+There's no file manager integration, nor does \fBchorizo\fR delete, overwrite or
+resume downloads.\& If a file already exists, it won't be touched.\& Instead, the
+new file name will have a suffix such as \fB.\&1\fR, \fB.\&2\fR, \fB.\&3\fR, and so on.\&
+.P
+.SH USER-SUPPLIED JAVASCRIPT FILES
+When a page is being loaded, the directory \fI~/.\&local/share/chorizo/user-scripts\fR
+will be scanned and each file in it ending with \fB.\&js\fR will be run as a
+JavaScript file in the context of said page.\&
+.P
+\fBchorizo\fR comes with the following scripts:
+.P
+\fBhints.\&js\fR
+.RS 4
+Press \fBf\fR (open link in current window) or \fBF\fR (open in new window) to
+activate link hints.\& After typing the characters for one of them, press
+\fBEnter\fR to confirm.\& Press \fBEscape\fR to abort.\&
+.P
+.RE
+\fBprivacy-redirect.\&js\fR
+.RS 4
+Redirects YouTube, Reddit, etc to privacy respecting alternatives.\&
+.P
+.RE
+\fBdarkreader.\&js\fR
+.RS 4
+See https://darkreader.\&org.\&
+.P
+.RE
+Those bundled scripts are automatically installed on \fBmake install\fR.\& To use
+them, though, make sure to link them to the directory mentioned above.\&
+.P
+.SH USER-SUPPLIED CSS FILES
+User supplied CSS files will be scanned for from
+\fI~/.\&local/share/chorizo/user-styles\fR, and be applied every time a page
+loads.\& The rules in these files override any rules provided by the website.\&
+.P
+.SH WEB EXTENSIONS
+On startup, WebKit checks \fI~/.\&local/share/chorizo/web-extensions\fR for any \fB.\&so\fR
+files.\& See
+<http://blogs.\&igalia.\&com/carlosgc/2013/09/10/webkit2gtk-web-process-extensions/>
+this blog post for further information on these extensions.\&
+.P
+\fBchorizo\fR comes with the following extensions:
+.P
+\fBwe_adblock.\&so\fR
+.RS 4
+Generic adblock.\& Reads patterns from the file \fI~/.\&config/chorizo/adblock\fR.\& Each
+line can contain a regular expression.\& These expressions match
+case-insensitive and partially, i.\&e.\&\fB*foo.\&*\fR is the same as \fB.\&*FOO.\&*\fR and
+you can use anchors like \fB^https?\&://.\&.\&.\&\fR.\& Please refer to
+https://developer.\&gnome.\&org/glib/stable/glib-regex-syntax.\&html the GLib
+reference for more details.\& Lines starting with "#" are ignored.\&
+.P
+Those bundled web extensions are automatically compiled when you run \fBmake\fR
+and installed on \fBmake install\fR.\& To use them, though, make sure to link them
+to the directory mentioned above.\&
+.P
+.RE
+.SH TRUSTED CERTIFICATES
+By default, \fBchorizo\fR trusts whatever CAs are trusted by WebKit.\& If you wish to
+trust additional certificates, such as self-signed certificates, the first thing
+you should do is try to add the appropriate CAs to your system-wide store.\&
+.P
+If you wish to add simple exceptions, you can grab the certificate and store it
+in the directory \fI~/.\&local/share/chorizo/certs\fR.\& The filename must be equal to
+the hostname:
+.P
+.RS 4
+$ echo | openssl s_client -connect foo.\&de:443 | openssl x509 >foo.\&de
+.P
+.RE
+This tells \fBchorizo\fR to trust the given certificate when connecting to host
+\fBfoo.\&de\fR.\&
+.P
+Note: This is NOT equal to certificate pinning.\& WebKit ignores user-specified
+certificates if the server's certificate can be validated by any system-wide CA.\&
+.P
+.SH SEE ALSO
+\fBchorizo\fR(1), \fBchorizo-config\fR(5)
--- /dev/null
+.TH "chorizo" "1" "2021-10-11"
+.P
+.SH NAME
+chorizo - simple web browser
+.P
+.SH SYNOPSIS
+\fBchorizo\fR - [-C] [\fIURI .\&.\&.\&\fR]
+.P
+.SH DESCRIPTION
+\fBchorizo\fR is a simple web browser using GTK+ 3, GLib and WebKit2GTK+.\&
+.P
+.SH OPTIONS
+In addition to the standard arguments of GTK+ 3, \fBchorizo\fR knows about the
+following options:
+.P
+\fB-C\fR
+.RS 4
+Disables cooperative instances.\&
+.P
+.RE
+\fB-p\fR
+.RS 4
+Launch a private window.\&
+.P
+.RE
+\fB-v\fR
+.RS 4
+Print version and exit.\&
+.P
+.RE
+After these options there can be any number of URIs specified to open.\&
+.P
+.SH ENVIRONMENT
+In addition to the standard variables of GTK+ 3, \fBchorizo\fR knows about the
+following environment variable:
+.P
+\fBCHORIZO_FIFO_SUFFIX\fR
+.RS 4
+Cooperative instances are implemented using a named pipe in the file
+system.\& The name of this pipe usually is (at least on modern systems following
+XDG standards: /var/run/user/$UID/chorizo.\&fifo-$CHORIZO_FIFO_SUFFIX
+.P
+\fB$UID\fR is the id of your user.\& \fB$CHORIZO_FIFO_SUFFIX\fR defaults to \fBmain\fR.\& If you
+change this variable, you can launch several independent cooperative instances
+of \fBchorizo\fR.\&
+.P
+.RE
+.SH FILES
+XDG variables will be used to construct these paths.\&
+\fB~/.\&config/chorizo/chorizo.\&ini\fR
+.RS 4
+Configuration file.\& See \fBchorizo-config\fR(5).\&
+.P
+.RE
+\fB~/.\&config/chorizo/adblock\fR
+.RS 4
+Adblock patterns.\& See \fBchorizo-usage\fR(1).\&
+.P
+.RE
+\fB~/.\&local/share/chorizo/certs\fR
+.RS 4
+Directory where trusted certificates are stored.\& See \fBchorizo-usage\fR(1).\&
+.P
+.RE
+\fB~/.\&local/share/chorizo/cookies.\&db\fR
+.RS 4
+Database where cookies are stored.\& It is kept in the same format as Firefox,
+so the file can easily be copied over.\&
+.P
+.RE
+\fB~/.\&local/share/chorizo/user-scripts\fR
+.RS 4
+Directory to store user-supplied JavaScript snippets.\& See \fBchorizo-usage\fR(1).\&
+.P
+.RE
+\fB~/.\&local/share/chorizo/user-styles\fR
+.RS 4
+Directory to store user-supplied CSS snippets.\& See \fBchorizo-usage\fR(1).\&
+.P
+.RE
+\fB~/.\&local/share/chorizo/web-extensions\fR
+.RS 4
+Sets the directory where WebKit will look for web extensions.\& See
+\fBchorizo-usage\fR(1).\&
+.P
+.RE
+\fB~/.\&cache/chorizo\fR
+\fB~/.\&cache/webkitgtk\fR
+.RS 4
+General caches.\&
+.P
+.RE
+\fB~/.\&local/share/webkitgtk\fR
+.RS 4
+WebKitGTK will dump its caches and local storage here.\& It is probably wise to
+clean those directories regularly or to mount them as \fBtmpfs\fR(5).\&
+.P
+.RE
+.SH LICENSE
+\fBchorizo\fR is released under the MIT license.\& See the accompanying LICENSE file.\&
+.P
+.SH HISTORY
+chorizo is a fork of the lariza browser by Peter Hofmann.\& The project was
+started in June 2014.\& This fork is maintained by Armaan Bhojwani.\&
+.P
+.SH SEE ALSO
+\fBchorizo-usage\fR(1), \fBchorizo-config\fR(5)
+++ /dev/null
-# Based on vimb / chromium's desktop entry
-[Desktop Entry]
-Name=chorizo
-GenericName=Web Browser
-Comment=Access the Internet
-Exec=chorizo %U
-Terminal=false
-Icon=
-Type=Application
-Categories=GTK;Network;WebBrowser;
-MimeType=text/html;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;
\ No newline at end of file
+++ /dev/null
-# chorizo browser example configuration file. A full list of options
-# can be found in chorizo-config(5).
-
-# [browser]
-# homepage=https://duckduckgo.com
-# console_to_stdout=true
-
-# [ui]
-# tab_width=25
-# zoom_level=1.25
-
-# [keybindings]
-# download_manager=m
\ No newline at end of file
--- /dev/null
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#define VERSION "1.1.0"
+gboolean cfg_js_default = TRUE;
+//Should JavaScript be enabled by default
+WebKitCookieAcceptPolicy cfg_cookie_policy = WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS;
+//Cookie policy
+gchar *cfg_home_uri = NULL;
+//Default URI
+int cfg_scroll_lines = 3;
+//Number of lines to scroll at a time
+gchar *cfg_search_engine = "https://searx.be/search?q=";
+//Search engine
+
+#endif
--- /dev/null
+#include <webkit2/webkit2.h>
+
+#include "downloads.h"
+
+gboolean download_handle(WebKitDownload *, gchar *, gpointer);
+void download_click(GtkToolButton *, gpointer);
+void download_cancel(GtkMenuItem *, gpointer);
+gboolean downloadmanager_delete(GtkWidget *, gpointer);
+
+struct DownloadManager {
+ GtkWidget *scroll;
+ GtkWidget *toolbar;
+ GtkWidget *win;
+} dm;
+
+gint downloads = 0;
+
+struct DownloadItem {
+ GtkToolButton *tb;
+ WebKitDownload *download;
+};
+gboolean
+key_downloadmanager(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ if (event->type == GDK_KEY_PRESS) {
+ if (((GdkEventKey *)event)->state & GDK_CONTROL_MASK) {
+ int key = ((GdkEventKey *)event)->keyval;
+ if ((GDK_KEY_q == key) || (GDK_KEY_y == key)) {
+ downloadmanager_delete(dm.win, NULL);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+void
+changed_download_progress(GObject *obj, GParamSpec *pspec, gpointer data)
+{
+ WebKitDownload *download = WEBKIT_DOWNLOAD(obj);
+ WebKitURIResponse *resp;
+ GtkToolItem *tb = GTK_TOOL_ITEM(data);
+ gdouble p, size_mb;
+ const gchar *uri;
+ gchar *t, *filename, *base;
+ p = webkit_download_get_estimated_progress(download);
+ p = p > 1 ? 1 : p;
+ p = p < 0 ? 0 : p;
+ p *= 100;
+ resp = webkit_download_get_response(download);
+ size_mb = webkit_uri_response_get_content_length(resp) / 1e6;
+
+ uri = webkit_download_get_destination(download);
+ filename = g_filename_from_uri(uri, NULL, NULL);
+ base = g_path_get_basename(filename);
+ t = g_strdup_printf("%s (%.0f%% of %.1f MB)", base, p, size_mb);
+ g_free(filename);
+ g_free(base);
+ gtk_tool_button_set_label(GTK_TOOL_BUTTON(tb), t);
+ g_free(t);
+}
+
+void
+download_finished(WebKitDownload *download, gpointer data)
+{
+ if (strcmp(gtk_tool_button_get_icon_name(GTK_TOOL_BUTTON(data)),
+ "dialog-error") != 0)
+ gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(data),
+ "emblem-downloads");
+ downloads--;
+}
+
+void
+download_start(WebKitWebView *web_view, WebKitDownload *download, gpointer data)
+{
+ g_signal_connect(G_OBJECT(download), "decide-destination",
+ G_CALLBACK(download_handle), data);
+}
+gboolean
+download_handle(WebKitDownload *download, gchar *suggested_filename,
+ gpointer data)
+{
+ gchar *uri;
+ GtkToolItem *tb;
+
+ GtkWidget *chooser = gtk_file_chooser_dialog_new(
+ "Choose download location", GTK_WINDOW(dm.win),
+ GTK_FILE_CHOOSER_ACTION_SAVE, "Save file", GTK_RESPONSE_ACCEPT,
+ "Cancel", GTK_RESPONSE_CANCEL, NULL);
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser),
+ (char *)data);
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(chooser),
+ suggested_filename);
+ gtk_file_chooser_set_do_overwrite_confirmation(
+ GTK_FILE_CHOOSER(chooser), TRUE);
+ gint res = gtk_dialog_run(GTK_DIALOG(chooser));
+ switch (res) {
+ case GTK_RESPONSE_ACCEPT:
+ uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(chooser));
+ webkit_download_set_destination(
+ download,
+ gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(chooser)));
+ break;
+ case GTK_RESPONSE_CANCEL:
+ return FALSE;
+ default:
+ return FALSE;
+ }
+
+ gtk_widget_destroy(chooser);
+
+ remove(uri + 7);
+ tb = gtk_tool_button_new(NULL, NULL);
+ gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(tb), "network-receive");
+ gtk_tool_button_set_label(GTK_TOOL_BUTTON(tb), uri);
+ gtk_toolbar_insert(GTK_TOOLBAR(dm.toolbar), tb, 0);
+ gtk_widget_show_all(dm.win);
+
+ g_signal_connect(G_OBJECT(download), "notify::estimated-progress",
+ G_CALLBACK(changed_download_progress), tb);
+
+ downloads++;
+ g_signal_connect(G_OBJECT(download), "finished",
+ G_CALLBACK(download_finished), tb);
+
+ g_object_ref(download);
+
+ struct DownloadItem *payload = malloc(sizeof(*payload));
+ payload->tb = (GtkToolButton *)tb;
+ payload->download = download;
+ g_signal_connect(G_OBJECT(tb), "clicked", G_CALLBACK(download_click),
+ payload);
+ g_signal_connect(G_OBJECT(tb), "failed", G_CALLBACK(download_cancel),
+ payload);
+ g_signal_connect(G_OBJECT(tb), "destroy_event", G_CALLBACK(g_free),
+ payload);
+
+ //Propagate-- to whom it may concern.
+ return FALSE;
+}
+
+void
+download_cancel(GtkMenuItem *tb, gpointer data)
+{
+ struct DownloadItem *payload = data;
+ gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(payload->tb),
+ "dialog-error");
+ webkit_download_cancel(payload->download);
+}
+
+void
+download_remove(GtkMenuItem *tb, gpointer data)
+{
+ struct DownloadItem *payload = data;
+ g_object_unref(payload->download);
+ gtk_widget_destroy(GTK_WIDGET(payload->tb));
+}
+
+void
+download_copy_url(GtkMenuItem *tb, gpointer data)
+{
+ struct DownloadItem *payload = data;
+ WebKitURIRequest *req = webkit_download_get_request(payload->download);
+ const gchar *uri = webkit_uri_request_get_uri(req);
+ gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), uri,
+ strlen(uri));
+}
+
+void
+download_copy_path(GtkMenuItem *tb, gpointer data)
+{
+ struct DownloadItem *payload = data;
+ const gchar *path = webkit_download_get_destination(payload->download);
+ gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
+ path + 7, strlen(path) - 7);
+ //Offset by 7 to remove "file://"
+}
+
+void
+download_xdg_open(GtkMenuItem *tb, gpointer data)
+{
+ struct DownloadItem *payload = data;
+ const gchar *path = webkit_download_get_destination(payload->download);
+ char *cmd = malloc(strlen(path) + 9);
+ sprintf(cmd, "xdg-open %s", path);
+ system(cmd);
+}
+
+void
+download_click(GtkToolButton *tb, gpointer data)
+{
+ GtkWidget *pmenu = gtk_menu_new();
+ GtkWidget *option;
+ if (strcmp(gtk_tool_button_get_icon_name(GTK_TOOL_BUTTON(tb)),
+ "network-receive") == 0) {
+ option = gtk_menu_item_new_with_label("Cancel download");
+ g_signal_connect(G_OBJECT(option), "activate",
+ G_CALLBACK(download_cancel), data);
+ gtk_widget_show(option);
+ gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
+ } else {
+ option = gtk_menu_item_new_with_label("Remove download");
+ g_signal_connect(G_OBJECT(option), "activate",
+ G_CALLBACK(download_remove), data);
+ gtk_widget_show(option);
+ gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
+
+ option =
+ gtk_menu_item_new_with_label("Open file with xdg-open");
+ gtk_widget_show(option);
+ gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
+ g_signal_connect(G_OBJECT(option), "activate",
+ G_CALLBACK(download_xdg_open), data);
+ }
+
+ option = gtk_menu_item_new_with_label("Copy download URL");
+ gtk_widget_show(option);
+ gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
+ g_signal_connect(G_OBJECT(option), "activate",
+ G_CALLBACK(download_copy_url), data);
+
+ option = gtk_menu_item_new_with_label("Copy local path");
+ gtk_widget_show(option);
+ gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
+ g_signal_connect(G_OBJECT(option), "activate",
+ G_CALLBACK(download_copy_path), data);
+
+ gtk_menu_popup_at_pointer(GTK_MENU(pmenu), NULL);
+}
+gboolean
+downloadmanager_delete(GtkWidget *obj, gpointer data)
+{
+ if (!quit_if_nothing_active())
+ gtk_widget_hide(dm.win);
+
+ return TRUE;
+}
+
+void
+downloadmanager_setup(void)
+{
+ dm.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_type_hint(GTK_WINDOW(dm.win),
+ GDK_WINDOW_TYPE_HINT_DIALOG);
+ gtk_window_set_default_size(GTK_WINDOW(dm.win), 500, 250);
+ gtk_window_set_title(GTK_WINDOW(dm.win), "chorizo - Download Manager");
+ g_signal_connect(G_OBJECT(dm.win), "delete-event",
+ G_CALLBACK(downloadmanager_delete), NULL);
+ g_signal_connect(G_OBJECT(dm.win), "key-press-event",
+ G_CALLBACK(key_downloadmanager), NULL);
+
+ dm.toolbar = gtk_toolbar_new();
+ gtk_orientable_set_orientation(GTK_ORIENTABLE(dm.toolbar),
+ GTK_ORIENTATION_VERTICAL);
+ gtk_toolbar_set_style(GTK_TOOLBAR(dm.toolbar), GTK_TOOLBAR_BOTH_HORIZ);
+ gtk_toolbar_set_show_arrow(GTK_TOOLBAR(dm.toolbar), FALSE);
+
+ dm.scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dm.scroll),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_container_add(GTK_CONTAINER(dm.scroll), dm.toolbar);
+
+ gtk_container_add(GTK_CONTAINER(dm.win), dm.scroll);
+}
+
+void
+downloadmanager_show(void)
+{
+ gtk_widget_show_all(dm.win);
+}
--- /dev/null
+extern int downloads;
+gboolean quit_if_nothing_active(void);
+void download_start(WebKitWebView *, WebKitDownload *, gpointer);
+void downloadmanager_setup(void);
+void downloadmanager_show(void);
GIOChannel *channel = NULL;
gchar *path = NULL, *buf = NULL;
- path = g_build_filename(g_get_user_config_dir(), __NAME__, "adblock", NULL);
+ path = g_build_filename(g_get_user_config_dir(), "chorizo", "adblock", NULL);
channel = g_io_channel_new_file(path, "r", &err);
if (channel != NULL) {
while (g_io_channel_read_line(channel, &buf, NULL, NULL, NULL) ==
re = g_regex_new(buf, G_REGEX_CASELESS | G_REGEX_OPTIMIZE,
G_REGEX_MATCH_PARTIAL, &err);
if (err != NULL) {
- fprintf(stderr, __NAME__ ": Could not compile regex: %s\n",
+ fprintf(stderr, "chorizo: Could not compile regex: %s\n",
buf);
g_error_free(err);
err = NULL;
+++ /dev/null
-chorizo-config(5)
-
-# NAME
-_chorizo.ini_ - configuration file for *chorizo*(1)
-
-# DESCRIPTION
-_chorizo.ini_ is the system configuration file for the chorizo browser. The syntax
-is the standard GTK ini format. An example is provided at
-_/usr/share/doc/chorizo/chorizo.ini_, and user configuration should go in
-_~/.config/chorizo/chorizo.ini_, or your equivalent as set by
-$XDG_CONFIG_DIR. Settings must go under the relevant subsection.
-
-# OPTIONS
-## BROWSER
-*console_to_stdout*++
- Type: boolean++
- Default: false++
- Print the contents of the browser console to stdout.
-
-*cookie_policy*++
- Type: string++
- Default: "no_third_party"++
- Options: "all", "none", "no_third_party"++
- Determines what cookies are accepted.
-
-*history_file*++
- Type: string++
- Default: none++
- File that chorizo should save history to.
-
-*homepage*++
- Type: string++
- Default: "about:blank"++
- Set the default URI for new tabs.
-
-*images_enabled*++
- Type: boolean++
- Default: true++
- Determines whether or not images are enabled by default.
-
-*javascript_can_access_clipboard*++
- Type: boolean++
- Default: false++
- Determines whether or not JavaScript can access the clipboard. Necessary for
- websites like gDrive, and "click to copy" buttons
-
-*javascript_enabled*++
- Type: boolean++
- Default: true++
- Determines whether or not JavaScript is enabled by default.
-
-*search_engine*++
- Type: string++
- Default: "https://duckduckgo.com?q="++
- What search engine to use when searching with "w/".
-
-*spellcheck_enabled*++
- Type: boolean++
- Default: true++
- Disable spell checking.
-
-*spellcheck_language*++
- Type: string++
- Default: "en_US;"++
- Language to use for spell checking.
-
-*user_agent*++
- Type: string++
- Default: the WebKit default++
- Choose a custom user agent.
-
-*webgl_enabled*++
- Type: boolean++
- Default: true++
- Determines whether or not WebGL is enabled.
-
-## UI
-*default_uri*++
- Type: string++
- Default: "https://"++
- The URI to fill the location bar with when entering the it from the homepage.
-
-*font_family_default*++
- Type: string++
- Default: "sans-serif"++
- Default font family.
-
-*font_family_default_monospace*++
- Type: string++
- Default: "monospace"++
- Default monospace font family
-
-*font_family_default_sans_serif*++
- Type: string++
- Default: "sans-serif"++
- Default sans-serif font family
-
-*font_family_default_serif*++
- Type: string++
- Default: "serif"++
- Default serif font family
-
-*font_size_default*++
- Type: integer++
- Default: 16++
- Default font size.
-
-*font_size_default_monospace*++
- Type: integer++
- Default: 13++
- Default monospace font size.
-
-*scroll_lines*++
- Type: integer++
- Default: 3++
- Number of lines to scroll in the "scroll_lines_\*" keybindings.
-
-*tab_width*++
- Type: integer++
- Default: 20++
- Width of each tab in characters.
-
-*zoom_level*++
- Type: double++
- Default: 1.0++
- Default zoom level of each page.
-
-## KEYBINDINGS
-All of these keybindings are bound to Control + key.
-
-*download_manager*++
- Type: string++
- Default: y++
- Toggle the download manager.
-
-*history_back*++
- Type: string++
- Default: h++
- Go back in history.
-
-*history_forwards*++
- Type: string++
- Default: h++
- Go forwards in history.
-
-*location*++
- Type: string++
- Default: t++
- Select the URL.
-
-*print*++
- Type: string++
- Default: Print++
- Print the current page
-
-*quit*++
- Type: string++
- Default: g++
- Deselect everything and focus on the webpage.
-
-*reload*++
- Type: string++
- Default: e++
- Reload the current tab.
-
-*scroll_line_down*++
- Type: string++
- Default: j++
- Scroll down one line.
-
-*scroll_line_up*++
- Type: string++
- Default: k++
- Scroll up one line.
-
-*scroll_page_down*++
- Type: string++
- Default: f++
- Scroll down one page.
-
-*scroll_page_up*++
- Type: string++
- Default: b++
- Scroll up one page.
-
-*search_backwards*++
- Type: string++
- Default: r++
- Search in-page backwareds.
-
-*search_forwards*++
- Type: string++
- Default: s++
- Search in-page forwards.
-
-*tab_close*++
- Type: string++
- Default: q++
- Close the current tab.
-
-*tab_switch_[1-9]*++
- Type: string++
- Default: [1-9]++
- Group of options to jump to a particular tab, numbered from the left. Set
- these separately from each other.
-
-*tab_previous*++
- Type: string++
- Default: u++
- Focus the previous tab.
-
-*tab_mute*++
- Type: string++
- Default: AudioMute++
- Mute the current tab.
-
-*tab_new*++
- Type: string++
- Default: w++
- Open a new tab.
-
-*tab_next*++
- Type: string++
- Default: i++
- Focus the next tab.
-
-*toggle_js*++
- Type: string++
- Default: o++
- Toggle JavaScript.
-
-*toggle_img*++
- Type: string++
- Default: NULL++
- Toggle image loading.
-
-*web_search*++
- Type: string++
- Default: d++
- Start a web search.
-
-*zoom_in*++
- Type: string++
- Default: =++
- Zoom in 10%.
-
-*zoom_out*++
- Type: string++
- Default: -++
- Zoom out 10%.
-
-*zoom_reset*++
- Type: string++
- Default: -++
- Reset zoom to default.
+++ /dev/null
-chorizo-usage(1)
-
-# NAME
-chorizo-usage - extended usage hints
-
-# DESCRIPTION
-*chorizo* is a simple web browser using GTK+ 3, GLib and WebKit2GTK+. This
-manpage contains additional hints and pointers regarding its usage.
-
-# KEYBINDINGS AND CONFIGURATION
-For this information, please refer to *chorizo-config*(5).
-
-# DOWNLOAD MANAGER
-Open the download manager using the appropriate hotkey. A new window listing
-your downloads will appear. Clicking on an item will remove it from the list and
-**if needed** cancel the download.
-
-There's no file manager integration, nor does *chorizo* delete, overwrite or
-resume downloads. If a file already exists, it won't be touched. Instead, the
-new file name will have a suffix such as *.1*, *.2*, *.3*, and so on.
-
-# USER-SUPPLIED JAVASCRIPT FILES
-When a page is being loaded, the directory _~/.local/share/chorizo/user-scripts_
-will be scanned and each file in it ending with *.js* will be run as a
-JavaScript file in the context of said page.
-
-*chorizo* comes with the following scripts:
-
-*hints.js*
- Press *f* (open link in current window) or *F* (open in new window) to
- activate link hints. After typing the characters for one of them, press
- *Enter* to confirm. Press *Escape* to abort.
-
-*privacy-redirect.js*
- Redirects YouTube, Reddit, etc to privacy respecting alternatives.
-
-*darkreader.js*
- See https://darkreader.org.
-
-Those bundled scripts are automatically installed on *make install*. To use
-them, though, make sure to link them to the directory mentioned above.
-
-# USER-SUPPLIED CSS FILES
-User supplied CSS files will be scanned for from
-_~/.local/share/chorizo/user-styles_, and be applied every time a page
-loads. The rules in these files override any rules provided by the website.
-
-# WEB EXTENSIONS
-On startup, WebKit checks _~/.local/share/chorizo/web-extensions_ for any *.so*
-files. See
-<http://blogs.igalia.com/carlosgc/2013/09/10/webkit2gtk-web-process-extensions/>
-this blog post for further information on these extensions.
-
-*chorizo* comes with the following extensions:
-
-*we_adblock.so*
- Generic adblock. Reads patterns from the file _~/.config/chorizo/adblock_. Each
- line can contain a regular expression. These expressions match
- case-insensitive and partially, i.e.*\*foo.\** is the same as *.\*FOO.\** and
- you can use anchors like *^https?://...*. Please refer to
- https://developer.gnome.org/glib/stable/glib-regex-syntax.html the GLib
- reference for more details. Lines starting with "#" are ignored.
-
- Those bundled web extensions are automatically compiled when you run *make*
- and installed on *make install*. To use them, though, make sure to link them
- to the directory mentioned above.
-
-# TRUSTED CERTIFICATES
-By default, *chorizo* trusts whatever CAs are trusted by WebKit. If you wish to
-trust additional certificates, such as self-signed certificates, the first thing
-you should do is try to add the appropriate CAs to your system-wide store.
-
-If you wish to add simple exceptions, you can grab the certificate and store it
-in the directory _~/.local/share/chorizo/certs_. The filename must be equal to
-the hostname:
-
- $ echo | openssl s_client -connect foo.de:443 | openssl x509 >foo.de
-
-This tells *chorizo* to trust the given certificate when connecting to host
-*foo.de*.
-
-Note: This is NOT equal to certificate pinning. WebKit ignores user-specified
-certificates if the server's certificate can be validated by any system-wide CA.
-
-# SEE ALSO
-*chorizo*(1), *chorizo-config*(5)
+++ /dev/null
-chorizo(1)
-
-# NAME
-chorizo - simple web browser
-
-# SYNOPSIS
-*chorizo* - [-C] [_URI ..._]
-
-# DESCRIPTION
-*chorizo* is a simple web browser using GTK+ 3, GLib and WebKit2GTK+.
-
-# OPTIONS
-In addition to the standard arguments of GTK+ 3, *chorizo* knows about the
-following options:
-
-*-C*
- Disables cooperative instances.
-
-*-p*
- Launch a private window.
-
-*-v*
- Print version and exit.
-
-After these options there can be any number of URIs specified to open.
-
-# ENVIRONMENT
-In addition to the standard variables of GTK+ 3, *chorizo* knows about the
-following environment variable:
-
-*CHORIZO_FIFO_SUFFIX*
- Cooperative instances are implemented using a named pipe in the file
- system. The name of this pipe usually is (at least on modern systems following
- XDG standards: /var/run/user/$UID/chorizo.fifo-$CHORIZO_FIFO_SUFFIX
-
- *$UID* is the id of your user. *$CHORIZO_FIFO_SUFFIX* defaults to *main*. If you
- change this variable, you can launch several independent cooperative instances
- of *chorizo*.
-
-# FILES
-XDG variables will be used to construct these paths.
-*~/.config/chorizo/chorizo.ini*
- Configuration file. See *chorizo-config*(5).
-
-*~/.config/chorizo/adblock*
- Adblock patterns. See *chorizo-usage*(1).
-
-*~/.local/share/chorizo/certs*
- Directory where trusted certificates are stored. See *chorizo-usage*(1).
-
-*~/.local/share/chorizo/cookies.db*
- Database where cookies are stored. It is kept in the same format as Firefox,
- so the file can easily be copied over.
-
-*~/.local/share/chorizo/user-scripts*
- Directory to store user-supplied JavaScript snippets. See *chorizo-usage*(1).
-
-*~/.local/share/chorizo/user-styles*
- Directory to store user-supplied CSS snippets. See *chorizo-usage*(1).
-
-*~/.local/share/chorizo/web-extensions*
- Sets the directory where WebKit will look for web extensions. See
- *chorizo-usage*(1).
-
-*~/.cache/chorizo*
-*~/.cache/webkitgtk*
- General caches.
-
-*~/.local/share/webkitgtk*
- WebKitGTK will dump its caches and local storage here. It is probably wise to
- clean those directories regularly or to mount them as *tmpfs*(5).
-
-# LICENSE
-*chorizo* is released under the MIT license. See the accompanying LICENSE file.
-
-# HISTORY
-chorizo is a fork of the lariza browser by Peter Hofmann. The project was
-started in June 2014. This fork is maintained by Armaan Bhojwani.
-
-# SEE ALSO
-*chorizo-usage*(1), *chorizo-config*(5)
+++ /dev/null
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <webkit2/webkit2.h>
-
-#include "downloads.h"
-
-void client_destroy(GtkWidget *, gpointer);
-WebKitWebView *client_new(const gchar *, WebKitWebView *, gboolean, gboolean);
-WebKitWebView *client_new_request(WebKitWebView *, WebKitNavigationAction *,
- gpointer);
-void cooperation_setup(void);
-void changed_load_progress(GObject *, GParamSpec *, gpointer);
-void changed_favicon(GObject *, GParamSpec *, gpointer);
-void changed_title(GObject *, GParamSpec *, gpointer);
-void changed_uri(GObject *, GParamSpec *, gpointer);
-gboolean crashed_web_view(WebKitWebView *, gpointer);
-gboolean decide_policy(WebKitWebView *, WebKitPolicyDecision *,
- WebKitPolicyDecisionType, gpointer);
-gchar *ensure_uri_scheme(const gchar *);
-void grab_environment_configuration(void);
-void grab_feeds_finished(GObject *, GAsyncResult *, gpointer);
-void hover_web_view(WebKitWebView *, WebKitHitTestResult *, guint, gpointer);
-void icon_location(GtkEntry *, GtkEntryIconPosition, GdkEvent *, gpointer);
-void init_default_web_context(void);
-gboolean key_common(GtkWidget *, GdkEvent *, gpointer);
-gboolean key_location(GtkWidget *, GdkEvent *, gpointer);
-gboolean key_tablabel(GtkWidget *, GdkEvent *, gpointer);
-gboolean key_web_view(GtkWidget *, GdkEvent *, gpointer);
-void mainwindow_setup(void);
-void mainwindow_title(gint);
-void notebook_switch_page(GtkNotebook *, GtkWidget *, guint, gpointer);
-gboolean remote_msg(GIOChannel *, GIOCondition, gpointer);
-void run_user_scripts(WebKitWebView *);
-void search(gpointer, gint);
-void show_web_view(WebKitWebView *, gpointer);
-void trust_user_certs(WebKitWebContext *);
-GKeyFile *get_ini(void);
-GKeyFile *config;
-
-struct Client {
- GtkWidget *imgbutton;
- GtkWidget *jsbutton;
- GtkWidget *location;
- GtkWidget *tabicon;
- GtkWidget *tablabel;
- GtkWidget *vbox;
- GtkWidget *web_view;
- WebKitSettings *settings;
- gboolean focus_new_tab;
- gchar *external_handler_uri;
- gchar *feed_html;
- gchar *hover_uri;
-};
-
-struct Configuration {
- gdouble zoom_level;
- WebKitCookieAcceptPolicy cookie_policy;
- gboolean cooperative_alone;
- gboolean cooperative_instances;
- gboolean images_enabled;
- gboolean javascript_enabled;
- gboolean private;
- gboolean spellcheck_enabled;
- gchar *default_uri;
- gchar *home_uri;
- gchar *search_engine;
- gchar *spellcheck_language;
- gint scroll_lines;
- gint tab_width_chars;
-} cfg;
-
-struct MainWindow {
- GtkWidget *win;
- GtkWidget *notebook;
-} mw;
-
-gint clients = 0;
-struct Client **client_arr;
-
-int cooperative_pipe_fp = 0;
-gchar *search_text;
-
-void
-togglejs(GtkButton *jsbutton, gpointer data) {
- struct Client *c = (struct Client *)data;
- webkit_settings_set_enable_javascript(
- c->settings, !webkit_settings_get_enable_javascript(c->settings));
- webkit_web_view_set_settings(WEBKIT_WEB_VIEW(c->web_view), c->settings);
-}
-
-void
-toggleimg(GtkButton *imgbutton, gpointer data) {
- struct Client *c = (struct Client *)data;
- webkit_settings_set_auto_load_images(
- c->settings, !webkit_settings_get_auto_load_images(c->settings));
- webkit_web_view_set_settings(WEBKIT_WEB_VIEW(c->web_view), c->settings);
-}
-
-void
-client_destroy(GtkWidget *widget, gpointer data) {
- struct Client *c = (struct Client *)data;
- gint idx;
-
- g_signal_handlers_disconnect_by_func(G_OBJECT(c->web_view),
- changed_load_progress, c);
-
- idx = gtk_notebook_page_num(GTK_NOTEBOOK(mw.notebook), c->vbox);
- if (idx == -1)
- fprintf(stderr, __NAME__ ": Tab index was -1, bamboozled\n");
- else
- gtk_notebook_remove_page(GTK_NOTEBOOK(mw.notebook), idx);
-
- free(c);
- clients--;
-
- quit_if_nothing_active();
-}
-
-void
-set_uri(const char *uri, struct Client *c) {
- if (!gtk_widget_is_focus(c->location) && uri != NULL)
- gtk_entry_set_text(GTK_ENTRY(c->location), uri);
-}
-
-WebKitWebView *
-client_new(const gchar *uri, WebKitWebView *related_wv, gboolean show,
- gboolean focus_tab) {
- struct Client *c;
- gchar *f;
- GtkWidget *evbox, *tabbox;
-
- if (uri != NULL && cfg.cooperative_instances && !cfg.cooperative_alone) {
- f = ensure_uri_scheme(uri);
- write(cooperative_pipe_fp, f, strlen(f));
- write(cooperative_pipe_fp, "\n", 1);
- g_free(f);
- return NULL;
- }
-
- c = calloc(1, sizeof(struct Client));
- if (!c) {
- fprintf(stderr, __NAME__ ": fatal: calloc failed\n");
- exit(EXIT_FAILURE);
- }
-
- c->focus_new_tab = focus_tab;
-
- if (related_wv == NULL) {
- WebKitUserContentManager *ucm = webkit_user_content_manager_new();
- WebKitUserScript *wkscript;
- WebKitUserStyleSheet *wkstyle;
- gchar *path = NULL, *source, *base;
- const gchar *entry = NULL;
- GDir *dir = NULL;
-
- base = g_build_filename(g_get_user_data_dir(), __NAME__, "user-scripts",
- NULL);
- dir = g_dir_open(base, 0, NULL);
- if (dir != NULL) {
- while ((entry = g_dir_read_name(dir)) != NULL) {
- path = g_build_filename(base, entry, NULL);
- if (g_str_has_suffix(path, ".js")) {
- g_file_get_contents(path, &source, NULL, NULL);
- wkscript = webkit_user_script_new(
- source, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
- WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START, NULL,
- NULL);
- webkit_user_content_manager_add_script(ucm, wkscript);
- webkit_user_script_unref(wkscript);
- }
- g_free(path);
- g_free(source);
- }
- g_dir_close(dir);
- }
-
- base = g_build_filename(g_get_user_data_dir(), __NAME__, "user-styles",
- NULL);
- dir = g_dir_open(base, 0, NULL);
- if (dir != NULL) {
- while ((entry = g_dir_read_name(dir)) != NULL) {
- path = g_build_filename(base, entry, NULL);
- if (g_str_has_suffix(path, ".css")) {
- g_file_get_contents(path, &source, NULL, NULL);
- wkstyle = webkit_user_style_sheet_new(
- source, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
- WEBKIT_USER_STYLE_LEVEL_USER, NULL, NULL);
- webkit_user_content_manager_add_style_sheet(ucm, wkstyle);
- webkit_user_style_sheet_unref(wkstyle);
- }
- g_free(path);
- g_free(source);
- }
- g_dir_close(dir);
- }
-
- g_free(base);
-
- c->web_view = webkit_web_view_new_with_user_content_manager(ucm);
- } else {
- c->web_view = webkit_web_view_new_with_related_view(related_wv);
- }
-
- // Get settings
- c->settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(c->web_view));
- webkit_settings_set_enable_javascript(c->settings, cfg.javascript_enabled);
- webkit_settings_set_auto_load_images(c->settings, cfg.images_enabled);
-
- GKeyFile *config = get_ini();
- char *val;
- val = g_key_file_get_string(config, "ui", "font_family_default", NULL);
- if (val != NULL)
- webkit_settings_set_default_font_family(c->settings, val);
-
- val = g_key_file_get_string(config, "ui", "font_family_default_monospace",
- NULL);
- if (val != NULL)
- webkit_settings_set_monospace_font_family(c->settings, val);
-
- val = g_key_file_get_string(config, "ui", "font_family_default_sans_serif",
- NULL);
- if (val != NULL)
- webkit_settings_set_sans_serif_font_family(c->settings, val);
-
- val =
- g_key_file_get_string(config, "ui", "font_family_default_serif", NULL);
- if (val != NULL)
- webkit_settings_set_serif_font_family(c->settings, val);
-
- val = g_key_file_get_string(config, "browser", "user_agent", NULL);
- if (val != NULL)
- g_object_set(c->settings, "user-agent", val, NULL);
-
- int val2;
- val2 = g_key_file_get_integer(config, "ui", "font_size_default", NULL);
- if (val2)
- webkit_settings_set_default_font_size(c->settings, val2);
-
- val2 = g_key_file_get_integer(config, "ui", "font_size_default_monospace",
- NULL);
- if (val2)
- webkit_settings_set_default_monospace_font_size(c->settings, val2);
-
- gboolean val3;
- val3 = g_key_file_get_boolean(config, "browser", "console_to_stdout", NULL);
- if (val3)
- webkit_settings_set_enable_write_console_messages_to_stdout(c->settings,
- val3);
-
- val3 = g_key_file_get_boolean(config, "browser", "webgl_enable", NULL);
- if (!val3)
- webkit_settings_set_enable_webgl(c->settings, val3);
-
- val3 = g_key_file_get_boolean(config, "browser",
- "javascript_can_access_clipboard", NULL);
- if (val3)
- webkit_settings_set_javascript_can_access_clipboard(c->settings, val3);
-
- double val4;
- val4 = g_key_file_get_double(config, "ui", "zoom_level", NULL);
- if (val4)
- webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(c->web_view), val4);
-
- webkit_settings_set_enable_developer_extras(c->settings, TRUE);
-
- g_signal_connect(G_OBJECT(c->web_view), "notify::favicon",
- G_CALLBACK(changed_favicon), c);
- g_signal_connect(G_OBJECT(c->web_view), "notify::title",
- G_CALLBACK(changed_title), c);
- g_signal_connect(G_OBJECT(c->web_view), "notify::uri",
- G_CALLBACK(changed_uri), c);
- g_signal_connect(G_OBJECT(c->web_view), "notify::estimated-load-progress",
- G_CALLBACK(changed_load_progress), c);
- g_signal_connect(G_OBJECT(c->web_view), "create",
- G_CALLBACK(client_new_request), NULL);
- g_signal_connect(G_OBJECT(c->web_view), "close", G_CALLBACK(client_destroy),
- c);
- g_signal_connect(G_OBJECT(c->web_view), "decide-policy",
- G_CALLBACK(decide_policy), NULL);
- g_signal_connect(G_OBJECT(c->web_view), "key-press-event",
- G_CALLBACK(key_web_view), c);
- g_signal_connect(G_OBJECT(c->web_view), "button-release-event",
- G_CALLBACK(key_web_view), c);
- g_signal_connect(G_OBJECT(c->web_view), "scroll-event",
- G_CALLBACK(key_web_view), c);
- g_signal_connect(G_OBJECT(c->web_view), "mouse-target-changed",
- G_CALLBACK(hover_web_view), c);
- g_signal_connect(G_OBJECT(c->web_view), "web-process-crashed",
- G_CALLBACK(crashed_web_view), c);
-
- GtkWidget *locbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
-
- c->jsbutton = gtk_toggle_button_new_with_label("JS");
- gtk_widget_set_tooltip_text(c->jsbutton, "Toggle JavaScript execution");
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(c->jsbutton),
- cfg.javascript_enabled);
- g_signal_connect(G_OBJECT(c->jsbutton), "toggled", G_CALLBACK(togglejs), c);
-
- c->imgbutton = gtk_toggle_button_new_with_label("IMG");
- gtk_widget_set_tooltip_text(c->imgbutton, "Toggle image loading");
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(c->imgbutton),
- cfg.images_enabled);
- g_signal_connect(G_OBJECT(c->imgbutton), "toggled", G_CALLBACK(toggleimg),
- c);
-
- c->location = gtk_entry_new();
- gtk_box_pack_start(GTK_BOX(locbox), c->location, TRUE, TRUE, 0);
-
- if (cfg.private) {
- GtkWidget *privindicator = gtk_label_new("Private mode");
- gtk_widget_set_tooltip_text(
- privindicator, "You are in private mode. No history, caches, or "
- "cookies will be saved beyond this session.");
- gtk_box_pack_end(GTK_BOX(locbox), privindicator, FALSE, FALSE, 5);
- }
-
- gtk_box_pack_start(GTK_BOX(locbox), c->jsbutton, FALSE, FALSE, 5);
- gtk_box_pack_start(GTK_BOX(locbox), c->imgbutton, FALSE, FALSE, 0);
-
- g_signal_connect(G_OBJECT(c->location), "key-press-event",
- G_CALLBACK(key_location), c);
- g_signal_connect(G_OBJECT(c->location), "icon-release",
- G_CALLBACK(icon_location), c);
- /* XXX This is a workaround. Setting this to NULL (which is done in
- * grab_feeds_finished() if no feed has been detected) adds a little
- * padding left of the text. Not sure why. The point of this call
- * right here is to have that padding right from the start. This
- * avoids a graphical artifact. */
- gtk_entry_set_icon_from_icon_name(GTK_ENTRY(c->location),
- GTK_ENTRY_ICON_SECONDARY, NULL);
-
- c->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
- gtk_box_pack_start(GTK_BOX(c->vbox), locbox, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(c->vbox), c->web_view, TRUE, TRUE, 0);
- gtk_container_set_focus_child(GTK_CONTAINER(c->vbox), c->web_view);
-
- c->tabicon =
- gtk_image_new_from_icon_name("text-html", GTK_ICON_SIZE_SMALL_TOOLBAR);
-
- c->tablabel = gtk_label_new(__NAME__);
- gtk_label_set_ellipsize(GTK_LABEL(c->tablabel), PANGO_ELLIPSIZE_END);
- gtk_label_set_width_chars(GTK_LABEL(c->tablabel), cfg.tab_width_chars);
- gtk_widget_set_has_tooltip(c->tablabel, TRUE);
-
- /* XXX I don't own a HiDPI screen, so I don't know if scale_factor
- * does the right thing. */
- tabbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
- 5 * gtk_widget_get_scale_factor(mw.win));
- gtk_box_pack_start(GTK_BOX(tabbox), c->tabicon, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(tabbox), c->tablabel, TRUE, TRUE, 0);
-
- evbox = gtk_event_box_new();
- gtk_container_add(GTK_CONTAINER(evbox), tabbox);
- g_signal_connect(G_OBJECT(evbox), "button-release-event",
- G_CALLBACK(key_tablabel), c);
-
- gtk_widget_add_events(evbox, GDK_SCROLL_MASK);
- g_signal_connect(G_OBJECT(evbox), "scroll-event", G_CALLBACK(key_tablabel),
- c);
-
- // For easy access, store a reference to our label.
- g_object_set_data(G_OBJECT(evbox), "chorizo-tab-label", c->tablabel);
-
- /* This only shows the event box and the label inside, nothing else.
- * Needed because the evbox/label is "internal" to the notebook and
- * not part of the normal "widget tree" (IIUC). */
- gtk_widget_show_all(evbox);
-
- int page = gtk_notebook_get_current_page(GTK_NOTEBOOK(mw.notebook)) + 1;
- gtk_notebook_insert_page(GTK_NOTEBOOK(mw.notebook), c->vbox, evbox, page);
- gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(mw.notebook), c->vbox, TRUE);
-
- if (show)
- show_web_view(NULL, c);
- else
- g_signal_connect(G_OBJECT(c->web_view), "ready-to-show",
- G_CALLBACK(show_web_view), c);
-
- if (uri != NULL) {
- f = ensure_uri_scheme(uri);
- webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view), f);
- g_free(f);
- }
-
- set_uri(uri, c);
-
- clients++;
- client_arr = realloc(client_arr, (clients + 1) * sizeof(client_arr[0]));
- client_arr[clients] = c;
-
- return WEBKIT_WEB_VIEW(c->web_view);
-}
-
-WebKitWebView *
-client_new_request(WebKitWebView *web_view,
- WebKitNavigationAction *navigation_action, gpointer data) {
- return client_new(NULL, web_view, FALSE, FALSE);
-}
-
-void
-cooperation_setup(void) {
- GIOChannel *towatch;
- gchar *fifofilename, *fifopath;
-
- gchar *priv = (cfg.private) ? "-private" : "";
- fifofilename = g_strdup_printf("%s%s%s-%s", __NAME__, priv, ".fifo",
- g_getenv(__NAME_UPPERCASE__ "_FIFO_SUFFIX"));
- fifopath = g_build_filename(g_get_user_runtime_dir(), fifofilename, NULL);
- g_free(fifofilename);
-
- if (!g_file_test(fifopath, G_FILE_TEST_EXISTS))
- mkfifo(fifopath, 0600);
-
- cooperative_pipe_fp = open(fifopath, O_WRONLY | O_NONBLOCK);
- if (!cooperative_pipe_fp) {
- fprintf(stderr, __NAME__ ": Can't open FIFO at all.\n");
- } else {
- if (write(cooperative_pipe_fp, "", 0) == -1) {
- /* Could not do an empty write to the FIFO which means there's
- * no one listening. */
- close(cooperative_pipe_fp);
- towatch = g_io_channel_new_file(fifopath, "r+", NULL);
- g_io_add_watch(towatch, G_IO_IN, (GIOFunc)remote_msg, NULL);
- } else {
- cfg.cooperative_alone = FALSE;
- }
- }
-
- g_free(fifopath);
-}
-
-void
-changed_load_progress(GObject *obj, GParamSpec *pspec, gpointer data) {
- struct Client *c = (struct Client *)data;
- gdouble p;
- gchar *grab_feeds =
- "a = document.querySelectorAll('"
- " html > head > "
- "link[rel=\"alternate\"][href][type=\"application/atom+xml\"],"
- " html > head > "
- "link[rel=\"alternate\"][href][type=\"application/rss+xml\"]"
- "');"
- "if (a.length == 0)"
- " null;"
- "else {"
- " out = '';"
- " for (i = 0; i < a.length; i++) {"
- " url = encodeURIComponent(a[i].href);"
- " if ('title' in a[i] && a[i].title != '')"
- " title = encodeURIComponent(a[i].title);"
- " else"
- " title = url;"
- " out += '<li><a href=\"' + url + '\">' + title + "
- "'</a></li>';"
- " }"
- " out;"
- "}";
-
- p = webkit_web_view_get_estimated_load_progress(
- WEBKIT_WEB_VIEW(c->web_view));
- if (p == 1) {
- p = 0;
-
- /* The page has loaded fully. We now run the short JavaScript
- * snippet above that operates on the DOM. It tries to grab all
- * occurences of <link rel="alternate" ...>, i.e. RSS/Atom feed
- * references. */
- webkit_web_view_run_javascript(WEBKIT_WEB_VIEW(c->web_view), grab_feeds,
- NULL, grab_feeds_finished, c);
- }
- gtk_entry_set_progress_fraction(GTK_ENTRY(c->location), p);
-}
-
-void
-changed_favicon(GObject *obj, GParamSpec *pspec, gpointer data) {
- struct Client *c = (struct Client *)data;
- cairo_surface_t *f;
- int w, h, w_should, h_should;
- GdkPixbuf *pb, *pb_scaled;
-
- f = webkit_web_view_get_favicon(WEBKIT_WEB_VIEW(c->web_view));
- if (f == NULL) {
- gtk_image_set_from_icon_name(GTK_IMAGE(c->tabicon), "text-html",
- GTK_ICON_SIZE_SMALL_TOOLBAR);
- } else {
- w = cairo_image_surface_get_width(f);
- h = cairo_image_surface_get_height(f);
- pb = gdk_pixbuf_get_from_surface(f, 0, 0, w, h);
- if (pb != NULL) {
- w_should = 16 * gtk_widget_get_scale_factor(c->tabicon);
- h_should = 16 * gtk_widget_get_scale_factor(c->tabicon);
- pb_scaled = gdk_pixbuf_scale_simple(pb, w_should, h_should,
- GDK_INTERP_BILINEAR);
- gtk_image_set_from_pixbuf(GTK_IMAGE(c->tabicon), pb_scaled);
-
- g_object_unref(pb_scaled);
- g_object_unref(pb);
- }
- }
-}
-
-void
-changed_title(GObject *obj, GParamSpec *pspec, gpointer data) {
- const gchar *t, *u;
- struct Client *c = (struct Client *)data;
-
- u = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
- t = webkit_web_view_get_title(WEBKIT_WEB_VIEW(c->web_view));
-
- u = u == NULL ? __NAME__ : u;
- u = u[0] == 0 ? __NAME__ : u;
-
- t = t == NULL ? u : t;
- t = t[0] == 0 ? u : t;
-
- gchar *name = malloc(strlen(t) + 4);
- gboolean mute = webkit_web_view_get_is_muted(WEBKIT_WEB_VIEW(c->web_view));
- gchar *muted = (mute) ? "[m] " : "";
- sprintf(name, "%s%s", muted, t);
- gtk_label_set_text(GTK_LABEL(c->tablabel), name);
- g_free(name);
-
- gtk_widget_set_tooltip_text(c->tablabel, t);
- mainwindow_title(gtk_notebook_get_current_page(GTK_NOTEBOOK(mw.notebook)));
-}
-
-void
-changed_uri(GObject *obj, GParamSpec *pspec, gpointer data) {
- const gchar *t;
- struct Client *c = (struct Client *)data;
- FILE *fp;
-
- t = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
-
- /* When a web process crashes, we get a "notify::uri" signal, but we
- * can no longer read a meaningful URI. It's just an empty string
- * now. Not updating the location bar in this scenario is important,
- * because we would override the "WEB PROCESS CRASHED" message. */
- if (t != NULL && strlen(t) > 0) {
- set_uri(t, c);
-
- gchar *history_file =
- g_key_file_get_string(config, "browser", "history_file", NULL);
-
- if (history_file != NULL && !cfg.private) {
- fp = fopen(history_file, "a");
- if (fp != NULL) {
- fprintf(fp, "%s\n", t);
- fclose(fp);
- } else {
- perror(__NAME__ ": Error opening history file");
- }
- }
- }
-}
-
-gboolean
-crashed_web_view(WebKitWebView *web_view, gpointer data) {
- gchar *t;
- struct Client *c = (struct Client *)data;
-
- t = g_strdup_printf("WEB PROCESS CRASHED: %s",
- webkit_web_view_get_uri(WEBKIT_WEB_VIEW(web_view)));
- gtk_entry_set_text(GTK_ENTRY(c->location), t);
- g_free(t);
-
- return TRUE;
-}
-
-gboolean
-decide_policy(WebKitWebView *web_view, WebKitPolicyDecision *decision,
- WebKitPolicyDecisionType type, gpointer data) {
- WebKitResponsePolicyDecision *r;
-
- switch (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;
-}
-
-gchar *
-ensure_uri_scheme(const gchar *t) {
- gchar *f, *fabs;
-
- f = g_ascii_strdown(t, -1);
- if (!g_str_has_prefix(f, "http:") && !g_str_has_prefix(f, "https:") &&
- !g_str_has_prefix(f, "file:") && !g_str_has_prefix(f, "about:") &&
- !g_str_has_prefix(f, "data:") && !g_str_has_prefix(f, "webkit:")) {
- g_free(f);
- fabs = realpath(t, NULL);
- if (fabs != NULL) {
- f = g_strdup_printf("file://%s", fabs);
- free(fabs);
- } else {
- f = g_strdup_printf("http://%s", t);
- }
- return f;
- } else
- return g_strdup(t);
-}
-
-void
-get_config(void) {
- cfg.cooperative_alone = TRUE;
- cfg.cooperative_instances = TRUE;
-
- config = get_ini();
-
- cfg.home_uri = g_key_file_get_string(config, "browser", "homepage", NULL);
- cfg.home_uri = (cfg.home_uri) ? cfg.home_uri : "about:blank";
-
- cfg.javascript_enabled =
- g_key_file_get_boolean(config, "browser", "javascript_enabled", NULL);
- cfg.javascript_enabled =
- (cfg.javascript_enabled) ? cfg.javascript_enabled : TRUE;
-
- cfg.images_enabled =
- g_key_file_get_boolean(config, "browser", "images_enabled", NULL);
- cfg.images_enabled = (cfg.images_enabled) ? cfg.images_enabled : TRUE;
-
- char *input_cookie_policy =
- g_key_file_get_string(config, "browser", "cookie_policy", NULL);
- cfg.cookie_policy = WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY;
- if (input_cookie_policy) {
- if (strcmp(input_cookie_policy, "all") == 0) {
- cfg.cookie_policy = WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS;
- } else if (strcmp(input_cookie_policy, "none") == 0) {
- cfg.cookie_policy = WEBKIT_COOKIE_POLICY_ACCEPT_NEVER;
- }
- }
-
- cfg.default_uri = g_key_file_get_string(config, "ui", "default_uri", NULL);
- cfg.default_uri = (cfg.default_uri) ? cfg.default_uri : "https://";
-
- cfg.tab_width_chars =
- g_key_file_get_integer(config, "ui", "tab_width", NULL);
- cfg.tab_width_chars = (cfg.tab_width_chars) ? cfg.tab_width_chars : 20;
-
- cfg.search_engine =
- g_key_file_get_string(config, "ui", "search_engine", NULL);
- cfg.search_engine =
- (cfg.search_engine) ? cfg.search_engine : "https://duckduckgo.com?q=";
-
- cfg.spellcheck_enabled =
- g_key_file_get_boolean(config, "ui", "spellcheck_enabled", NULL);
- cfg.spellcheck_enabled =
- (cfg.spellcheck_enabled) ? cfg.spellcheck_enabled : FALSE;
-
- cfg.spellcheck_language =
- g_key_file_get_string(config, "ui", "spellcheck_language", NULL);
- cfg.spellcheck_language =
- (cfg.spellcheck_language) ? cfg.spellcheck_language : "en_US";
-
- cfg.scroll_lines =
- g_key_file_get_integer(config, "ui", "scroll_lines", NULL);
- cfg.scroll_lines = (cfg.scroll_lines) ? cfg.scroll_lines : 3;
-}
-
-void
-grab_feeds_finished(GObject *object, GAsyncResult *result, gpointer data) {
- struct Client *c = (struct Client *)data;
- WebKitJavascriptResult *js_result;
- JSCValue *value;
- JSCException *exception;
- GError *err = NULL;
- gchar *str_value;
-
- g_free(c->feed_html);
- c->feed_html = NULL;
-
- /* This was taken almost verbatim from the example in WebKit's
- * documentation:
- *
- * https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebView.html
- */
-
- js_result = webkit_web_view_run_javascript_finish(WEBKIT_WEB_VIEW(object),
- result, &err);
- if (!js_result) {
- fprintf(stderr, __NAME__ ": Error running javascript: %s\n",
- err->message);
- g_error_free(err);
- return;
- }
-
- value = webkit_javascript_result_get_js_value(js_result);
- if (jsc_value_is_string(value)) {
- str_value = jsc_value_to_string(value);
- exception = jsc_context_get_exception(jsc_value_get_context(value));
- if (exception != NULL) {
- fprintf(stderr, __NAME__ ": Error running javascript: %s\n",
- jsc_exception_get_message(exception));
- } else {
- c->feed_html = str_value;
- }
-
- gtk_entry_set_icon_from_icon_name(GTK_ENTRY(c->location),
- GTK_ENTRY_ICON_SECONDARY,
- "application-rss+xml-symbolic");
- gtk_entry_set_icon_activatable(GTK_ENTRY(c->location),
- GTK_ENTRY_ICON_SECONDARY, TRUE);
- } else {
- gtk_entry_set_icon_from_icon_name(GTK_ENTRY(c->location),
- GTK_ENTRY_ICON_SECONDARY, NULL);
- }
-
- webkit_javascript_result_unref(js_result);
-}
-
-void
-hover_web_view(WebKitWebView *web_view, WebKitHitTestResult *ht,
- guint modifiers, gpointer data) {
- struct Client *c = (struct Client *)data;
- const char *to_show;
-
- g_free(c->hover_uri);
-
- if (webkit_hit_test_result_context_is_link(ht)) {
- to_show = webkit_hit_test_result_get_link_uri(ht);
- c->hover_uri = g_strdup(to_show);
- } else {
- to_show = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
- c->hover_uri = NULL;
- }
-
- if (!gtk_widget_is_focus(c->location))
- set_uri(to_show, c);
-}
-
-void
-icon_location(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEvent *event,
- gpointer data) {
- struct Client *c = (struct Client *)data;
- gchar *d;
- gchar *data_template = "data:text/html,"
- "<!DOCTYPE html>"
- "<html>"
- " <head>"
- " <meta charset=\"UTF-8\">"
- " <title>Feeds</title>"
- " </head>"
- " <body>"
- " <p>Feeds found on this page:</p>"
- " <ul>"
- " %s"
- " </ul>"
- " </body>"
- "</html>";
-
- if (c->feed_html != NULL) {
- /* What we're actually trying to do is show a simple HTML page
- * that lists all the feeds on the current page. The function
- * webkit_web_view_load_html() looks like the proper way to do
- * that. Sad thing is, it doesn't create a history entry, but
- * instead simply replaces the content of the current page. This
- * is not what we want.
- *
- * RFC 2397 [0] defines the data URI scheme [1]. We abuse this
- * mechanism to show my custom HTML snippet *and* create a
- * history entry.
- *
- * [0]: https://tools.ietf.org/html/rfc2397
- * [1]: https://en.wikipedia.org/wiki/Data_URI_scheme */
- d = g_strdup_printf(data_template, c->feed_html);
- webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view), d);
- g_free(d);
- }
-}
-
-void
-init_default_web_context(void) {
- gchar *p;
- WebKitWebContext *wc;
- WebKitCookieManager *cm;
-
- wc = (cfg.private) ? webkit_web_context_new_ephemeral()
- : webkit_web_context_get_default();
-
- p = g_build_filename(g_get_user_config_dir(), __NAME__, "adblock", NULL);
- webkit_web_context_set_sandbox_enabled(wc, TRUE);
- webkit_web_context_add_path_to_sandbox(wc, p, TRUE);
- g_free(p);
-
- WebKitProcessModel model =
- WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES;
- webkit_web_context_set_process_model(wc, model);
-
- p = g_build_filename(g_get_user_data_dir(), __NAME__, "web-extensions",
- NULL);
- webkit_web_context_set_web_extensions_directory(wc, p);
- g_free(p);
-
- char *xdg_down = getenv("XDG_DOWNLOAD_DIR");
- g_signal_connect(G_OBJECT(wc), "download-started",
- G_CALLBACK(download_start),
- (xdg_down) ? xdg_down : "/var/tmp");
-
- trust_user_certs(wc);
-
- cm = webkit_web_context_get_cookie_manager(wc);
- webkit_cookie_manager_set_accept_policy(cm, cfg.cookie_policy);
-
- if (!cfg.private) {
- webkit_web_context_set_favicon_database_directory(wc, NULL);
-
- gchar *fname = g_build_filename("/", g_get_user_data_dir(), __NAME__,
- "cookies.db", NULL);
- WebKitCookiePersistentStorage type =
- WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE;
- webkit_cookie_manager_set_persistent_storage(cm, fname, type);
- g_free(fname);
- }
-
- const gchar *const languages[2] = {(const gchar *)cfg.spellcheck_language,
- NULL};
- webkit_web_context_set_spell_checking_languages(wc, languages);
- webkit_web_context_set_spell_checking_enabled(wc, cfg.spellcheck_enabled);
-}
-
-void
-search(gpointer data, gint direction) {
- struct Client *c = (struct Client *)data;
- WebKitWebView *web_view = WEBKIT_WEB_VIEW(c->web_view);
- WebKitFindController *fc = webkit_web_view_get_find_controller(web_view);
-
- if (search_text == NULL)
- return;
-
- switch (direction) {
- case 0:
- webkit_find_controller_search(fc, search_text,
- WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE |
- WEBKIT_FIND_OPTIONS_WRAP_AROUND,
- G_MAXUINT);
- break;
- case 1:
- webkit_find_controller_search_next(fc);
- break;
- case -1:
- webkit_find_controller_search_previous(fc);
- break;
- case 2:
- webkit_find_controller_search_finish(fc);
- break;
- }
-}
-
-void
-search_init(struct Client *c, int direction) {
- gtk_widget_grab_focus(c->location);
- const gchar *contents = gtk_entry_get_text(GTK_ENTRY(c->location));
- if (strcspn(contents, "s/")) {
- gtk_entry_set_text(GTK_ENTRY(c->location), "s/");
- gtk_editable_set_position(GTK_EDITABLE(c->location), -1);
- } else {
- search(c, 0);
- search(c, -1);
- search(c, direction);
- }
-}
-
-int
-def_key(char *key, unsigned int def) {
- char *conf = g_key_file_get_string(config, "keybindings", key, NULL);
- return (conf) ? gdk_keyval_from_name((conf) ? conf : NULL) : def;
-}
-
-gboolean
-key_common(GtkWidget *widget, GdkEvent *event, gpointer data) {
- struct Client *c = (struct Client *)data;
- gdouble now;
- gchar *f;
-
- if (event->type == GDK_KEY_PRESS) {
- if (((GdkEventKey *)event)->state & GDK_CONTROL_MASK) {
- const char *uri =
- webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
- int key = ((GdkEventKey *)event)->keyval;
- if (def_key("download_manager", GDK_KEY_y) == key) {
- downloadmanager_show();
- return TRUE;
- } else if (def_key("history_back", GDK_KEY_h) == key) {
- webkit_web_view_go_back(WEBKIT_WEB_VIEW(c->web_view));
- return TRUE;
- } else if (def_key("history_forwards", GDK_KEY_l) == key) {
- webkit_web_view_go_forward(WEBKIT_WEB_VIEW(c->web_view));
- return TRUE;
- } else if (def_key("location", GDK_KEY_t) == key) {
- gtk_widget_grab_focus(c->location);
- const char *goal = (strcmp(cfg.home_uri, uri) == 0 || !uri)
- ? cfg.default_uri
- : uri;
- gtk_entry_set_text(GTK_ENTRY(c->location), goal);
- gtk_editable_set_position(GTK_EDITABLE(c->location), -1);
- return TRUE;
- } else if (def_key("print", GDK_KEY_Print) == key) {
- WebKitPrintOperation *operation =
- webkit_print_operation_new(WEBKIT_WEB_VIEW(c->web_view));
- GtkWidget *toplevel = gtk_widget_get_toplevel(mw.win);
- webkit_print_operation_run_dialog(operation,
- GTK_WINDOW(toplevel));
- return TRUE;
- } else if (def_key("quit", GDK_KEY_g) == key) {
- search(c, 2);
- gtk_widget_grab_focus(c->web_view);
- gtk_entry_set_text(GTK_ENTRY(c->location), uri);
- gtk_editable_set_position(GTK_EDITABLE(c->location), -1);
- webkit_web_view_run_javascript(
- WEBKIT_WEB_VIEW(c->web_view),
- "window.getSelection().removeAllRanges();"
- "document.activeElement.blur();",
- NULL, NULL, c);
- return TRUE;
- } else if (def_key("reload", GDK_KEY_e) == key) {
- webkit_web_view_reload_bypass_cache(
- WEBKIT_WEB_VIEW(c->web_view));
- return TRUE;
- } else if (def_key("scroll_line_down", GDK_KEY_j) == key) {
- for (int i = 0; i <= cfg.scroll_lines - 1; i++) {
- event->key.keyval = GDK_KEY_Down;
- gdk_event_put(event);
- }
- return TRUE;
- } else if (def_key("scroll_line_up", GDK_KEY_k) == key) {
- for (int i = 0; i <= cfg.scroll_lines - 1; i++) {
- event->key.keyval = GDK_KEY_Up;
- gdk_event_put(event);
- }
- return TRUE;
- } else if (def_key("scroll_page_down", GDK_KEY_f) == key) {
- event->key.keyval = GDK_KEY_Page_Down;
- gdk_event_put(event);
- return TRUE;
- } else if (def_key("scroll_page_up", GDK_KEY_b) == key) {
- event->key.keyval = GDK_KEY_Page_Up;
- gdk_event_put(event);
- return TRUE;
- } else if (def_key("search_forwards", GDK_KEY_s) == key) {
- search_init(c, 1);
- return TRUE;
- } else if (def_key("search_backwards", GDK_KEY_r) == key) {
- search_init(c, -1);
- return TRUE;
- } else if (def_key("tab_close", GDK_KEY_q) == key) {
- client_destroy(NULL, c);
- return TRUE;
- } else if (def_key("tab_switch_1", GDK_KEY_1) == key) {
- gtk_notebook_set_current_page(GTK_NOTEBOOK(mw.notebook), 0);
- return TRUE;
- } else if (def_key("tab_switch_2", GDK_KEY_2) == key) {
- gtk_notebook_set_current_page(GTK_NOTEBOOK(mw.notebook), 1);
- return TRUE;
- } else if (def_key("tab_switch_3", GDK_KEY_3) == key) {
- gtk_notebook_set_current_page(GTK_NOTEBOOK(mw.notebook), 2);
- return TRUE;
- } else if (def_key("tab_switch_4", GDK_KEY_4) == key) {
- gtk_notebook_set_current_page(GTK_NOTEBOOK(mw.notebook), 3);
- return TRUE;
- } else if (def_key("tab_switch_5", GDK_KEY_5) == key) {
- gtk_notebook_set_current_page(GTK_NOTEBOOK(mw.notebook), 4);
- return TRUE;
- } else if (def_key("tab_switch_6", GDK_KEY_6) == key) {
- gtk_notebook_set_current_page(GTK_NOTEBOOK(mw.notebook), 5);
- return TRUE;
- } else if (def_key("tab_switch_7", GDK_KEY_7) == key) {
- gtk_notebook_set_current_page(GTK_NOTEBOOK(mw.notebook), 6);
- return TRUE;
- } else if (def_key("tab_switch_8", GDK_KEY_8) == key) {
- gtk_notebook_set_current_page(GTK_NOTEBOOK(mw.notebook), 7);
- return TRUE;
- } else if (def_key("tab_switch_9", GDK_KEY_9) == key) {
- gtk_notebook_set_current_page(GTK_NOTEBOOK(mw.notebook), 8);
- return TRUE;
- } else if (def_key("tab_previous", GDK_KEY_u) == key) {
- gtk_notebook_prev_page(GTK_NOTEBOOK(mw.notebook));
- return TRUE;
- } else if (def_key("tab_mute", GDK_KEY_m) == key) {
- gboolean muted =
- webkit_web_view_get_is_muted(WEBKIT_WEB_VIEW(c->web_view));
- webkit_web_view_set_is_muted(WEBKIT_WEB_VIEW(c->web_view),
- !muted);
- changed_title(G_OBJECT(c->web_view), NULL, c);
- return TRUE;
- } else if (def_key("tab_new", GDK_KEY_w) == key) {
- f = ensure_uri_scheme(cfg.home_uri);
- client_new(f, NULL, TRUE, TRUE);
- g_free(f);
- return TRUE;
- } else if (def_key("tab_next", GDK_KEY_i) == key) {
- gtk_notebook_next_page(GTK_NOTEBOOK(mw.notebook));
- return TRUE;
- } else if (def_key("toggle_js", GDK_KEY_o) == key) {
- gboolean on =
- webkit_settings_get_enable_javascript(c->settings);
- webkit_settings_set_enable_javascript(c->settings, !on);
- webkit_web_view_set_settings(WEBKIT_WEB_VIEW(c->web_view),
- c->settings);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(c->jsbutton),
- !on);
- } else if (def_key("toggle_img", -1) == key) {
- gboolean on = webkit_settings_get_auto_load_images(c->settings);
- webkit_settings_set_auto_load_images(c->settings, !on);
- webkit_web_view_set_settings(WEBKIT_WEB_VIEW(c->web_view),
- c->settings);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(c->imgbutton),
- !on);
- } else if (def_key("web_search", GDK_KEY_d) == key) {
- gtk_widget_grab_focus(c->location);
- gtk_entry_set_text(GTK_ENTRY(c->location), "w/");
- gtk_editable_set_position(GTK_EDITABLE(c->location), -1);
- return TRUE;
- } else if (def_key("zoom_in", GDK_KEY_equal) == key) {
- now = webkit_web_view_get_zoom_level(
- WEBKIT_WEB_VIEW(c->web_view));
- webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(c->web_view),
- now + 0.1);
- return TRUE;
- } else if (def_key("zoom_out", GDK_KEY_minus) == key) {
- now = webkit_web_view_get_zoom_level(
- WEBKIT_WEB_VIEW(c->web_view));
- webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(c->web_view),
- now - 0.1);
- return TRUE;
- } else if (def_key("zoom_reset", GDK_KEY_0) == key) {
- webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(c->web_view),
- cfg.zoom_level);
- return TRUE;
- }
- }
- }
- return FALSE;
-}
-
-gboolean
-key_location(GtkWidget *widget, GdkEvent *event, gpointer data) {
- struct Client *c = (struct Client *)data;
- const gchar *t;
- gchar *f;
-
- if (key_common(widget, event, data))
- return TRUE;
-
- if (event->type == GDK_KEY_PRESS) {
- int key = ((GdkEventKey *)event)->keyval;
- if ((GDK_KEY_KP_Enter == key) || (GDK_KEY_Return == key)) {
- gtk_widget_grab_focus(c->web_view);
- t = gtk_entry_get_text(GTK_ENTRY(c->location));
- if (t != NULL && t[0] == 's' && t[1] == '/') {
- if (search_text != NULL)
- g_free(search_text);
- search_text = g_strdup(t + 2);
- search(c, 0);
- } else if (t != NULL && t[0] == 'w' && t[1] == '/') {
- int len = strlen(cfg.search_engine) + strlen(t) - 2;
- gchar *f = malloc(len + 1);
- snprintf(f, len + 1, "%s%s", cfg.search_engine, t + 2);
- webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view), f);
- g_free(f);
- } else {
- f = ensure_uri_scheme(t);
- webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view), f);
- g_free(f);
- }
- return TRUE;
- } else if (GDK_KEY_Escape == key) {
- t = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
- gtk_entry_set_text(GTK_ENTRY(c->location), (t == NULL) ? "" : t);
- return TRUE;
- }
- }
- return FALSE;
-}
-
-gboolean
-key_tablabel(GtkWidget *widget, GdkEvent *event, gpointer data) {
- GdkScrollDirection direction;
-
- if (event->type == GDK_BUTTON_RELEASE) {
- switch (((GdkEventButton *)event)->button) {
- case 2:
- client_destroy(NULL, data);
- return TRUE;
- }
- } else if (event->type == GDK_SCROLL) {
- gdk_event_get_scroll_direction(event, &direction);
- switch (direction) {
- case GDK_SCROLL_UP:
- gtk_notebook_prev_page(GTK_NOTEBOOK(mw.notebook));
- break;
- case GDK_SCROLL_DOWN:
- gtk_notebook_next_page(GTK_NOTEBOOK(mw.notebook));
- break;
- default:
- break;
- }
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-key_web_view(GtkWidget *widget, GdkEvent *event, gpointer data) {
- struct Client *c = (struct Client *)data;
- gdouble dx, dy;
- gfloat z;
-
- if (key_common(widget, event, data))
- return TRUE;
-
- if (event->type == GDK_KEY_PRESS) {
- if (((GdkEventKey *)event)->keyval == GDK_KEY_Escape) {
- webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(c->web_view));
- gtk_entry_set_progress_fraction(GTK_ENTRY(c->location), 0);
- }
- } else if (event->type == GDK_BUTTON_RELEASE) {
- GdkModifierType modifiers = gtk_accelerator_get_default_mod_mask();
- switch (((GdkEventButton *)event)->button) {
- case 1:
- if ((((GdkEventButton *)event)->state & modifiers) ==
- GDK_CONTROL_MASK &&
- c->hover_uri != NULL) {
- client_new(c->hover_uri, NULL, TRUE, FALSE);
- return TRUE;
- }
- break;
- case 8:
- webkit_web_view_go_back(WEBKIT_WEB_VIEW(c->web_view));
- return TRUE;
- case 9:
- webkit_web_view_go_forward(WEBKIT_WEB_VIEW(c->web_view));
- return TRUE;
- }
- } else if (event->type == GDK_SCROLL) {
- event->scroll.delta_y *= cfg.scroll_lines;
- if (((GdkEventScroll *)event)->state & GDK_CONTROL_MASK) {
- gdk_event_get_scroll_deltas(event, &dx, &dy);
- z = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(c->web_view));
- z += -dy * 0.1;
- z = dx != 0 ? cfg.zoom_level : z;
- webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(c->web_view), z);
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-void
-mainwindow_setup(void) {
- mw.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_default_size(GTK_WINDOW(mw.win), 800, 600);
- g_signal_connect(G_OBJECT(mw.win), "destroy", gtk_main_quit, NULL);
-
- gchar *priv = (cfg.private) ? "-private" : "";
- gchar *title = malloc(strlen(priv) + strlen(__NAME__) + 1);
- sprintf(title, "%s%s", __NAME__, priv);
- gtk_window_set_title(GTK_WINDOW(mw.win), title);
- g_free(title);
-
- mw.notebook = gtk_notebook_new();
- gtk_notebook_set_scrollable(GTK_NOTEBOOK(mw.notebook), TRUE);
- gtk_container_add(GTK_CONTAINER(mw.win), mw.notebook);
- g_signal_connect(G_OBJECT(mw.notebook), "switch-page",
- G_CALLBACK(notebook_switch_page), NULL);
-}
-
-void
-mainwindow_title(gint idx) {
- GtkWidget *child, *widg, *tablabel;
- const gchar *text;
-
- child = gtk_notebook_get_nth_page(GTK_NOTEBOOK(mw.notebook), idx);
- if (child == NULL)
- return;
-
- widg = gtk_notebook_get_tab_label(GTK_NOTEBOOK(mw.notebook), child);
- tablabel =
- (GtkWidget *)g_object_get_data(G_OBJECT(widg), "chorizo-tab-label");
- text = gtk_label_get_text(GTK_LABEL(tablabel));
- gtk_window_set_title(GTK_WINDOW(mw.win), text);
-}
-
-void
-notebook_switch_page(GtkNotebook *nb, GtkWidget *p, guint idx, gpointer data) {
- mainwindow_title(idx);
-}
-
-gboolean
-quit_if_nothing_active(void) {
- if (clients == 0) {
- if (downloads == 0) {
- gtk_main_quit();
- return TRUE;
- } else {
- downloadmanager_show();
- }
- }
-
- return FALSE;
-}
-
-gboolean
-remote_msg(GIOChannel *channel, GIOCondition condition, gpointer data) {
- gchar *uri = NULL;
-
- g_io_channel_read_line(channel, &uri, NULL, NULL, NULL);
- if (uri) {
- g_strstrip(uri);
- client_new(uri, NULL, TRUE, TRUE);
- g_free(uri);
- }
- return TRUE;
-}
-
-void
-show_web_view(WebKitWebView *web_view, gpointer data) {
- struct Client *c = (struct Client *)data;
- gint idx;
-
- (void)web_view;
-
- gtk_widget_show_all(mw.win);
-
- if (c->focus_new_tab) {
- idx = gtk_notebook_page_num(GTK_NOTEBOOK(mw.notebook), c->vbox);
- if (idx != -1)
- gtk_notebook_set_current_page(GTK_NOTEBOOK(mw.notebook), idx);
-
- gtk_widget_grab_focus(c->web_view);
- }
-}
-
-void
-trust_user_certs(WebKitWebContext *wc) {
- GTlsCertificate *cert;
- gchar *basedir, *absfile;
- const gchar *file;
- GDir *dir = NULL;
-
- basedir = g_build_filename(g_get_user_data_dir(), __NAME__, "certs", NULL);
- dir = g_dir_open(basedir, 0, NULL);
- g_free(basedir);
- if (dir != NULL) {
- file = g_dir_read_name(dir);
- while (file != NULL) {
- absfile = g_build_filename(g_get_user_data_dir(), __NAME__, "certs",
- file, NULL);
- cert = g_tls_certificate_new_from_file(absfile, NULL);
- g_free(absfile);
- if (cert == NULL)
- fprintf(stderr, __NAME__ ": Could not load trusted cert '%s'\n",
- file);
- else
- webkit_web_context_allow_tls_certificate_for_host(wc, cert,
- file);
- file = g_dir_read_name(dir);
- }
- g_dir_close(dir);
- }
-}
-
-GKeyFile *
-get_ini(void) {
- GKeyFileFlags flags = G_KEY_FILE_NONE;
- config = g_key_file_new();
-
- // Load user config
- gchar *fname = g_build_filename(g_get_user_config_dir(), __NAME__,
- "chorizo.ini", NULL);
- if (!g_key_file_load_from_file(config, fname, flags, NULL)) {
- // Load global config
- if (!g_key_file_load_from_file(config, "/etc/chorizo.ini", flags,
- NULL)) {
- fprintf(stderr, "Could not load chorizo.ini");
- }
- }
- g_free(fname);
- return config;
-}
-
-int
-main(int argc, char **argv) {
- int opt, i;
-
- while ((opt = getopt(argc, argv, "Cpv")) != -1) {
- switch (opt) {
- case 'C':
- cfg.cooperative_instances = FALSE;
- break;
- case 'p':
- cfg.private = true;
- break;
- case 'v':
- printf("%s %s\n", __NAME__, VERSION);
- exit(0);
- default:
- fprintf(stderr, "Usage: " __NAME__ " [OPTION]... [URI]...\n");
- exit(EXIT_FAILURE);
- }
- }
-
- gtk_init(&argc, &argv);
-
- // Keep clipboard contents after program closes
- gtk_clipboard_store(gtk_clipboard_get_for_display(gdk_display_get_default(),
- GDK_SELECTION_CLIPBOARD));
-
- get_config();
-
- if (cfg.cooperative_instances)
- cooperation_setup();
-
- if (!cfg.cooperative_instances || cfg.cooperative_alone)
- init_default_web_context();
-
- downloadmanager_setup();
- mainwindow_setup();
-
- client_arr = malloc(sizeof(struct Client *));
- if (optind >= argc) {
- client_new(cfg.home_uri, NULL, TRUE, TRUE);
- } else {
- for (i = optind; i < argc; i++)
- client_new(argv[i], NULL, TRUE, TRUE);
- }
-
- if (!cfg.cooperative_instances || cfg.cooperative_alone)
- gtk_main();
-
- for (int i = 0; i < clients; i++) {
- free(&(client_arr[i]));
- }
-
- exit(EXIT_SUCCESS);
-}
+++ /dev/null
-#include <webkit2/webkit2.h>
-
-#include "downloads.h"
-
-gboolean download_handle(WebKitDownload *, gchar *, gpointer);
-void download_click(GtkToolButton *, gpointer);
-void download_cancel(GtkMenuItem *, gpointer);
-gboolean downloadmanager_delete(GtkWidget *, gpointer);
-
-struct DownloadManager {
- GtkWidget *scroll;
- GtkWidget *toolbar;
- GtkWidget *win;
-} dm;
-
-gint downloads = 0;
-
-struct DownloadItem {
- GtkToolButton *tb;
- WebKitDownload *download;
-};
-
-gboolean
-key_downloadmanager(GtkWidget *widget, GdkEvent *event, gpointer data) {
- if (event->type == GDK_KEY_PRESS) {
- if (((GdkEventKey *)event)->state & GDK_CONTROL_MASK) {
- int key = ((GdkEventKey *)event)->keyval;
- if ((def_key("close_tab", GDK_KEY_q) == key) ||
- (def_key("download_manager", GDK_KEY_y) == key)) {
- downloadmanager_delete(dm.win, NULL);
- return TRUE;
- }
- }
- }
-
- return FALSE;
-}
-
-void
-changed_download_progress(GObject *obj, GParamSpec *pspec, gpointer data) {
- WebKitDownload *download = WEBKIT_DOWNLOAD(obj);
- WebKitURIResponse *resp;
- GtkToolItem *tb = GTK_TOOL_ITEM(data);
- gdouble p, size_mb;
- const gchar *uri;
- gchar *t, *filename, *base;
-
- p = webkit_download_get_estimated_progress(download);
- p = p > 1 ? 1 : p;
- p = p < 0 ? 0 : p;
- p *= 100;
- resp = webkit_download_get_response(download);
- size_mb = webkit_uri_response_get_content_length(resp) / 1e6;
-
- uri = webkit_download_get_destination(download);
- filename = g_filename_from_uri(uri, NULL, NULL);
- base = g_path_get_basename(filename);
- t = g_strdup_printf("%s (%.0f%% of %.1f MB)", base, p, size_mb);
- g_free(filename);
- g_free(base);
- gtk_tool_button_set_label(GTK_TOOL_BUTTON(tb), t);
- g_free(t);
-}
-
-void
-download_finished(WebKitDownload *download, gpointer data) {
- if (strcmp(gtk_tool_button_get_icon_name(GTK_TOOL_BUTTON(data)),
- "dialog-error") != 0)
- gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(data),
- "emblem-downloads");
- downloads--;
-}
-
-void
-download_start(WebKitWebView *web_view, WebKitDownload *download,
- gpointer data) {
- g_signal_connect(G_OBJECT(download), "decide-destination",
- G_CALLBACK(download_handle), data);
-}
-
-gboolean
-download_handle(WebKitDownload *download, gchar *suggested_filename,
- gpointer data) {
- gchar *uri;
- GtkToolItem *tb;
-
- GtkWidget *chooser = gtk_file_chooser_dialog_new(
- "Choose download location", GTK_WINDOW(dm.win),
- GTK_FILE_CHOOSER_ACTION_SAVE, "Save file", GTK_RESPONSE_ACCEPT,
- "Cancel", GTK_RESPONSE_CANCEL, NULL);
- gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser),
- (char *)data);
- gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(chooser),
- suggested_filename);
- gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(chooser),
- TRUE);
- gint res = gtk_dialog_run(GTK_DIALOG(chooser));
-
- switch (res) {
- case GTK_RESPONSE_ACCEPT:
- uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(chooser));
- webkit_download_set_destination(
- download, gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(chooser)));
- break;
- case GTK_RESPONSE_CANCEL:
- return FALSE;
- default:
- return FALSE;
- }
-
- gtk_widget_destroy(chooser);
-
- remove(uri + 7);
- tb = gtk_tool_button_new(NULL, NULL);
- gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(tb), "network-receive");
- gtk_tool_button_set_label(GTK_TOOL_BUTTON(tb), uri);
- gtk_toolbar_insert(GTK_TOOLBAR(dm.toolbar), tb, 0);
- gtk_widget_show_all(dm.win);
-
- g_signal_connect(G_OBJECT(download), "notify::estimated-progress",
- G_CALLBACK(changed_download_progress), tb);
-
- downloads++;
- g_signal_connect(G_OBJECT(download), "finished",
- G_CALLBACK(download_finished), tb);
-
- g_object_ref(download);
-
- struct DownloadItem *payload = malloc(sizeof(*payload));
- payload->tb = (GtkToolButton *)tb;
- payload->download = download;
- g_signal_connect(G_OBJECT(tb), "clicked", G_CALLBACK(download_click),
- payload);
- g_signal_connect(G_OBJECT(tb), "failed", G_CALLBACK(download_cancel),
- payload);
- g_signal_connect(G_OBJECT(tb), "destroy_event", G_CALLBACK(g_free),
- payload);
-
- // Propagate -- to whom it may concern.
- return FALSE;
-}
-
-void
-download_cancel(GtkMenuItem *tb, gpointer data) {
- struct DownloadItem *payload = data;
- gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(payload->tb), "dialog-error");
- webkit_download_cancel(payload->download);
-}
-
-void
-download_remove(GtkMenuItem *tb, gpointer data) {
- struct DownloadItem *payload = data;
- g_object_unref(payload->download);
- gtk_widget_destroy(GTK_WIDGET(payload->tb));
-}
-
-void
-download_copy_url(GtkMenuItem *tb, gpointer data) {
- struct DownloadItem *payload = data;
- WebKitURIRequest *req = webkit_download_get_request(payload->download);
- const gchar *uri = webkit_uri_request_get_uri(req);
- gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), uri,
- strlen(uri));
-}
-
-void
-download_copy_path(GtkMenuItem *tb, gpointer data) {
- struct DownloadItem *payload = data;
- const gchar *path = webkit_download_get_destination(payload->download);
- gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), path + 7,
- strlen(path) - 7); // Offset by 7 to remove "file://"
-}
-
-void
-download_xdg_open(GtkMenuItem *tb, gpointer data) {
- struct DownloadItem *payload = data;
- const gchar *path = webkit_download_get_destination(payload->download);
- char *cmd = malloc(strlen(path) + 9);
- sprintf(cmd, "xdg-open %s", path);
- system(cmd);
-}
-
-void
-download_click(GtkToolButton *tb, gpointer data) {
- GtkWidget *pmenu = gtk_menu_new();
- GtkWidget *option;
-
- if (strcmp(gtk_tool_button_get_icon_name(GTK_TOOL_BUTTON(tb)),
- "network-receive") == 0) {
- option = gtk_menu_item_new_with_label("Cancel download");
- g_signal_connect(G_OBJECT(option), "activate",
- G_CALLBACK(download_cancel), data);
- gtk_widget_show(option);
- gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
- } else {
- option = gtk_menu_item_new_with_label("Remove download");
- g_signal_connect(G_OBJECT(option), "activate",
- G_CALLBACK(download_remove), data);
- gtk_widget_show(option);
- gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
-
- option = gtk_menu_item_new_with_label("Open file with xdg-open");
- gtk_widget_show(option);
- gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
- g_signal_connect(G_OBJECT(option), "activate",
- G_CALLBACK(download_xdg_open), data);
- }
-
- option = gtk_menu_item_new_with_label("Copy download URL");
- gtk_widget_show(option);
- gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
- g_signal_connect(G_OBJECT(option), "activate",
- G_CALLBACK(download_copy_url), data);
-
- option = gtk_menu_item_new_with_label("Copy local path");
- gtk_widget_show(option);
- gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
- g_signal_connect(G_OBJECT(option), "activate",
- G_CALLBACK(download_copy_path), data);
-
- gtk_menu_popup_at_pointer(GTK_MENU(pmenu), NULL);
-}
-
-gboolean
-downloadmanager_delete(GtkWidget *obj, gpointer data) {
- if (!quit_if_nothing_active())
- gtk_widget_hide(dm.win);
-
- return TRUE;
-}
-
-void
-downloadmanager_setup(void) {
- dm.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_type_hint(GTK_WINDOW(dm.win), GDK_WINDOW_TYPE_HINT_DIALOG);
- gtk_window_set_default_size(GTK_WINDOW(dm.win), 500, 250);
- gtk_window_set_title(GTK_WINDOW(dm.win), __NAME__ " - Download Manager");
- g_signal_connect(G_OBJECT(dm.win), "delete-event",
- G_CALLBACK(downloadmanager_delete), NULL);
- g_signal_connect(G_OBJECT(dm.win), "key-press-event",
- G_CALLBACK(key_downloadmanager), NULL);
-
- dm.toolbar = gtk_toolbar_new();
- gtk_orientable_set_orientation(GTK_ORIENTABLE(dm.toolbar),
- GTK_ORIENTATION_VERTICAL);
- gtk_toolbar_set_style(GTK_TOOLBAR(dm.toolbar), GTK_TOOLBAR_BOTH_HORIZ);
- gtk_toolbar_set_show_arrow(GTK_TOOLBAR(dm.toolbar), FALSE);
-
- dm.scroll = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dm.scroll),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_container_add(GTK_CONTAINER(dm.scroll), dm.toolbar);
-
- gtk_container_add(GTK_CONTAINER(dm.win), dm.scroll);
-}
-
-void
-downloadmanager_show(void) {
- gtk_widget_show_all(dm.win);
-}
+++ /dev/null
-extern int downloads;
-gboolean quit_if_nothing_active(void);
-int def_key(char *, unsigned int);
-void download_start(WebKitWebView *, WebKitDownload *, gpointer);
-void downloadmanager_setup(void);
-void downloadmanager_show(void);
--- /dev/null
+/**
+ * Minified by jsDelivr using Terser v5.7.1.
+ * Original file: /npm/darkreader@4.9.39/darkreader.js
+ *
+ * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
+ */
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).DarkReader={})}(this,(function(e){"use strict";
+/*! *****************************************************************************
+ Copyright (c) Microsoft Corporation.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ PERFORMANCE OF THIS SOFTWARE.
+ ***************************************************************************** */var t=function(){return(t=Object.assign||function(e){for(var t,r=1,n=arguments.length;r<n;r++)for(var o in t=arguments[r])Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o]);return e}).apply(this,arguments)};function r(e,t,r,n){return new(r||(r=Promise))((function(o,a){function i(e){try{s(n.next(e))}catch(e){a(e)}}function u(e){try{s(n.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(i,u)}s((n=n.apply(e,t||[])).next())}))}function n(e,t){var r,n,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(r)throw new TypeError("Generator is already executing.");for(;i;)try{if(r=1,n&&(o=2&a[0]?n.return:a[0]?n.throw||((o=n.return)&&o.call(n),0):n.next)&&!(o=o.call(n,a[1])).done)return o;switch(n=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,n=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],n=0}finally{r=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}}function o(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function a(e,t){var r="function"==typeof Symbol&&e[Symbol.iterator];if(!r)return e;var n,o,a=r.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(e){o={error:e}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i}function i(e,t,r){if(r||2===arguments.length)for(var n,o=0,a=t.length;o<a;o++)!n&&o in t||(n||(n=Array.prototype.slice.call(t,0,o)),n[o]=t[o]);return e.concat(n||t)}var u="bg-fetch-response",s="cs-fetch",c="undefined"==typeof navigator?"some useragent":navigator.userAgent.toLowerCase(),l="undefined"==typeof navigator?"some platform":navigator.platform.toLowerCase(),d=c.includes("chrome")||c.includes("chromium"),f=c.includes("thunderbird"),h=c.includes("firefox")||f;c.includes("vivaldi"),c.includes("yabrowser"),c.includes("opr")||c.includes("opera"),c.includes("edg");var p=c.includes("safari")&&!d,v=l.startsWith("win"),m=l.startsWith("mac");c.includes("mobile");var g,b="function"==typeof ShadowRoot,y="function"==typeof MediaQueryList&&"function"==typeof MediaQueryList.prototype.addEventListener;(g=c.match(/chrom[e|ium]\/([^ ]+)/))&&g[1]&&g[1];var w=function(){try{return document.querySelector(":defined"),!0}catch(e){return!1}}();function k(e,t,o){return r(this,void 0,void 0,(function(){var r;return n(this,(function(n){switch(n.label){case 0:return[4,fetch(e,{cache:"force-cache",credentials:"omit",referrer:o})];case 1:if(r=n.sent(),h&&"text/css"===t&&e.startsWith("moz-extension://")&&e.endsWith(".css"))return[2,r];if(t&&!r.headers.get("Content-Type").startsWith(t))throw new Error("Mime type mismatch when loading "+e);if(!r.ok)throw new Error("Unable to load "+e+" "+r.status+" "+r.statusText);return[2,r]}}))}))}function S(e,t){return r(this,void 0,void 0,(function(){return n(this,(function(r){switch(r.label){case 0:return[4,k(e,t)];case 1:return[4,_(r.sent())];case 2:return[2,r.sent()]}}))}))}function _(e){return r(this,void 0,void 0,(function(){var t;return n(this,(function(r){switch(r.label){case 0:return[4,e.blob()];case 1:return t=r.sent(),[4,new Promise((function(e){var r=new FileReader;r.onloadend=function(){return e(r.result)},r.readAsDataURL(t)}))];case 2:return[2,r.sent()]}}))}))}globalThis.chrome&&globalThis.chrome.runtime&&globalThis.chrome.runtime.getManifest&&globalThis.chrome.runtime.getManifest().manifest_version;var E=function(e){return r(void 0,void 0,void 0,(function(){return n(this,(function(t){return[2,Promise.reject(new Error(["Embedded Dark Reader cannot access a cross-origin resource",e,"Overview your URLs and CORS policies or use","`DarkReader.setFetchMethod(fetch: (url) => Promise<Response>))`.","See if using `DarkReader.setFetchMethod(window.fetch)`","before `DarkReader.enable()` works."].join(" ")))]}))}))},x=E;function C(e){return r(this,void 0,void 0,(function(){return n(this,(function(t){switch(t.label){case 0:return[4,x(e)];case 1:return[2,t.sent()]}}))}))}window.chrome||(window.chrome={}),chrome.runtime||(chrome.runtime={});var V=new Set;function T(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];return r(this,void 0,void 0,(function(){var t,r,o,a,i,c,l;return n(this,(function(n){switch(n.label){case 0:if(!e[0]||e[0].type!==s)return[3,8];t=e[0].id,n.label=1;case 1:return n.trys.push([1,7,,8]),r=e[0].data,o=r.url,a=r.responseType,[4,C(o)];case 2:return i=n.sent(),"data-url"!==a?[3,4]:[4,_(i)];case 3:return c=n.sent(),[3,6];case 4:return[4,i.text()];case 5:c=n.sent(),n.label=6;case 6:return V.forEach((function(e){return e({type:u,data:c,error:null,id:t})})),[3,8];case 7:return l=n.sent(),console.error(l),V.forEach((function(e){return e({type:u,data:null,error:l,id:t})})),[3,8];case 8:return[2]}}))}))}function R(e){V.add(e)}if("function"==typeof chrome.runtime.sendMessage){var M=chrome.runtime.sendMessage;chrome.runtime.sendMessage=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];T.apply(void 0,i([],a(e))),M.apply(chrome.runtime,e)}}else chrome.runtime.sendMessage=T;if(chrome.runtime.onMessage||(chrome.runtime.onMessage={}),"function"==typeof chrome.runtime.onMessage.addListener){var A=chrome.runtime.onMessage.addListener;chrome.runtime.onMessage.addListener=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];R.apply(void 0,i([],a(e))),A.apply(chrome.runtime.onMessage,e)}}else chrome.runtime.onMessage.addListener=R;var L="dynamicTheme",P={background:"#181a1b",text:"#e8e6e3"},O={background:"#dcdad7",text:"#181a1b"},j={mode:1,brightness:100,contrast:100,grayscale:0,sepia:0,useFont:!1,fontFamily:m?"Helvetica Neue":v?"Segoe UI":"Open Sans",textStroke:0,engine:L,stylesheet:"",darkSchemeBackgroundColor:P.background,darkSchemeTextColor:P.text,lightSchemeBackgroundColor:O.background,lightSchemeTextColor:O.text,scrollbarColor:m?"":"auto",selectionColor:"auto",styleSystemControls:!0};function D(e,t){var r,n;if(function(e){return null!=e.length}(e))for(var a=0,i=e.length;a<i;a++)t(e[a]);else try{for(var u=o(e),s=u.next();!s.done;s=u.next()){t(s.value)}}catch(e){r={error:e}}finally{try{s&&!s.done&&(n=u.return)&&n.call(u)}finally{if(r)throw r.error}}}function F(e,t){D(t,(function(t){return e.push(t)}))}function q(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t]}function N(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t]}function B(e){var t,r=!1,n=null;return Object.assign((function(){for(var o=[],u=0;u<arguments.length;u++)o[u]=arguments[u];t=o,n?r=!0:(e.apply(void 0,i([],a(t))),n=requestAnimationFrame((function(){n=null,r&&(e.apply(void 0,i([],a(t))),r=!1)})))}),{cancel:function(){cancelAnimationFrame(n),r=!1,n=null}})}function W(e){var t=0;return e.seconds&&(t+=1e3*e.seconds),e.minutes&&(t+=60*e.minutes*1e3),e.hours&&(t+=60*e.hours*60*1e3),e.days&&(t+=24*e.days*60*60*1e3),t}function I(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function U(e,t,r){void 0===r&&(r=Function.prototype);var n=W({seconds:2}),o=W({seconds:10}),a=e.previousSibling,i=e.parentNode;if(!i)throw new Error("Unable to watch for node position: parent element not found");if("prev-sibling"===t&&!a)throw new Error("Unable to watch for node position: there is no previous sibling");var u=0,s=null,c=null,l=B((function(){if(!c){u++;var f=Date.now();if(null==s)s=f;else if(u>=10){if(f-s<o)return N("Node position watcher paused: retry in "+n+"ms",e,a),void(c=setTimeout((function(){s=null,u=0,c=null,l()}),n));s=f,u=1}if("parent"===t&&a&&a.parentNode!==i)return N("Unable to restore node position: sibling parent changed",e,a,i),void h();if("prev-sibling"===t){if(null==a.parentNode)return N("Unable to restore node position: sibling was removed",e,a,i),void h();a.parentNode!==i&&(N("Style was moved to another parent",e,a,i),p(a.parentNode))}N("Restoring node position",e,a,i),i.insertBefore(e,a?a.nextSibling:i.firstChild),d.takeRecords(),r&&r()}})),d=new MutationObserver((function(){("parent"===t&&e.parentNode!==i||"prev-sibling"===t&&e.previousSibling!==a)&&l()})),f=function(){d.observe(i,{childList:!0})},h=function(){clearTimeout(c),d.disconnect(),l.cancel()},p=function(e){i=e,h(),f()};return f(),{run:f,stop:h,skip:function(){d.takeRecords()}}}function z(e,t){if(null!=e)for(var r=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return null==e.shadowRoot?NodeFilter.FILTER_SKIP:NodeFilter.FILTER_ACCEPT}}),n=e.shadowRoot?r.currentNode:r.nextNode();null!=n;n=r.nextNode())t(n),z(n.shadowRoot,t)}function $(){return"complete"===document.readyState||"interactive"===document.readyState}var H=new Set;function G(e){H.add(e)}function Q(e){H.delete(e)}function K(){return"complete"===document.readyState}var J=new Set;function X(e){J.add(e)}if(!$()){var Y=function(){$()&&(H.forEach((function(e){return e()})),H.clear(),K()&&(document.removeEventListener("readystatechange",Y),J.forEach((function(e){return e()})),J.clear()))};document.addEventListener("readystatechange",Y)}var Z,ee=new Map,te=new WeakMap;function re(e,t){var r,n,o;if(ee.has(e))r=ee.get(e),n=te.get(r);else{var a=!1,i=!1;(r=new MutationObserver((function(t){if(function(e){if(e.length>1e3)return!0;for(var t=0,r=0;r<e.length;r++)if((t+=e[r].addedNodes.length)>1e3)return!0;return!1}(t))!a||$()?n.forEach((function(t){return(0,t.onHugeMutations)(e)})):i||(G(o=function(){return n.forEach((function(t){return(0,t.onHugeMutations)(e)}))}),i=!0),a=!0;else{var r=function(e){var t=new Set,r=new Set,n=new Set;e.forEach((function(e){D(e.addedNodes,(function(e){e instanceof Element&&e.isConnected&&t.add(e)})),D(e.removedNodes,(function(e){e instanceof Element&&(e.isConnected?n.add(e):r.add(e))}))})),n.forEach((function(e){return t.delete(e)}));var o=[],a=[];return t.forEach((function(e){t.has(e.parentElement)&&o.push(e)})),r.forEach((function(e){r.has(e.parentElement)&&a.push(e)})),o.forEach((function(e){return t.delete(e)})),a.forEach((function(e){return r.delete(e)})),{additions:t,moves:n,deletions:r}}(t);n.forEach((function(e){return(0,e.onMinorMutations)(r)}))}}))).observe(e,{childList:!0,subtree:!0}),ee.set(e,r),n=new Set,te.set(r,n)}return n.add(t),{disconnect:function(){n.delete(t),o&&Q(o),0===n.size&&(r.disconnect(),te.delete(r),ee.delete(e))}}}var ne=new Map;function oe(e){return Z||(Z=document.createElement("a")),Z.href=e,Z.href}function ae(e,t){void 0===t&&(t=null);var r=e+(t?";"+t:"");if(ne.has(r))return ne.get(r);if(t){var n=new URL(e,oe(t));return ne.set(r,n),n}var o=new URL(oe(e));return ne.set(e,o),o}function ie(e,t){if(t.match(/^data\\?\:/))return t;if(/^\/\//.test(t))return""+location.protocol+t;var r=ae(e);return ae(t,r.href).href}function ue(e,t,r){D(e,(function(e){if(e.selectorText)t(e);else if(e.href)try{ue(e.styleSheet.cssRules,t,r)}catch(e){q("Found a non-loaded link."),r&&r()}else if(e.media){var n=Array.from(e.media),o=n.some((function(e){return e.startsWith("screen")||e.startsWith("all")})),a=n.some((function(e){return e.startsWith("print")||e.startsWith("speech")}));!o&&a||ue(e.cssRules,t,r)}else e.conditionText?CSS.supports(e.conditionText)&&ue(e.cssRules,t,r):N("CSSRule type not supported",e)}))}var se=["background","border","border-color","border-bottom","border-left","border-right","border-top","outline","outline-color"],ce=p?se.map((function(e){return[e,new RegExp(e+":\\s*(.*?)\\s*;")]})):null;function le(e,t){D(e,(function(r){var n=e.getPropertyValue(r).trim();n&&t(r,n)}));var r=e.cssText;r.includes("var(")&&(p?ce.forEach((function(e){var n=a(e,2),o=n[0],i=n[1],u=r.match(i);if(u&&u[1]){var s=u[1].trim();t(o,s)}})):se.forEach((function(r){var n=e.getPropertyValue(r);n&&n.includes("var(")&&t(r,n)})))}var de=/url\((('.+?')|(".+?")|([^\)]*?))\)/g,fe=/@import\s*(url\()?(('.+?')|(".+?")|([^\)]*?))\)?;?/g;function he(e){return e.replace(/^url\((.*)\)$/,"$1").trim().replace(/^"(.*)"$/,"$1").replace(/^'(.*)'$/,"$1")}function pe(e){var t=ae(e);return""+t.origin+t.pathname.replace(/\?.*$/,"").replace(/(\/)([^\/]+)$/i,"$1")}var ve=/\/\*[\s\S]*?\*\//g;var me=/@font-face\s*{[^}]*}/g;function ge(e){var t=e.h,r=e.s,n=e.l,o=e.a,i=void 0===o?1:o;if(0===r){var u=a([n,n,n].map((function(e){return Math.round(255*e)})),3),s=u[0],c=u[1];return{r:s,g:u[2],b:c,a:i}}var l=(1-Math.abs(2*n-1))*r,d=l*(1-Math.abs(t/60%2-1)),f=n-l/2,h=a((t<60?[l,d,0]:t<120?[d,l,0]:t<180?[0,l,d]:t<240?[0,d,l]:t<300?[d,0,l]:[l,0,d]).map((function(e){return Math.round(255*(e+f))})),3);return{r:h[0],g:h[1],b:h[2],a:i}}function be(e){var t=e.r,r=e.g,n=e.b,o=e.a,a=void 0===o?1:o,i=t/255,u=r/255,s=n/255,c=Math.max(i,u,s),l=Math.min(i,u,s),d=c-l,f=(c+l)/2;if(0===d)return{h:0,s:0,l:f,a:a};var h=60*(c===i?(u-s)/d%6:c===u?(s-i)/d+2:(i-u)/d+4);return h<0&&(h+=360),{h:h,s:d/(1-Math.abs(2*f-1)),l:f,a:a}}function ye(e,t){void 0===t&&(t=0);var r=e.toFixed(t);if(0===t)return r;var n=r.indexOf(".");if(n>=0){var o=r.match(/0+$/);if(o)return o.index===n+1?r.substring(0,n):r.substring(0,o.index)}return r}function we(e){var t=e.h,r=e.s,n=e.l,o=e.a;return null!=o&&o<1?"hsla("+ye(t)+", "+ye(100*r)+"%, "+ye(100*n)+"%, "+ye(o,2)+")":"hsl("+ye(t)+", "+ye(100*r)+"%, "+ye(100*n)+"%)"}var ke=/^rgba?\([^\(\)]+\)$/,Se=/^hsla?\([^\(\)]+\)$/,_e=/^#[0-9a-f]+$/i;function Ee(e){var t,r,n,o,i,u=e.trim().toLowerCase();if(u.match(ke))return t=a(xe(u,Ce,Ve),4),r=t[0],n=t[1],o=t[2],i=t[3],{r:r,g:n,b:o,a:void 0===i?1:i};if(u.match(Se))return function(e){var t=a(xe(e,Te,Re),4),r=t[0],n=t[1],o=t[2],i=t[3];return ge({h:r,s:n,l:o,a:void 0===i?1:i})}(u);if(u.match(_e))return function(e){var t=e.substring(1);switch(t.length){case 3:case 4:var r=a([0,1,2].map((function(e){return parseInt(""+t[e]+t[e],16)})),3);return{r:r[0],g:r[1],b:r[2],a:3===t.length?1:parseInt(""+t[3]+t[3],16)/255};case 6:case 8:var n=a([0,2,4].map((function(e){return parseInt(t.substring(e,e+2),16)})),3);return{r:n[0],g:n[1],b:n[2],a:6===t.length?1:parseInt(t.substring(6,8),16)/255}}throw new Error("Unable to parse "+e)}(u);if(Me.has(u))return function(e){var t=Me.get(e);return{r:t>>16&255,g:t>>8&255,b:t>>0&255,a:1}}(u);if(Ae.has(u))return function(e){var t=Ae.get(e);return{r:t>>16&255,g:t>>8&255,b:t>>0&255,a:1}}(u);if("transparent"===e)return{r:0,g:0,b:0,a:0};throw new Error("Unable to parse "+e)}function xe(e,t,r){var n=function(e){var t=[],r=0,n=!1,o=e.indexOf("(");e=e.substring(o+1,e.length-1);for(var a=0;a<e.length;a++){var i=e[a];i>="0"&&i<="9"||"."===i||"+"===i||"-"===i?n=!0:!n||" "!==i&&","!==i?n||(r=a+1):(t.push(e.substring(r,a)),n=!1,r=a+1)}return n&&t.push(e.substring(r,e.length)),t}(e),o=Object.entries(r);return n.map((function(e){return e.trim()})).map((function(e,r){var n,i=o.find((function(t){var r=a(t,1)[0];return e.endsWith(r)}));return n=i?parseFloat(e.substring(0,e.length-i[0].length))/i[1]*t[r]:parseFloat(e),t[r]>1?Math.round(n):n}))}var Ce=[255,255,255,1],Ve={"%":100};var Te=[360,1,1,1],Re={"%":100,deg:360,rad:2*Math.PI,turn:1};var Me=new Map(Object.entries({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgrey:11119017,darkgreen:25600,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,grey:8421504,green:32768,greenyellow:11403055,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgrey:13882323,lightgreen:9498256,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074})),Ae=new Map(Object.entries({ActiveBorder:3906044,ActiveCaption:0,AppWorkspace:11184810,Background:6513614,ButtonFace:16777215,ButtonHighlight:15329769,ButtonShadow:10461343,ButtonText:0,CaptionText:0,GrayText:8355711,Highlight:11720703,HighlightText:0,InactiveBorder:16777215,InactiveCaption:16777215,InactiveCaptionText:0,InfoBackground:16514245,InfoText:0,Menu:16185078,MenuText:16777215,Scrollbar:11184810,ThreeDDarkShadow:0,ThreeDFace:12632256,ThreeDHighlight:16777215,ThreeDLightShadow:16777215,ThreeDShadow:0,Window:15527148,WindowFrame:11184810,WindowText:0,"-webkit-focus-ring-color":15046400}).map((function(e){var t=a(e,2),r=t[0],n=t[1];return[r.toLowerCase(),n]})));function Le(e,t,r,n,o){return(e-t)*(o-n)/(r-t)+n}function Pe(e,t,r){return Math.min(r,Math.max(t,e))}function Oe(e,t){for(var r=[],n=0,o=e.length;n<o;n++){r[n]=[];for(var a=0,i=t[0].length;a<i;a++){for(var u=0,s=0,c=e[0].length;s<c;s++)u+=e[n][s]*t[s][a];r[n][a]=u}}return r}function je(e,t,r){void 0===r&&(r=0);for(var n,o=[];n=e.exec(t);)o.push(n[r]);return o}function De(e){var t=Fe.identity();return 0!==e.sepia&&(t=Oe(t,Fe.sepia(e.sepia/100))),0!==e.grayscale&&(t=Oe(t,Fe.grayscale(e.grayscale/100))),100!==e.contrast&&(t=Oe(t,Fe.contrast(e.contrast/100))),100!==e.brightness&&(t=Oe(t,Fe.brightness(e.brightness/100))),1===e.mode&&(t=Oe(t,Fe.invertNHue())),t}var Fe={identity:function(){return[[1,0,0,0,0],[0,1,0,0,0],[0,0,1,0,0],[0,0,0,1,0],[0,0,0,0,1]]},invertNHue:function(){return[[.333,-.667,-.667,0,1],[-.667,.333,-.667,0,1],[-.667,-.667,.333,0,1],[0,0,0,1,0],[0,0,0,0,1]]},brightness:function(e){return[[e,0,0,0,0],[0,e,0,0,0],[0,0,e,0,0],[0,0,0,1,0],[0,0,0,0,1]]},contrast:function(e){var t=(1-e)/2;return[[e,0,0,0,t],[0,e,0,0,t],[0,0,e,0,t],[0,0,0,1,0],[0,0,0,0,1]]},sepia:function(e){return[[.393+.607*(1-e),.769-.769*(1-e),.189-.189*(1-e),0,0],[.349-.349*(1-e),.686+.314*(1-e),.168-.168*(1-e),0,0],[.272-.272*(1-e),.534-.534*(1-e),.131+.869*(1-e),0,0],[0,0,0,1,0],[0,0,0,0,1]]},grayscale:function(e){return[[.2126+.7874*(1-e),.7152-.7152*(1-e),.0722-.0722*(1-e),0,0],[.2126-.2126*(1-e),.7152+.2848*(1-e),.0722-.0722*(1-e),0,0],[.2126-.2126*(1-e),.7152-.7152*(1-e),.0722+.9278*(1-e),0,0],[0,0,0,1,0],[0,0,0,0,1]]}};function qe(e){return e[1===e.mode?"darkSchemeBackgroundColor":"lightSchemeBackgroundColor"]}function Ne(e){return e[1===e.mode?"darkSchemeTextColor":"lightSchemeTextColor"]}var Be=new Map,We=new Map;function Ie(e){if(We.has(e))return We.get(e);var t=be(Ee(e));return We.set(e,t),t}var Ue=["r","g","b","a"],ze=["mode","brightness","contrast","grayscale","sepia","darkSchemeBackgroundColor","darkSchemeTextColor","lightSchemeBackgroundColor","lightSchemeTextColor"];function $e(e,t,r,n,o){var i;Be.has(r)?i=Be.get(r):(i=new Map,Be.set(r,i));var u=function(e,t){var r="";return Ue.forEach((function(t){r+=e[t]+";"})),ze.forEach((function(e){r+=t[e]+";"})),r}(e,t);if(i.has(u))return i.get(u);var s=ge(r(be(e),null==n?null:Ie(n),null==o?null:Ie(o))),c=s.r,l=s.g,d=s.b,f=s.a,h=a(function(e,t){var r=a(e,3),n=Oe(t,[[r[0]/255],[r[1]/255],[r[2]/255],[1],[1]]);return[0,1,2].map((function(e){return Pe(Math.round(255*n[e][0]),0,255)}))}([c,l,d],De(t)),3),p=h[0],v=h[1],m=h[2],g=1===f?function(e){var t=e.r,r=e.g,n=e.b,o=e.a;return"#"+(null!=o&&o<1?[t,r,n,Math.round(255*o)]:[t,r,n]).map((function(e){return(e<16?"0":"")+e.toString(16)})).join("")}({r:p,g:v,b:m}):function(e){var t=e.r,r=e.g,n=e.b,o=e.a;return null!=o&&o<1?"rgba("+ye(t)+", "+ye(r)+", "+ye(n)+", "+ye(o,2)+")":"rgb("+ye(t)+", "+ye(r)+", "+ye(n)+")"}({r:p,g:v,b:m,a:f});return i.set(u,g),g}function He(e){return e}function Ge(e,t){var r=qe(t);return $e(e,t,Qe,Ne(t),r)}function Qe(e,t,r){var n,o=e.h,a=e.s,i=e.l,u=e.a,s=i<.5;s?n=i<.2||a<.12:n=a<.24||i>.8&&(o>200&&o<280);var c=o,l=i;return n&&(s?(c=t.h,l=t.s):(c=r.h,l=r.s)),{h:c,s:l,l:Le(i,0,1,t.l,r.l),a:u}}function Ke(e,t){var r=e.h,n=e.s,o=e.l,a=e.a,i=n<.12||o>.8&&(r>200&&r<280);if(o<.5){var u=Le(o,0,.5,0,.4);return i?{h:t.h,s:t.s,l:u,a:a}:{h:r,s:n,l:u,a:a}}var s=Le(o,.5,1,.4,t.l);if(i)return{h:t.h,s:t.s,l:s,a:a};var c=r;r>60&&r<180&&(c=r>120?Le(r,120,180,135,180):Le(r,60,120,60,105));return{h:c,s:n,l:s,a:a}}function Je(e,r){if(0===r.mode)return Ge(e,r);var n=qe(r);return $e(e,t(t({},r),{mode:0}),Ke,n)}var Xe,Ye=.55;function Ze(e){return Le(e,205,245,205,220)}function et(e,t){var r=e.h,n=e.s,o=e.l,a=e.a,i=o<.2||n<.24,u=!i&&r>205&&r<245;if(o>.5){var s=Le(o,.5,1,Ye,t.l);if(i)return{h:t.h,s:t.s,l:s,a:a};var c=r;return u&&(c=Ze(r)),{h:c,s:n,l:s,a:a}}if(i)return{h:t.h,s:t.s,l:Le(o,0,.5,t.l,Ye),a:a};var l,d=r;return u?(d=Ze(r),l=Le(o,0,.5,t.l,Math.min(1,.6000000000000001))):l=Le(o,0,.5,t.l,Ye),{h:d,s:n,l:l,a:a}}function tt(e,r){if(0===r.mode)return Ge(e,r);var n=Ne(r);return $e(e,t(t({},r),{mode:0}),et,n)}function rt(e,t,r){var n=e.h,o=e.s,a=e.l,i=e.a,u=n,s=o;return(a<.2||o<.24)&&(a<.5?(u=t.h,s=t.s):(u=r.h,s=r.s)),{h:u,s:s,l:Le(a,0,1,.5,.2),a:i}}function nt(e,r){if(0===r.mode)return Ge(e,r);var n=Ne(r),o=qe(r);return $e(e,t(t({},r),{mode:0}),rt,n,o)}function ot(e,t){return Je(e,t)}function at(e){var t=[];return e.mode===Xe.dark&&t.push("invert(100%) hue-rotate(180deg)"),100!==e.brightness&&t.push("brightness("+e.brightness+"%)"),100!==e.contrast&&t.push("contrast("+e.contrast+"%)"),0!==e.grayscale&&t.push("grayscale("+e.grayscale+"%)"),0!==e.sepia&&t.push("sepia("+e.sepia+"%)"),0===t.length?null:t.join(" ")}!function(e){e[e.light=0]="light",e[e.dark=1]="dark"}(Xe||(Xe={}));var it=0,ut=new Map,st=new Map;function ct(e){return r(this,void 0,void 0,(function(){return n(this,(function(t){return[2,new Promise((function(t,r){var n=++it;ut.set(n,t),st.set(n,r),chrome.runtime.sendMessage({type:s,data:e,id:n})}))]}))}))}chrome.runtime.onMessage.addListener((function(e){var t=e.type,r=e.data,n=e.error,o=e.id;if(t===u){var a=ut.get(o),i=st.get(o);ut.delete(o),st.delete(o),n?i&&i(n):a&&a(r)}}));var lt=new(function(){function e(){this.queue=[],this.timerId=null,this.frameDuration=1e3/60}return e.prototype.addToQueue=function(e){this.queue.push(e),this.startQueue()},e.prototype.stopQueue=function(){null!==this.timerId&&(cancelAnimationFrame(this.timerId),this.timerId=null),this.queue=[]},e.prototype.startQueue=function(){var e=this;this.timerId||(this.timerId=requestAnimationFrame((function(){e.timerId=null;for(var t,r=Date.now();t=e.queue.shift();)if(t(),Date.now()-r>=e.frameDuration){e.startQueue();break}})))},e}());function dt(e){return r(this,void 0,void 0,(function(){var o=this;return n(this,(function(a){return[2,new Promise((function(a,i){return r(o,void 0,void 0,(function(){var r,o,u,s;return n(this,(function(n){switch(n.label){case 0:return e.startsWith("data:")?(r=e,[3,4]):[3,1];case 1:return n.trys.push([1,3,,4]),[4,ft(e)];case 2:return r=n.sent(),[3,4];case 3:return o=n.sent(),i(o),[3,4];case 4:return n.trys.push([4,6,,7]),[4,ht(r)];case 5:return u=n.sent(),lt.addToQueue((function(){a(t({src:e,dataURL:r,width:u.naturalWidth,height:u.naturalHeight},function(e){pt||(t=mt,r=mt,(pt=document.createElement("canvas")).width=t,pt.height=r,(vt=pt.getContext("2d")).imageSmoothingEnabled=!1);var t,r;var n=e.naturalWidth,o=e.naturalHeight;if(0===o||0===n)return N("logWarn(Image is empty "+e.currentSrc+")"),null;if(n*o*4>gt)return q("Skipped large image analyzing(Larger than 5mb in memory)"),{isDark:!1,isLight:!1,isTransparent:!1,isLarge:!1,isTooLarge:!0};var a=n*o,i=Math.min(1,Math.sqrt(mt/a)),u=Math.ceil(n*i),s=Math.ceil(o*i);vt.clearRect(0,0,u,s),vt.drawImage(e,0,0,n,o,0,0,u,s);var c,l,d,f,h,p,v,m=vt.getImageData(0,0,u,s).data,g=.05,b=.4,y=.7,w=0,k=0,S=0;for(d=0;d<s;d++)for(l=0;l<u;l++)f=m[(c=4*(d*u+l))+0]/255,h=m[c+1]/255,p=m[c+2]/255,m[c+3]/255<g?w++:((v=.2126*f+.7152*h+.0722*p)<b&&k++,v>y&&S++);var _=u*s,E=_-w;return{isDark:k/E>=.7,isLight:S/E>=.7,isTransparent:w/_>=.1,isLarge:a>=48e4,isTooLarge:!1}}(u)))})),[3,7];case 6:return s=n.sent(),i(s),[3,7];case 7:return[2]}}))}))}))]}))}))}function ft(e){return r(this,void 0,void 0,(function(){return n(this,(function(t){switch(t.label){case 0:return new URL(e).origin!==location.origin?[3,2]:[4,S(e)];case 1:return[2,t.sent()];case 2:return[4,ct({url:e,responseType:"data-url"})];case 3:return[2,t.sent()]}}))}))}function ht(e){return r(this,void 0,void 0,(function(){return n(this,(function(t){return[2,new Promise((function(t,r){var n=new Image;n.onload=function(){return t(n)},n.onerror=function(){return r("Unable to load image "+e)},n.src=e}))]}))}))}var pt,vt,mt=1024;var gt=5242880;function bt(e,t){var r=e.dataURL,n=e.width,o=e.height,a=['<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="'+n+'" height="'+o+'">',"<defs>",'<filter id="darkreader-image-filter">','<feColorMatrix type="matrix" values="'+De(t).slice(0,4).map((function(e){return e.map((function(e){return e.toFixed(3)})).join(" ")})).join(" ")+'" />',"</filter>","</defs>",'<image width="'+n+'" height="'+o+'" filter="url(#darkreader-image-filter)" xlink:href="'+r+'" />',"</svg>"].join("");return"data:image/svg+xml;base64,"+btoa(a)}function yt(){lt&<.stopQueue(),pt=null,vt=null}function wt(e,t){return Boolean(e&&e.getPropertyPriority(t))}function kt(e,t,r,n,o,a){if(e.startsWith("--")){if(i=function(e,t,r,n,o,a){return e.getModifierForVariable({varName:t,sourceValue:r,rule:n,ignoredImgSelectors:o,isCancelled:a})}(n,e,t,r,o,a))return{property:e,value:i,important:wt(r.style,e),sourceValue:t}}else if(t.includes("var(")){if(i=function(e,t,r){return e.getModifierForVarDependant(t,r)}(n,e,t))return{property:e,value:i,important:wt(r.style,e),sourceValue:t}}else if(e.includes("color")&&"-webkit-print-color-adjust"!==e||"fill"===e||"stroke"===e||"stop-color"===e){if(i=function(e,t){if(xt.has(t.toLowerCase()))return t;try{var r=Vt(t);return e.includes("background")?function(e){return Je(r,e)}:e.includes("border")||e.includes("outline")?function(e){return nt(r,e)}:function(e){return tt(r,e)}}catch(e){return N("Color parse error",e),null}}(e,t))return{property:e,value:i,important:wt(r.style,e),sourceValue:t}}else if("background-image"===e||"list-style-image"===e){if(i=Lt(t,r,o,a))return{property:e,value:i,important:wt(r.style,e),sourceValue:t}}else if(e.includes("shadow")){var i;if(i=Pt(t))return{property:e,value:i,important:wt(r.style,e),sourceValue:t}}return null}function St(e,r,n){var o=[];return r||(o.push("html {"),o.push(" background-color: "+Je({r:255,g:255,b:255},e)+" !important;"),o.push("}")),o.push((r?"":"html, body, ")+(n?"input, textarea, select, button":"")+" {"),o.push(" background-color: "+Je({r:255,g:255,b:255},e)+";"),o.push("}"),o.push("html, body, "+(n?"input, textarea, select, button":"")+" {"),o.push(" border-color: "+nt({r:76,g:76,b:76},e)+";"),o.push(" color: "+tt({r:0,g:0,b:0},e)+";"),o.push("}"),o.push("a {"),o.push(" color: "+tt({r:0,g:64,b:255},e)+";"),o.push("}"),o.push("table {"),o.push(" border-color: "+nt({r:128,g:128,b:128},e)+";"),o.push("}"),o.push("::placeholder {"),o.push(" color: "+tt({r:169,g:169,b:169},e)+";"),o.push("}"),o.push("input:-webkit-autofill,"),o.push("textarea:-webkit-autofill,"),o.push("select:-webkit-autofill {"),o.push(" background-color: "+Je({r:250,g:255,b:189},e)+" !important;"),o.push(" color: "+tt({r:0,g:0,b:0},e)+" !important;"),o.push("}"),e.scrollbarColor&&o.push(function(e){var r,n,o,a,i,u,s=[];if("auto"===e.scrollbarColor)r=Je({r:241,g:241,b:241},e),n=tt({r:96,g:96,b:96},e),o=Je({r:176,g:176,b:176},e),a=Je({r:144,g:144,b:144},e),i=Je({r:96,g:96,b:96},e),u=Je({r:255,g:255,b:255},e);else{var c=be(Ee(e.scrollbarColor)),l=c.l>.5,d=function(e){return t(t({},c),{l:Pe(c.l+e,0,1)})},f=function(e){return t(t({},c),{l:Pe(c.l-e,0,1)})};r=we(f(.4)),n=we(l?f(.4):d(.4)),o=we(c),a=we(d(.1)),i=we(d(.2))}s.push("::-webkit-scrollbar {"),s.push(" background-color: "+r+";"),s.push(" color: "+n+";"),s.push("}"),s.push("::-webkit-scrollbar-thumb {"),s.push(" background-color: "+o+";"),s.push("}"),s.push("::-webkit-scrollbar-thumb:hover {"),s.push(" background-color: "+a+";"),s.push("}"),s.push("::-webkit-scrollbar-thumb:active {"),s.push(" background-color: "+i+";"),s.push("}"),s.push("::-webkit-scrollbar-corner {"),s.push(" background-color: "+u+";"),s.push("}"),h&&(s.push("* {"),s.push(" scrollbar-color: "+o+" "+r+";"),s.push("}"));return s.join("\n")}(e)),e.selectionColor&&o.push(function(e){var t=[],r=_t(e),n=r.backgroundColorSelection,o=r.foregroundColorSelection;return["::selection","::-moz-selection"].forEach((function(e){t.push(e+" {"),t.push(" background-color: "+n+" !important;"),t.push(" color: "+o+" !important;"),t.push("}")})),t.join("\n")}(e)),o.join("\n")}function _t(e){var r,n;if("auto"===e.selectionColor)r=Je({r:0,g:96,b:212},t(t({},e),{grayscale:0})),n=tt({r:255,g:255,b:255},t(t({},e),{grayscale:0}));else{var o=be(Ee(e.selectionColor));r=e.selectionColor,n=o.l<.5?"#FFF":"#000"}return{backgroundColorSelection:r,foregroundColorSelection:n}}function Et(e,t){var r=t.strict,n=[];return n.push("html, body, "+(r?"body :not(iframe)":"body > :not(iframe)")+" {"),n.push(" background-color: "+Je({r:255,g:255,b:255},e)+" !important;"),n.push(" border-color: "+nt({r:64,g:64,b:64},e)+" !important;"),n.push(" color: "+tt({r:0,g:0,b:0},e)+" !important;"),n.push("}"),n.join("\n")}var xt=new Set(["inherit","transparent","initial","currentcolor","none","unset"]),Ct=new Map;function Vt(e){if(e=e.trim(),Ct.has(e))return Ct.get(e);var t=Ee(e);return Ct.set(e,t),t}function Tt(e){try{return Vt(e)}catch(e){return null}}var Rt=/[\-a-z]+gradient\(([^\(\)]*(\(([^\(\)]*(\(.*?\)))*[^\(\)]*\))){0,15}[^\(\)]*\)/g,Mt=new Map,At=new Map;function Lt(e,o,a,i){var u=this;try{var s=je(Rt,e),c=je(de,e);if(0===c.length&&0===s.length)return e;var l=function(t){var r=0;return t.map((function(t){var n=e.indexOf(t,r);return r=n+t.length,{match:t,index:n}}))},d=l(c).map((function(e){return t({type:"url"},e)})).concat(l(s).map((function(e){return t({type:"gradient"},e)}))).sort((function(e,t){return e.index-t.index})),f=function(e,r){var n,o=e.isDark,a=e.isLight,i=e.isTransparent,u=e.isLarge,s=e.isTooLarge,c=e.width;if(s)n='url("'+e.src+'")';else if(o&&i&&1===r.mode&&!u&&c>2){q("Inverting dark image "+e.src),n='url("'+bt(e,t(t({},r),{sepia:Pe(r.sepia+10,0,100)}))+'")'}else if(a&&!i&&1===r.mode){if(u)n="none";else q("Dimming light image "+e.src),n='url("'+bt(e,r)+'")'}else if(0===r.mode&&a&&!u){q("Applying filter to image "+e.src),n='url("'+bt(e,t(t({},r),{brightness:Pe(r.brightness-10,5,200),sepia:Pe(r.sepia+10,0,100)}))+'")'}else n=null;return n},h=[],p=0;return d.forEach((function(t,s){var c=t.match,l=t.type,v=t.index,m=p,g=v+c.length;p=g,h.push((function(){return e.substring(m,v)})),h.push("url"===l?function(e){var t;if(function(e,t){if(!e||0===t.length)return!1;if(t.some((function(e){return"*"===e})))return!0;for(var r=e.split(/,\s*/g),n=function(e){var n=t[e];if(r.some((function(e){return e===n})))return{value:!0}},o=0;o<t.length;o++){var a=n(o);if("object"==typeof a)return a.value}return!1}(o.selectorText,a))return null;var s=he(e),c=o.parentStyleSheet,l=c&&c.href?pe(c.href):(null===(t=c.ownerNode)||void 0===t?void 0:t.baseURI)||location.origin,d='url("'+(s=ie(l,s))+'")';return function(e){return r(u,void 0,void 0,(function(){var t,r;return n(this,(function(n){switch(n.label){case 0:return Mt.has(s)?(t=Mt.get(s),[3,7]):[3,1];case 1:return n.trys.push([1,6,,7]),At.has(s)?(r=At.get(s),[4,new Promise((function(e){return r.push(e)}))]):[3,3];case 2:return(t=n.sent())?[3,5]:[2,null];case 3:return At.set(s,[]),[4,dt(s)];case 4:t=n.sent(),Mt.set(s,t),At.get(s).forEach((function(e){return e(t)})),At.delete(s),n.label=5;case 5:return i()?[2,null]:[3,7];case 6:return N(n.sent()),At.has(s)&&(At.get(s).forEach((function(e){return e(null)})),At.delete(s)),[2,d];case 7:return[2,f(t,e)||d]}}))}))}}(c):function(e){var t=e.match(/^(.*-gradient)\((.*)\)$/),r=t[1],n=t[2],o=/^(from|color-stop|to)\(([^\(\)]*?,\s*)?(.*?)\)$/,a=je(/([^\(\),]+(\([^\(\)]*(\([^\(\)]*\)*[^\(\)]*)?\))?[^\(\),]*),?/g,n,1).map((function(e){var t=Tt(e=e.trim());if(t)return function(e){return ot(t,e)};var r=e.lastIndexOf(" ");if(t=Tt(e.substring(0,r)))return function(n){return ot(t,n)+" "+e.substring(r+1)};var n=e.match(o);return n&&(t=Tt(n[3]))?function(e){return n[1]+"("+(n[2]?n[2]+", ":"")+ot(t,e)+")"}:function(){return e}}));return function(e){return r+"("+a.map((function(t){return t(e)})).join(", ")+")"}}(c)),s===d.length-1&&h.push((function(){return e.substring(g)}))})),function(e){var t=h.filter(Boolean).map((function(t){return t(e)}));return t.some((function(e){return e instanceof Promise}))?Promise.all(t).then((function(e){return e.join("")})):t.join("")}}catch(t){return N("Unable to parse gradient "+e,t),null}}function Pt(e){try{var t=0,r=je(/(^|\s)(?!calc)([a-z]+\(.+?\)|#[0-9a-f]+|[a-z]+)(.*?(inset|outset)?($|,))/gi,e,2),n=r.map((function(n,o){var a=t,i=e.indexOf(n,t),u=i+n.length;t=u;var s=Tt(n);return s?function(t){return""+e.substring(a,i)+function(e,t){return Je(e,t)}(s,t)+(o===r.length-1?e.substring(u):"")}:function(){return e.substring(a,u)}}));return function(e){return n.map((function(t){return t(e)})).join("")}}catch(t){return N("Unable to parse shadow "+e,t),null}}function Ot(){Ct.clear(),Be.clear(),We.clear(),Mt.clear(),yt(),At.clear()}var jt=new(function(){function e(){this.varTypes=new Map,this.rulesQueue=[],this.definedVars=new Set,this.varRefs=new Map,this.unknownColorVars=new Set,this.unknownBgVars=new Set,this.undefinedVars=new Set,this.initialVarTypes=new Map,this.changedTypeVars=new Set,this.typeChangeSubscriptions=new Map,this.unstableVarValues=new Map}return e.prototype.clear=function(){this.varTypes.clear(),this.rulesQueue.splice(0),this.definedVars.clear(),this.varRefs.clear(),this.unknownColorVars.clear(),this.unknownBgVars.clear(),this.undefinedVars.clear(),this.initialVarTypes.clear(),this.changedTypeVars.clear(),this.typeChangeSubscriptions.clear(),this.unstableVarValues.clear()},e.prototype.isVarType=function(e,t){return this.varTypes.has(e)&&(this.varTypes.get(e)&t)>0},e.prototype.addRulesForMatching=function(e){this.rulesQueue.push(e)},e.prototype.matchVariablesAndDependants=function(){var e=this;this.changedTypeVars.clear(),this.initialVarTypes=new Map(this.varTypes),this.collectRootVariables(),this.collectVariablesAndVarDep(this.rulesQueue),this.rulesQueue.splice(0),this.collectRootVarDependants(),this.varRefs.forEach((function(t,r){t.forEach((function(t){e.varTypes.has(r)&&e.resolveVariableType(t,e.varTypes.get(r))}))})),this.unknownColorVars.forEach((function(t){e.unknownBgVars.has(t)?(e.unknownColorVars.delete(t),e.unknownBgVars.delete(t),e.resolveVariableType(t,1)):e.isVarType(t,7)?e.unknownColorVars.delete(t):e.undefinedVars.add(t)})),this.unknownBgVars.forEach((function(t){null!=e.findVarRef(t,(function(t){return e.unknownColorVars.has(t)||e.isVarType(t,6)}))?e.itarateVarRefs(t,(function(t){e.resolveVariableType(t,1)})):e.isVarType(t,9)?e.unknownBgVars.delete(t):e.undefinedVars.add(t)})),this.changedTypeVars.forEach((function(t){e.typeChangeSubscriptions.has(t)&&e.typeChangeSubscriptions.get(t).forEach((function(e){e()}))})),this.changedTypeVars.clear()},e.prototype.getModifierForVariable=function(e){var t=this;return function(r){var n=e.varName,o=e.sourceValue,a=e.rule,i=e.ignoredImgSelectors,u=e.isCancelled,s=function(){var e=[],s=function(a,i,u){if(t.isVarType(n,a)){var s,c=i(n);if($t(o))if(Ht(o)){var l=Jt(o,t.unstableVarValues);l||(l=1===a?"#ffffff":"#000000"),s=u(l,r)}else s=Nt(o,(function(e){return i(e)}),(function(e){return u(e,r)}));else s=u(o,r);e.push({property:c,value:s})}};if(s(1,Bt,Gt),s(2,Wt,Qt),s(4,It,Kt),t.isVarType(n,8)){var c=Ut(n),l=o;$t(o)&&(l=Nt(o,(function(e){return Bt(e)}),(function(e){return Gt(e,r)})));var d=Lt(l,a,i,u);l="function"==typeof d?d(r):d,e.push({property:c,value:l})}return e},c=new Set;return{declarations:s(),onTypeChange:{addListener:function(e){var r=function(){var t=s();e(t)};c.add(r),t.subscribeForVarTypeChange(n,r)},removeListeners:function(){c.forEach((function(e){t.unsubscribeFromVariableTypeChanges(n,e)}))}}}}},e.prototype.getModifierForVarDependant=function(e,t){var r=this;if(t.match(/^\s*(rgb|hsl)a?\(/)){var n=e.startsWith("background"),o="color"===e||"caret-color"===e;return function(e){var a=Jt(t,r.unstableVarValues);return a||(a=n?"#ffffff":"#000000"),(n?Gt:o?Qt:Kt)(a,e)}}if("background-color"===e)return function(e){return Nt(t,(function(e){return Bt(e)}),(function(t){return Gt(t,e)}))};if("color"===e||"caret-color"===e)return function(e){return Nt(t,(function(e){return Wt(e)}),(function(t){return Qt(t,e)}))};if("background"===e||"background-image"===e||"box-shadow"===e)return function(n){var o=new Set,a=function(){var a=Nt(t,(function(e){return r.isVarType(e,1)?Bt(e):r.isVarType(e,8)?Ut(e):(o.add(e),e)}),(function(e){return Gt(e,n)}));return"box-shadow"===e&&Pt(a)(n)||a},i=a();return o.size>0?new Promise((function(e){var t=o.values().next().value,n=function(){r.unsubscribeFromVariableTypeChanges(t,n);var o=a();e(o)};r.subscribeForVarTypeChange(t,n)})):i};if(e.startsWith("border")||e.startsWith("outline")){if(t.endsWith(")")){var a=t.match(/((rgb|hsl)a?)\(/);if(a){var i=a.index;return function(e){return Jt(t,r.unstableVarValues)?""+t.substring(0,i)+Kt(Jt(t.substring(i,t.length),r.unstableVarValues),e):t}}}return function(e){return Nt(t,(function(e){return It(e)}),(function(t){return Qt(t,e)}))}}return null},e.prototype.subscribeForVarTypeChange=function(e,t){this.typeChangeSubscriptions.has(e)||this.typeChangeSubscriptions.set(e,new Set);var r=this.typeChangeSubscriptions.get(e);r.has(t)||r.add(t)},e.prototype.unsubscribeFromVariableTypeChanges=function(e,t){this.typeChangeSubscriptions.has(e)&&this.typeChangeSubscriptions.get(e).delete(t)},e.prototype.collectVariablesAndVarDep=function(e){var t=this;e.forEach((function(e){ue(e,(function(e){e.style&&le(e.style,(function(e,r){zt(e)&&t.inspectVariable(e,r),$t(r)&&t.inspectVarDependant(e,r)}))}))}))},e.prototype.collectRootVariables=function(){var e=this;le(document.documentElement.style,(function(t,r){zt(t)&&e.inspectVariable(t,r)}))},e.prototype.inspectVariable=function(e,t){(this.unstableVarValues.set(e,t),$t(t)&&Ht(t)&&(this.unknownColorVars.add(e),this.definedVars.add(e)),this.definedVars.has(e))||(this.definedVars.add(e),Tt(t)?this.unknownColorVars.add(e):(t.includes("url(")||t.includes("linear-gradient(")||t.includes("radial-gradient("))&&this.resolveVariableType(e,8))},e.prototype.resolveVariableType=function(e,t){var r=this.initialVarTypes.get(e)||0,n=(this.varTypes.get(e)||0)|t;this.varTypes.set(e,n),(n!==r||this.undefinedVars.has(e))&&(this.changedTypeVars.add(e),this.undefinedVars.delete(e)),this.unknownColorVars.delete(e),this.unknownBgVars.delete(e)},e.prototype.collectRootVarDependants=function(){var e=this;le(document.documentElement.style,(function(t,r){$t(r)&&e.inspectVarDependant(t,r)}))},e.prototype.inspectVarDependant=function(e,t){var r=this;zt(e)?this.iterateVarDeps(t,(function(t){r.varRefs.has(e)||r.varRefs.set(e,new Set),r.varRefs.get(e).add(t)})):"background-color"===e||"box-shadow"===e?this.iterateVarDeps(t,(function(e){return r.resolveVariableType(e,1)})):"color"===e||"caret-color"===e?this.iterateVarDeps(t,(function(e){return r.resolveVariableType(e,2)})):e.startsWith("border")||e.startsWith("outline")?this.iterateVarDeps(t,(function(e){return r.resolveVariableType(e,4)})):"background"!==e&&"background-image"!==e||this.iterateVarDeps(t,(function(e){if(!r.isVarType(e,9)){var t=null!=r.findVarRef(e,(function(e){return r.unknownColorVars.has(e)||r.isVarType(e,6)}));r.itarateVarRefs(e,(function(e){t?r.resolveVariableType(e,1):r.unknownBgVars.add(e)}))}}))},e.prototype.iterateVarDeps=function(e,t){var r=new Set;!function(e,t){Nt(e,(function(e){return t(e),e}))}(e,(function(e){return r.add(e)})),r.forEach((function(e){return t(e)}))},e.prototype.findVarRef=function(e,t,r){var n,a;if(void 0===r&&(r=new Set),r.has(e))return null;if(r.add(e),t(e))return e;var i=this.varRefs.get(e);if(!i||0===i.size)return null;try{for(var u=o(i),s=u.next();!s.done;s=u.next()){var c=s.value,l=this.findVarRef(c,t,r);if(l)return l}}catch(e){n={error:e}}finally{try{s&&!s.done&&(a=u.return)&&a.call(u)}finally{if(n)throw n.error}}return null},e.prototype.itarateVarRefs=function(e,t){this.findVarRef(e,(function(e){return t(e),!1}))},e.prototype.setOnRootVariableChange=function(e){this.onRootVariableDefined=e},e.prototype.putRootVars=function(e,t){var r,n,i=this,u=e.sheet;u.cssRules.length>0&&u.deleteRule(0);var s=new Map;le(document.documentElement.style,(function(e,r){zt(e)&&(i.isVarType(e,1)&&s.set(Bt(e),Gt(r,t)),i.isVarType(e,2)&&s.set(Wt(e),Qt(r,t)),i.isVarType(e,4)&&s.set(It(e),Kt(r,t)),i.subscribeForVarTypeChange(e,i.onRootVariableDefined))}));var c=[];c.push(":root {");try{for(var l=o(s),d=l.next();!d.done;d=l.next()){var f=a(d.value,2),h=f[0],p=f[1];c.push(" "+h+": "+p+";")}}catch(e){r={error:e}}finally{try{d&&!d.done&&(n=l.return)&&n.call(l)}finally{if(r)throw r.error}}c.push("}");var v=c.join("\n");u.insertRule(v)},e}());function Dt(e,t){void 0===t&&(t=0);var r=e.indexOf("var(",t);if(r>=0){var n=function(e,t){void 0===t&&(t=0);for(var r=e.length,n=0,o=-1,a=t;a<r;a++)if(0===n){if((i=e.indexOf("(",a))<0)break;o=i,n++,a=i}else{var i,u=e.indexOf(")",a);if(u<0)break;if((i=e.indexOf("(",a))<0||u<i){if(0==--n)return{start:o,end:u+1};a=u}else n++,a=i}return null}(e,r+3);return n?{start:r,end:n.end}:null}}function Ft(e,t){var r=function(e){for(var t,r=[],n=0;t=Dt(e,n);){var o=t.start,a=t.end;r.push({start:o,end:a,value:e.substring(o,a)}),n=t.end+1}return r}(e),n=r.length;if(0===n)return e;var o=e.length,a=r.map((function(e){return t(e.value)})),i=[];i.push(e.substring(0,r[0].start));for(var u=0;u<n;u++){i.push(a[u]);var s=r[u].end,c=u<n-1?r[u+1].start:o;i.push(e.substring(s,c))}return i.join("")}function qt(e){var t,r,n=e.indexOf(",");return n>=0?(t=e.substring(4,n).trim(),r=e.substring(n+1,e.length-1).trim()):(t=e.substring(4,e.length-1).trim(),r=""),{name:t,fallback:r}}function Nt(e,t,r){return Ft(e,(function(e){var n=qt(e),o=n.name,a=n.fallback,i=t(o);return a?"var("+i+", "+($t(a)?Nt(a,t,r):r?r(a):a)+")":"var("+i+")"}))}function Bt(e){return"--darkreader-bg"+e}function Wt(e){return"--darkreader-text"+e}function It(e){return"--darkreader-border"+e}function Ut(e){return"--darkreader-bgimg"+e}function zt(e){return e.startsWith("--")}function $t(e){return e.includes("var(")}function Ht(e){return e.match(/^\s*(rgb|hsl)a?\(/)}function Gt(e,t){var r=Tt(e);return r?Je(r,t):e}function Qt(e,t){var r=Tt(e);return r?tt(r,t):e}function Kt(e,t){var r=Tt(e);return r?nt(r,t):e}function Jt(e,t,r){void 0===r&&(r=new Set);var n=!1,o=Ft(e,(function(e){var o=qt(e),a=o.name,i=o.fallback;if(r.has(a))return n=!0,null;r.add(a);var u=t.get(a)||i,s=null;return u&&(s=$t(u)?Jt(u,t,r):u),s||(n=!0,null)}));return n?null:o}var Xt={"background-color":{customProp:"--darkreader-inline-bgcolor",cssProp:"background-color",dataAttr:"data-darkreader-inline-bgcolor"},"background-image":{customProp:"--darkreader-inline-bgimage",cssProp:"background-image",dataAttr:"data-darkreader-inline-bgimage"},"border-color":{customProp:"--darkreader-inline-border",cssProp:"border-color",dataAttr:"data-darkreader-inline-border"},"border-bottom-color":{customProp:"--darkreader-inline-border-bottom",cssProp:"border-bottom-color",dataAttr:"data-darkreader-inline-border-bottom"},"border-left-color":{customProp:"--darkreader-inline-border-left",cssProp:"border-left-color",dataAttr:"data-darkreader-inline-border-left"},"border-right-color":{customProp:"--darkreader-inline-border-right",cssProp:"border-right-color",dataAttr:"data-darkreader-inline-border-right"},"border-top-color":{customProp:"--darkreader-inline-border-top",cssProp:"border-top-color",dataAttr:"data-darkreader-inline-border-top"},"box-shadow":{customProp:"--darkreader-inline-boxshadow",cssProp:"box-shadow",dataAttr:"data-darkreader-inline-boxshadow"},color:{customProp:"--darkreader-inline-color",cssProp:"color",dataAttr:"data-darkreader-inline-color"},fill:{customProp:"--darkreader-inline-fill",cssProp:"fill",dataAttr:"data-darkreader-inline-fill"},stroke:{customProp:"--darkreader-inline-stroke",cssProp:"stroke",dataAttr:"data-darkreader-inline-stroke"},"outline-color":{customProp:"--darkreader-inline-outline",cssProp:"outline-color",dataAttr:"data-darkreader-inline-outline"},"stop-color":{customProp:"--darkreader-inline-stopcolor",cssProp:"stop-color",dataAttr:"data-darkreader-inline-stopcolor"}},Yt=Object.values(Xt),Zt={};Yt.forEach((function(e){var t=e.cssProp,r=e.customProp;return Zt[r]=t}));var er=["style","fill","stop-color","stroke","bgcolor","color"],tr=er.map((function(e){return"["+e+"]"})).join(", ");function rr(){return Yt.map((function(e){var t=e.dataAttr,r=e.customProp;return["["+t+"] {"," "+e.cssProp+": var("+r+") !important;","}"].join("\n")})).join("\n")}var nr=new Map,or=new Map;function ar(e,t,r){nr.has(e)&&(nr.get(e).disconnect(),or.get(e).disconnect());var n=new WeakSet;function o(e){(function(e){var t=[];return e instanceof Element&&e.matches(tr)&&t.push(e),(e instanceof Element||b&&e instanceof ShadowRoot||e instanceof Document)&&F(t,e.querySelectorAll(tr)),t})(e).forEach((function(e){n.has(e)||(n.add(e),t(e))})),z(e,(function(o){n.has(e)||(n.add(e),r(o.shadowRoot),ar(o.shadowRoot,t,r))}))}var u=re(e,{onMinorMutations:function(e){e.additions.forEach((function(e){return o(e)}))},onHugeMutations:function(){o(e)}});nr.set(e,u);var s=0,c=null,l=W({seconds:10}),d=W({seconds:2}),f=[],h=null,p=B((function(e){e.forEach((function(e){er.includes(e.attributeName)&&t(e.target)}))})),v=new MutationObserver((function(e){if(h)f.push.apply(f,i([],a(e)));else{s++;var t=Date.now();if(null==c)c=t;else if(s>=50){if(t-c<l)return h=setTimeout((function(){c=null,s=0,h=null;var e=f;f=[],p(e)}),d),void f.push.apply(f,i([],a(e)));c=t,s=1}p(e)}}));v.observe(e,{attributes:!0,attributeFilter:er.concat(Yt.map((function(e){return e.dataAttr}))),subtree:!0}),or.set(e,v)}var ir=new WeakMap,ur=["brightness","contrast","grayscale","sepia","mode"];function sr(e,t){return er.map((function(t){return t+'="'+e.getAttribute(t)+'"'})).concat(ur.map((function(e){return e+'="'+t[e]+'"'}))).join(" ")}function cr(e,t,r,n){if(sr(e,t)!==ir.get(e)){var o=new Set(Object.keys(Xt));if(r.length>0&&function(e,t){for(var r=0,n=t.length;r<n;r++){var o=t[r];if(e.matches(o))return!0}return!1}(e,r))o.forEach((function(t){e.removeAttribute(Xt[t].dataAttr)}));else{if(e.hasAttribute("bgcolor"))((u=e.getAttribute("bgcolor")).match(/^[0-9a-f]{3}$/i)||u.match(/^[0-9a-f]{6}$/i))&&(u="#"+u),s("background-color","background-color",u);if(e.hasAttribute("color")&&"mask-icon"!==e.rel)((u=e.getAttribute("color")).match(/^[0-9a-f]{3}$/i)||u.match(/^[0-9a-f]{6}$/i))&&(u="#"+u),s("color","color",u);if(e instanceof SVGElement){if(e.hasAttribute("fill")){var a=e.getAttribute("fill");if("none"!==a)if(e instanceof SVGTextElement)s("fill","color",a);else{var i=function(){var t=e.getBoundingClientRect(),r=t.width,n=t.height;s("fill",r>32||n>32?"background-color":"color",a)};K()?i():X(i)}}e.hasAttribute("stop-color")&&s("stop-color","background-color",e.getAttribute("stop-color"))}if(e.hasAttribute("stroke")){var u=e.getAttribute("stroke");s("stroke",e instanceof SVGLineElement||e instanceof SVGTextElement?"border-color":"color",u)}e.style&&le(e.style,(function(t,r){if("background-image"!==t||!r.includes("url"))if(Xt.hasOwnProperty(t))s(t,t,r);else{var n=Zt[t];!n||e.style.getPropertyValue(n)||e.hasAttribute(n)||e.style.setProperty(t,"")}})),e.style&&e instanceof SVGTextElement&&e.style.fill&&s("fill","color",e.style.getPropertyValue("fill")),D(o,(function(t){e.removeAttribute(Xt[t].dataAttr)})),ir.set(e,sr(e,t))}}function s(r,a,i){var u=Xt[r],s=u.customProp,c=u.dataAttr,l=kt(a,i,{},jt,n,null);if(l){var d=l.value;"function"==typeof d&&(d=d(t)),e.style.setProperty(s,d),e.hasAttribute(c)||e.setAttribute(c,""),o.delete(r)}}}var lr="theme-color",dr='meta[name="theme-color"]',fr=null,hr=null;function pr(e,t){fr=fr||e.content;try{var r=Ee(fr);e.content=Je(r,t)}catch(e){N(e)}}var vr=["mode","brightness","contrast","grayscale","sepia","darkSchemeBackgroundColor","darkSchemeTextColor","lightSchemeBackgroundColor","lightSchemeTextColor"];var mr=function(){var e=[],t=null;function r(){for(var r;r=e.shift();)r();t=null}return{add:function(n){e.push(n),t||(t=requestAnimationFrame(r))},cancel:function(){e.splice(0),cancelAnimationFrame(t),t=null}}}();function gr(){var e=0,t=new Set,r=new Map,n=new Set,o=null,u=!1,s=!1;return{modifySheet:function(c){var l=c.sourceCSSRules,d=c.theme,f=c.ignoreImageAnalysis,h=c.force,p=c.prepareSheet,v=c.isAsyncCancelled,m=0===r.size,g=new Set(r.keys()),b=function(e){return vr.map((function(t){return t+":"+e[t]})).join(";")}(d),y=b!==o;u&&(s=!0);var w=[];if(ue(l,(function(e){var n=e.cssText,o=!1;if(g.delete(n),e.parentRule instanceof CSSMediaRule&&(n+=";"+e.parentRule.media.mediaText),t.has(n)||(t.add(n),o=!0),o){m=!0;var a=[];e.style&&le(e.style,(function(t,r){var n=kt(t,r,e,jt,f,v);n&&a.push(n)}));var i=null;if(a.length>0){var u=e.parentRule;i={selector:e.selectorText,declarations:a,parentRule:u},w.push(i)}r.set(n,i)}else w.push(r.get(n))}),(function(){u=!0})),g.forEach((function(e){t.delete(e),r.delete(e)})),o=b,h||m||y){e++;var k=new Map,S=new Map,_=0,E=0,x={rule:null,rules:[],isGroup:!0},C=new WeakMap;n.forEach((function(e){return e()})),n.clear(),w.filter((function(e){return e})).forEach((function(t){var r=t.selector,o=t.declarations,u=R(t.parentRule),s={selector:r,declarations:[],isGroup:!1},c=s.declarations;function l(t,r,n,o){var a=++_,i={property:t,value:null,important:n,asyncKey:a,sourceValue:o};c.push(i);var u=e;r.then((function(t){t&&!v()&&u===e&&(i.value=t,mr.add((function(){v()||u!==e||function(e){var t=k.get(e),r=t.rule,n=t.target,o=t.index;n.deleteRule(o),T(n,o,r),k.delete(e)}(a)})))}))}function f(t,r,o,u){var s=r,d=s.declarations,f=s.onTypeChange,h=++E,p=e,m=c.length,g=[];if(0===d.length){var b={property:t,value:u,important:o,sourceValue:u,varKey:h};c.push(b),g=[b]}d.forEach((function(e){if(e.value instanceof Promise)l(e.property,e.value,o,u);else{var t={property:e.property,value:e.value,important:o,sourceValue:u,varKey:h};c.push(t),g.push(t)}})),f.addListener((function(t){if(!v()&&p===e){var r=t.map((function(e){return{property:e.property,value:e.value,important:o,sourceValue:u,varKey:h}})),n=c.indexOf(g[0],m);c.splice.apply(c,i([n,g.length],a(r))),g=r,function(e){var t=S.get(e),r=t.rule,n=t.target,o=t.index;n.deleteRule(o),T(n,o,r)}(h)}})),n.add((function(){return f.removeListeners()}))}u.rules.push(s),o.forEach((function(e){var t=e.property,r=e.value,n=e.important,o=e.sourceValue;if("function"==typeof r){var a=r(d);a instanceof Promise?l(t,a,n,o):t.startsWith("--")?f(t,a,n,o):c.push({property:t,value:a,important:n,sourceValue:o})}else c.push({property:t,value:r,important:n,sourceValue:o})}))}));var V=p();!function e(t,r,n){t.rules.forEach((function(t){t.isGroup?e(t,function(e,t){var r=e.rule;if(r instanceof CSSMediaRule){var n=r.media,o=t.cssRules.length;return t.insertRule("@media "+n.mediaText+" {}",o),t.cssRules[o]}return t}(t,r),n):n(t,r)}))}(x,V,(function(e,t){var r=t.cssRules.length;e.declarations.forEach((function(n){var o=n.asyncKey,a=n.varKey;null!=o&&k.set(o,{rule:e,target:t,index:r}),null!=a&&S.set(a,{rule:e,target:t,index:r})})),T(t,r,e)}))}function T(e,t,r){var n=r.selector+" { "+r.declarations.map((function(e){var t=e.property,r=e.value,n=e.important,o=e.sourceValue;return t+": "+(null==r?o:r)+(n?" !important":"")+";"})).join(" ")+" }";e.insertRule(n,t)}function R(e){if(null==e)return x;if(C.has(e))return C.get(e);var t={rule:e,rules:[],isGroup:!0};return C.set(e,t),R(e.parentRule).rules.push(t),t}},shouldRebuildStyle:function(){return u&&!s}}}function br(e){return(e instanceof HTMLStyleElement||e instanceof SVGStyleElement||e instanceof HTMLLinkElement&&e.rel&&e.rel.toLowerCase().includes("stylesheet")&&!e.disabled)&&!e.classList.contains("darkreader")&&"print"!==e.media.toLowerCase()&&!e.classList.contains("stylus")}function yr(e,t,r){return void 0===t&&(t=[]),void 0===r&&(r=!0),br(e)?t.push(e):(e instanceof Element||b&&e instanceof ShadowRoot||e===document)&&(D(e.querySelectorAll('style, link[rel*="stylesheet" i]:not([disabled])'),(function(e){return yr(e,t,!1)})),r&&z(e,(function(e){return yr(e.shadowRoot,t,!1)}))),t}var wr=new WeakSet,kr=new WeakSet,Sr=!1;document.addEventListener("__darkreader__inlineScriptsAllowed",(function(){Sr=!0}));var _r=0,Er=new Map;function xr(e,t){for(var o=t.update,i=t.loadingStart,u=t.loadingEnd,s=[],c=e;(c=c.nextElementSibling)&&c.matches(".darkreader");)s.push(c);var l=s.find((function(e){return e.matches(".darkreader--cors")&&!kr.has(e)}))||null,h=s.find((function(e){return e.matches(".darkreader--sync")&&!wr.has(e)}))||null,v=null,m=null,g=!1,b=!0,y=gr(),w=new MutationObserver((function(){o()})),k={attributes:!0,childList:!0,subtree:!0,characterData:!0};function S(){return e instanceof HTMLStyleElement&&e.textContent.trim().match(fe)}function _(e){var t=!1;if(e){var r=void 0;e:for(var n=0,o=e.length;n<o;n++)if((r=e[n]).href&&r.href.startsWith("http")&&!r.href.startsWith(location.origin)){t=!0;break e}}return t}function E(){if(l)return l.sheet.cssRules;if(S())return null;var e=L();return _(e)?null:e}function x(){l?(e.nextSibling!==l&&e.parentNode.insertBefore(l,e.nextSibling),l.nextSibling!==h&&e.parentNode.insertBefore(h,l.nextSibling)):e.nextSibling!==h&&e.parentNode.insertBefore(h,e.nextSibling)}var C=!1,V=!1,T=++_r;function R(){return r(this,void 0,void 0,(function(){var t,r,o,i,u,s,c,d;return n(this,(function(n){switch(n.label){case 0:if(!(e instanceof HTMLLinkElement))return[3,7];if(o=a(A(),2),i=o[0],(u=o[1])&&N(u),!(!i&&!u&&!p||p&&!e.sheet||(f=u,f&&f.message&&f.message.includes("loading"))))return[3,5];n.label=1;case 1:return n.trys.push([1,3,,4]),q("Linkelement "+T+" is not loaded yet and thus will be await for",e),[4,Cr(e,T)];case 2:return n.sent(),[3,4];case 3:return N(n.sent()),V=!0,[3,4];case 4:if(g)return[2,null];d=a(A(),2),i=d[0],(u=d[1])&&N(u),n.label=5;case 5:return s=_(i),null==i||s?[4,Vr(e.href)]:[2,i];case 6:return t=n.sent(),r=pe(e.href),g?[2,null]:[3,8];case 7:if(!S())return[2,null];t=e.textContent.trim(),r=pe(location.href),n.label=8;case 8:if(!t)return[3,13];n.label=9;case 9:return n.trys.push([9,11,,12]),[4,Tr(t,r)];case 10:return c=n.sent(),l=function(e,t){if(!t)return null;var r=document.createElement("style");return r.classList.add("darkreader"),r.classList.add("darkreader--cors"),r.media="screen",r.textContent=t,e.parentNode.insertBefore(r,e.nextSibling),r.sheet.disabled=!0,kr.add(r),r}(e,c),[3,12];case 11:return N(n.sent()),[3,12];case 12:if(l)return v=U(l,"prev-sibling"),[2,l.sheet.cssRules];n.label=13;case 13:return[2,null]}var f}))}))}var M=!1;function A(){try{return null==e.sheet?[null,null]:[e.sheet.cssRules,null]}catch(e){return[null,e]}}function L(){var e=a(A(),2),t=e[0],r=e[1];return r?(N(r),null):t}function P(){e.addEventListener("__darkreader__updateSheet",W),f||Sr&&e.sheet||function(){O=D(),F();var t=function(){D()!==O&&(O=D(),o()),Sr&&e.sheet?F():j=requestAnimationFrame(t)};t()}()}var O=null,j=null;function D(){var e=L();return e?e.length:null}function F(){cancelAnimationFrame(j)}var B=!1;function W(){function e(){B=!1,g||o()}Sr=!0,F(),B||(B=!0,"function"==typeof queueMicrotask?queueMicrotask(e):requestAnimationFrame(e))}function z(){e.removeEventListener("__darkreader__updateSheet",W),F()}function $(){w.disconnect(),g=!0,v&&v.stop(),m&&m.stop(),z()}var H=0;return{details:function(){var e=E();return e?{rules:e}:(C||V||(C=!0,i(),R().then((function(e){C=!1,u(),e&&o()})).catch((function(e){N(e),C=!1,u()}))),null)},render:function(t,r){var n=E();function a(){h||((h=e instanceof SVGStyleElement?document.createElementNS("http://www.w3.org/2000/svg","style"):document.createElement("style")).classList.add("darkreader"),h.classList.add("darkreader--sync"),h.media="screen",!d&&e.title&&(h.title=e.title),wr.add(h)),m&&m.stop(),x(),null==h.sheet&&(h.textContent="");for(var t=h.sheet,r=t.cssRules.length-1;r>=0;r--)t.deleteRule(r);return m?m.run():m=U(h,"prev-sibling",(function(){M=!0,i()})),h.sheet}function i(){var e=M;M=!1,y.modifySheet({prepareSheet:a,sourceCSSRules:n,theme:t,ignoreImageAnalysis:r,force:e,isAsyncCancelled:function(){return g}}),b=0===h.sheet.cssRules.length,y.shouldRebuildStyle()&&X((function(){return o()}))}n&&(g=!1,i())},pause:$,destroy:function(){if($(),I(l),I(h),u(),Er.has(T)){var e=Er.get(T);Er.delete(T),e&&e()}},watch:function(){w.observe(e,k),e instanceof HTMLStyleElement&&P()},restore:function(){h&&(++H>10?N("Style sheet was moved multiple times",e):(N("Restore style",h,e),x(),v&&v.skip(),m&&m.skip(),b||(M=!0,o())))}}}function Cr(e,t){return r(this,void 0,void 0,(function(){return n(this,(function(r){return[2,new Promise((function(r,n){var o=function(){e.removeEventListener("load",a),e.removeEventListener("error",i),Er.delete(t)},a=function(){o(),q("Linkelement "+t+" has been loaded"),r()},i=function(){o(),n("Linkelement "+t+" couldn't be loaded. "+e.href)};Er.set(t,(function(){o(),n()})),e.addEventListener("load",a),e.addEventListener("error",i),e.href||i()}))]}))}))}function Vr(e){return r(this,void 0,void 0,(function(){return n(this,(function(t){switch(t.label){case 0:return e.startsWith("data:")?[4,fetch(e)]:[3,3];case 1:return[4,t.sent().text()];case 2:return[2,t.sent()];case 3:return[4,ct({url:e,responseType:"text",mimeType:"text/css",origin:window.location.origin})];case 4:return[2,t.sent()]}}))}))}function Tr(e,t,a){return void 0===a&&(a=new Map),r(this,void 0,void 0,(function(){var r,i,u,s,c,l,d,f,h,p;return n(this,(function(n){switch(n.label){case 0:e=function(e,t){return e.replace(de,(function(e){var r=he(e);return'url("'+ie(t,r)+'")'}))}(e=function(e){return e.replace(me,"")}(e=e.replace(ve,"")),t),r=je(fe,e),n.label=1;case 1:n.trys.push([1,10,11,12]),i=o(r),u=i.next(),n.label=2;case 2:return u.done?[3,9]:(s=u.value,c=he(s.substring(7).trim().replace(/;$/,"")),l=ie(t,c),d=void 0,a.has(l)?(d=a.get(l),[3,7]):[3,3]);case 3:return n.trys.push([3,6,,7]),[4,Vr(l)];case 4:return d=n.sent(),a.set(l,d),[4,Tr(d,pe(l),a)];case 5:return d=n.sent(),[3,7];case 6:return N(n.sent()),d="",[3,7];case 7:e=e.split(s).join(d),n.label=8;case 8:return u=i.next(),[3,2];case 9:return[3,12];case 10:return f=n.sent(),h={error:f},[3,12];case 11:try{u&&!u.done&&(p=i.return)&&p.call(i)}finally{if(h)throw h.error}return[7];case 12:return[2,e=e.trim()]}}))}))}var Rr,Mr,Ar=[],Lr=new Map;function Pr(e){w&&D(e.querySelectorAll(":not(:defined)"),(function(e){var t=e.tagName.toLowerCase();if(!t.includes("-")){var o=e.getAttribute("is");if(!o)return;t=o}Lr.has(t)||(Lr.set(t,new Set),function(e){return r(this,void 0,void 0,(function(){return n(this,(function(t){return[2,new Promise((function(t){if(window.customElements&&"function"==typeof customElements.whenDefined)customElements.whenDefined(e).then(t);else if(Or)jr.set(e,t),document.dispatchEvent(new CustomEvent("__darkreader__addUndefinedResolver",{detail:{tag:e}}));else{var r=function(){var n=Lr.get(e);n&&n.size>0&&(n.values().next().value.matches(":defined")?t():requestAnimationFrame(r))};requestAnimationFrame(r)}}))]}))}))}(t).then((function(){if(Mr){var e=Lr.get(t);Lr.delete(t),Mr(Array.from(e))}}))),Lr.get(t).add(e)}))}var Or=!1;document.addEventListener("__darkreader__inlineScriptsAllowed",(function(){Or=!0}));var jr=new Map;function Dr(e){(Or=!0,jr.has(e.detail.tag))&&jr.get(e.detail.tag)()}function Fr(e,t,r){qr();var n=new Set(e),o=new WeakMap,a=new WeakMap;function i(e){o.set(e,e.previousElementSibling),a.set(e,e.nextElementSibling)}function u(e){var r=e.createdStyles,u=e.removedStyles,s=e.movedStyles;r.forEach((function(e){return i(e)})),s.forEach((function(e){return i(e)})),u.forEach((function(e){return t=e,o.delete(t),void a.delete(t);var t})),r.forEach((function(e){return n.add(e)})),u.forEach((function(e){return n.delete(e)})),r.size+u.size+s.size>0&&t({created:Array.from(r),removed:Array.from(u),moved:Array.from(s),updated:[]})}function s(e){var t=e.additions,r=e.moves,n=e.deletions,o=new Set,a=new Set,i=new Set;t.forEach((function(e){return yr(e).forEach((function(e){return o.add(e)}))})),n.forEach((function(e){return yr(e).forEach((function(e){return a.add(e)}))})),r.forEach((function(e){return yr(e).forEach((function(e){return i.add(e)}))})),u({createdStyles:o,removedStyles:a,movedStyles:i}),t.forEach((function(e){z(e,f),Pr(e)}))}function c(e){var t=new Set(yr(e)),r=new Set,i=new Set,s=new Set;t.forEach((function(e){n.has(e)||r.add(e)})),n.forEach((function(e){t.has(e)||i.add(e)})),t.forEach((function(e){var t;r.has(e)||i.has(e)||(t=e).previousElementSibling===o.get(t)&&t.nextElementSibling===a.get(t)||s.add(e)})),u({createdStyles:r,removedStyles:i,movedStyles:s}),z(e,f),Pr(e)}function l(e){var r=new Set,n=new Set;e.forEach((function(e){var t=e.target;t.isConnected&&(br(t)?r.add(t):t instanceof HTMLLinkElement&&t.disabled&&n.add(t))})),r.size+n.size>0&&t({updated:Array.from(r),created:[],removed:Array.from(n),moved:[]})}function d(e){var t=re(e,{onMinorMutations:s,onHugeMutations:c}),r=new MutationObserver(l);r.observe(e,{attributes:!0,attributeFilter:["rel","disabled","media"],subtree:!0}),Ar.push(t,r),Rr.add(e)}function f(e){var t=e.shadowRoot;null==t||Rr.has(t)||(d(t),r(t))}e.forEach(i),d(document),z(document.documentElement,f),Mr=function(e){var r=[];e.forEach((function(e){return F(r,yr(e.shadowRoot))})),t({created:r,updated:[],removed:[],moved:[]}),e.forEach((function(e){var t=e.shadowRoot;null!=t&&(f(e),z(t,f),Pr(t))}))},document.addEventListener("__darkreader__isDefined",Dr),Pr(document)}function qr(){Ar.forEach((function(e){return e.disconnect()})),Ar.splice(0,Ar.length),Rr=new WeakSet,Mr=null,Lr.clear(),document.removeEventListener("__darkreader__isDefined",Dr)}var Nr=new WeakMap,Br=new WeakSet;function Wr(e){var t=!1;return{render:function(r,n){e.adoptedStyleSheets.forEach((function(o){if(!Br.has(o)){var u=o.rules,s=new CSSStyleSheet;gr().modifySheet({prepareSheet:function(){for(var t=s.cssRules.length-1;t>=0;t--)s.deleteRule(t);return function(t,r){var n=i([],a(e.adoptedStyleSheets)),o=n.indexOf(t),u=n.indexOf(r);o!==u-1&&(u>=0&&n.splice(u,1),n.splice(o+1,0,r),e.adoptedStyleSheets=n)}(o,s),Nr.set(o,s),Br.add(s),s},sourceCSSRules:u,theme:r,ignoreImageAnalysis:n,force:!1,isAsyncCancelled:function(){return t}})}}))},destroy:function(){t=!0;var r=i([],a(e.adoptedStyleSheets));e.adoptedStyleSheets.forEach((function(e){if(Br.has(e)){var t=r.indexOf(e);t>=0&&r.splice(t,1),Nr.delete(e),Br.delete(e)}})),e.adoptedStyleSheets=r}}}function Ir(){document.dispatchEvent(new CustomEvent("__darkreader__inlineScriptsAllowed"));var e=Object.getOwnPropertyDescriptor(CSSStyleSheet.prototype,"addRule"),t=Object.getOwnPropertyDescriptor(CSSStyleSheet.prototype,"insertRule"),r=Object.getOwnPropertyDescriptor(CSSStyleSheet.prototype,"deleteRule"),n=Object.getOwnPropertyDescriptor(CSSStyleSheet.prototype,"removeRule"),o=Object.getOwnPropertyDescriptor(Document.prototype,"styleSheets"),u=location.hostname.endsWith("baidu.com"),s=u?Object.getOwnPropertyDescriptor(Element.prototype,"getElementsByTagName"):null,c=function(){Object.defineProperty(CSSStyleSheet.prototype,"addRule",e),Object.defineProperty(CSSStyleSheet.prototype,"insertRule",t),Object.defineProperty(CSSStyleSheet.prototype,"deleteRule",r),Object.defineProperty(CSSStyleSheet.prototype,"removeRule",n),document.removeEventListener("__darkreader__cleanUp",c),document.removeEventListener("__darkreader__addUndefinedResolver",l),Object.defineProperty(Document.prototype,"styleSheets",o),u&&Object.defineProperty(Element.prototype,"getElementsByTagName",s)},l=function(e){customElements.whenDefined(e.detail.tag).then((function(){document.dispatchEvent(new CustomEvent("__darkreader__isDefined",{detail:{tag:e.detail.tag}}))}))};document.addEventListener("__darkreader__cleanUp",c),document.addEventListener("__darkreader__addUndefinedResolver",l);var d=new Event("__darkreader__updateSheet");Object.defineProperty(CSSStyleSheet.prototype,"addRule",Object.assign({},e,{value:function(t,r,n){return e.value.call(this,t,r,n),this.ownerNode&&!this.ownerNode.classList.contains("darkreader")&&this.ownerNode.dispatchEvent(d),-1}})),Object.defineProperty(CSSStyleSheet.prototype,"insertRule",Object.assign({},t,{value:function(e,r){var n=t.value.call(this,e,r);return this.ownerNode&&!this.ownerNode.classList.contains("darkreader")&&this.ownerNode.dispatchEvent(d),n}})),Object.defineProperty(CSSStyleSheet.prototype,"deleteRule",Object.assign({},r,{value:function(e){r.value.call(this,e),this.ownerNode&&!this.ownerNode.classList.contains("darkreader")&&this.ownerNode.dispatchEvent(d)}})),Object.defineProperty(CSSStyleSheet.prototype,"removeRule",Object.assign({},n,{value:function(e){n.value.call(this,e),this.ownerNode&&!this.ownerNode.classList.contains("darkreader")&&this.ownerNode.dispatchEvent(d)}})),Object.defineProperty(Document.prototype,"styleSheets",Object.assign({},o,{get:function(){var e=i([],a(o.get.call(this))).filter((function(e){return!e.ownerNode.classList.contains("darkreader")}));return Object.setPrototypeOf(e,StyleSheetList.prototype)}})),u&&Object.defineProperty(Element.prototype,"getElementsByTagName",Object.assign({},s,{value:function(e){var t=this,r=function(){var r=s.value.call(t,e);return"style"===e&&(r=Object.setPrototypeOf(i([],a(r)).filter((function(e){return!e.classList.contains("darkreader")})),NodeList.prototype)),r},n=r();return new Proxy(n,{get:function(e,t){return r()[t]}})}}))}var Ur=function(){if("randomUUID"in crypto){var e=crypto.randomUUID();return e.substring(0,8)+e.substring(9,13)+e.substring(14,18)+e.substring(19,23)+e.substring(24)}return Array.from(crypto.getRandomValues(new Uint8Array(16))).map((function(e){return((t=e)<16?"0":"")+t.toString(16);var t})).join("")}(),zr=new Map,$r=[],Hr=null,Gr=null,Qr=null,Kr=null,Jr=null;function Xr(e,t){void 0===t&&(t=document.head||document);var r=t.querySelector("."+e);return r||((r=document.createElement("style")).classList.add("darkreader"),r.classList.add(e),r.media="screen",r.textContent=""),r}var Yr=new Map;function Zr(e,t){Yr.has(t)&&Yr.get(t).stop(),Yr.set(t,U(e,"parent"))}function en(){var e=Xr("darkreader--fallback",document);e.textContent=Et(Hr,{strict:!0}),document.head.insertBefore(e,document.head.firstChild),Zr(e,"fallback");var r=Xr("darkreader--user-agent");r.textContent=St(Hr,Qr,Hr.styleSystemControls),document.head.insertBefore(r,e.nextSibling),Zr(r,"user-agent");var n,o,a=Xr("darkreader--text");Hr.useFont||Hr.textStroke>0?a.textContent=(n=Hr,(o=[]).push('*:not(pre, pre *, code, .far, .fa, .glyphicon, [class*="vjs-"], .fab, .fa-github, .fas, .material-icons, .icofont, .typcn, mu, [class*="mu-"], .glyphicon, .icon) {'),n.useFont&&n.fontFamily&&o.push(" font-family: "+n.fontFamily+" !important;"),n.textStroke>0&&(o.push(" -webkit-text-stroke: "+n.textStroke+"px !important;"),o.push(" text-stroke: "+n.textStroke+"px !important;")),o.push("}"),o.join("\n")):a.textContent="",document.head.insertBefore(a,e.nextSibling),Zr(a,"text");var i=Xr("darkreader--invert");Gr&&Array.isArray(Gr.invert)&&Gr.invert.length>0?i.textContent=[Gr.invert.join(", ")+" {"," filter: "+at(t(t({},Hr),{contrast:0===Hr.mode?Hr.contrast:Pe(Hr.contrast-10,0,100)}))+" !important;","}"].join("\n"):i.textContent="",document.head.insertBefore(i,a.nextSibling),Zr(i,"invert");var u=Xr("darkreader--inline");u.textContent=rr(),document.head.insertBefore(u,i.nextSibling),Zr(u,"inline");var s=Xr("darkreader--override");s.textContent=Gr&&Gr.css?nn(Gr.css):"",document.head.appendChild(s),Zr(s,"override");var c=Xr("darkreader--variables"),l=_t(Hr),d=Hr.darkSchemeBackgroundColor,f=Hr.darkSchemeTextColor,h=Hr.lightSchemeBackgroundColor,p=Hr.lightSchemeTextColor,v=Hr.mode,m=0===v?h:d,g=0===v?p:f;m=Je(Ee(m),Hr),g=tt(Ee(g),Hr),c.textContent=[":root {"," --darkreader-neutral-background: "+m+";"," --darkreader-neutral-text: "+g+";"," --darkreader-selection-background: "+l.backgroundColorSelection+";"," --darkreader-selection-text: "+l.foregroundColorSelection+";","}"].join("\n"),document.head.insertBefore(c,u.nextSibling),Zr(c,"variables");var b=Xr("darkreader--root-vars");document.head.insertBefore(b,c.nextSibling);var y=function(e,t){void 0===t&&(t=document.head||document);var r=t.querySelector("."+e);return r||((r=document.createElement("script")).classList.add("darkreader"),r.classList.add(e)),r}("darkreader--proxy");y.append("("+Ir+")()"),document.head.insertBefore(y,b.nextSibling),y.remove()}var tn=new Set;function rn(e){var r=Xr("darkreader--inline",e);r.textContent=rr(),e.insertBefore(r,e.firstChild);var n=Xr("darkreader--override",e);n.textContent=Gr&&Gr.css?nn(Gr.css):"",e.insertBefore(n,r.nextSibling);var o=Xr("darkreader--invert",e);Gr&&Array.isArray(Gr.invert)&&Gr.invert.length>0?o.textContent=[Gr.invert.join(", ")+" {"," filter: "+at(t(t({},Hr),{contrast:0===Hr.mode?Hr.contrast:Pe(Hr.contrast-10,0,100)}))+" !important;","}"].join("\n"):o.textContent="",e.insertBefore(o,n.nextSibling),tn.add(e)}function nn(e){return e.replace(/\${(.+?)}/g,(function(e,t){var r=Tt(t);return r?$e(r,Hr,He):(N("Couldn't parse CSSTemplate's color."),t)}))}function on(){var e=document.querySelector(".darkreader--fallback");e&&(e.textContent="")}var an=0,un=new Set;function sn(e){var t=++an;q("New manager for element, with loadingStyleID "+t,e);var r=xr(e,{update:function(){var e=r.details();e&&(jt.addRulesForMatching(e.rules),jt.matchVariablesAndDependants(),r.render(Hr,Kr))},loadingStart:function(){if(!$()||!pn){un.add(t),q("Current amount of styles loading: "+un.size);var e=document.querySelector(".darkreader--fallback");e.textContent||(e.textContent=Et(Hr,{strict:!1}))}},loadingEnd:function(){un.delete(t),q("Removed loadingStyle "+t+", now awaiting: "+un.size),q("To-do to be loaded",un),0===un.size&&$()&&on()}});return zr.set(e,r),r}function cn(e){var t=zr.get(e);t&&(t.destroy(),zr.delete(e))}var ln=B((function(e){zr.forEach((function(e){return e.render(Hr,Kr)})),$r.forEach((function(e){return e.render(Hr,Kr)})),e&&e()})),dn=function(){ln.cancel()};function fn(){0!==un.size?N("DOM is ready, but still have styles being loaded.",un):on()}var hn=null,pn=!document.hidden;function vn(){document.removeEventListener("visibilitychange",hn),hn=null}function mn(){function e(){var e,t;!function(){dn();var e=yr(document).filter((function(e){return!zr.has(e)})).map((function(e){return sn(e)}));e.map((function(e){return e.details()})).filter((function(e){return e&&e.rules.length>0})).forEach((function(e){jt.addRulesForMatching(e.rules)})),jt.matchVariablesAndDependants(),jt.setOnRootVariableChange((function(){jt.putRootVars(document.head.querySelector(".darkreader--root-vars"),Hr)})),jt.putRootVars(document.head.querySelector(".darkreader--root-vars"),Hr),zr.forEach((function(e){return e.render(Hr,Kr)})),0===un.size&&on(),e.forEach((function(e){return e.watch()}));var t=function(e){for(var t=[],r=0,n=e.length;r<n;r++)t.push(e[r]);return t}(document.querySelectorAll(tr));z(document.documentElement,(function(e){rn(e.shadowRoot);var r=e.shadowRoot.querySelectorAll(tr);r.length>0&&F(t,r)})),t.forEach((function(e){return cr(e,Hr,Jr,Kr)})),gn(document)}(),Fr(Array.from(zr.keys()),(function(e){var t=e.created,r=e.updated,n=e.removed,o=e.moved,a=n,i=t.concat(r).concat(o).filter((function(e){return!zr.has(e)})),u=o.filter((function(e){return zr.has(e)}));q("Styles to be removed:",a),a.forEach((function(e){return cn(e)}));var s=i.map((function(e){return sn(e)}));s.map((function(e){return e.details()})).filter((function(e){return e&&e.rules.length>0})).forEach((function(e){jt.addRulesForMatching(e.rules)})),jt.matchVariablesAndDependants(),s.forEach((function(e){return e.render(Hr,Kr)})),s.forEach((function(e){return e.watch()})),u.forEach((function(e){return zr.get(e).restore()}))}),(function(e){rn(e),gn(e)})),e=function(e){cr(e,Hr,Jr,Kr),e===document.documentElement&&e.getAttribute("style").includes("--")&&(jt.matchVariablesAndDependants(),jt.putRootVars(document.head.querySelector(".darkreader--root-vars"),Hr))},t=function(e){rn(e);var t=e.querySelectorAll(tr);t.length>0&&D(t,(function(e){return cr(e,Hr,Jr,Kr)}))},ar(document,e,t),z(document.documentElement,(function(r){ar(r.shadowRoot,e,t)})),G(fn)}var t,r,n,o;en(),document.hidden?(t=e,r=Boolean(hn),hn=function(){document.hidden||(vn(),t(),pn=!0)},r||document.addEventListener("visibilitychange",hn)):e(),n=Hr,(o=document.querySelector(dr))?pr(o,n):(hr&&hr.disconnect(),(hr=new MutationObserver((function(e){e:for(var t=0;t<e.length;t++)for(var r=e[t].addedNodes,o=0;o<r.length;o++){var a=r[o];if(a instanceof HTMLMetaElement&&a.name===lr){hr.disconnect(),hr=null,pr(a,n);break e}}}))).observe(document.head,{childList:!0}))}function gn(e){if(Array.isArray(e.adoptedStyleSheets)&&e.adoptedStyleSheets.length>0){var t=Wr(e);$r.push(t),t.render(Hr,Kr)}}function bn(){zr.forEach((function(e){return e.pause()})),D(Yr.values(),(function(e){return e.stop()})),Yr.clear(),qr(),nr.forEach((function(e){return e.disconnect()})),or.forEach((function(e){return e.disconnect()})),nr.clear(),or.clear(),Q(fn),J.clear()}function yn(){var e,t=document.querySelector('meta[name="darkreader"]');return t?t.content!==Ur:((e=document.createElement("meta")).name="darkreader",e.content=Ur,document.head.appendChild(e),!1)}function wn(e,t,r){if(Hr=e,(Gr=t)?(Kr=Array.isArray(Gr.ignoreImageAnalysis)?Gr.ignoreImageAnalysis:[],Jr=Array.isArray(Gr.ignoreInlineStyle)?Gr.ignoreInlineStyle:[]):(Kr=[],Jr=[]),Qr=r,document.head){if(yn())return;document.documentElement.setAttribute("data-darkreader-mode","dynamic"),document.documentElement.setAttribute("data-darkreader-scheme",Hr.mode?"dark":"dimmed"),mn()}else{if(!h){var n=Xr("darkreader--fallback");document.documentElement.appendChild(n),n.textContent=Et(Hr,{strict:!0})}var o=new MutationObserver((function(){if(document.head){if(o.disconnect(),yn())return void kn();mn()}}));o.observe(document,{childList:!0,subtree:!0})}}function kn(){document.documentElement.removeAttribute("data-darkreader-mode"),document.documentElement.removeAttribute("data-darkreader-scheme"),jt.clear(),ne.clear(),vn(),dn(),bn(),Ot(),I(document.querySelector(".darkreader--fallback")),document.head&&(!function(){hr&&(hr.disconnect(),hr=null);var e=document.querySelector(dr);e&&fr&&(e.content=fr)}(),I(document.head.querySelector(".darkreader--user-agent")),I(document.head.querySelector(".darkreader--text")),I(document.head.querySelector(".darkreader--invert")),I(document.head.querySelector(".darkreader--inline")),I(document.head.querySelector(".darkreader--override")),I(document.head.querySelector(".darkreader--variables")),I(document.head.querySelector(".darkreader--root-vars")),I(document.head.querySelector('meta[name="darkreader"]')),document.dispatchEvent(new CustomEvent("__darkreader__cleanUp")),I(document.head.querySelector(".darkreader--proxy"))),tn.forEach((function(e){I(e.querySelector(".darkreader--inline")),I(e.querySelector(".darkreader--override"))})),tn.clear(),D(zr.keys(),(function(e){return cn(e)})),un.clear(),Er.clear(),D(document.querySelectorAll(".darkreader"),I),$r.forEach((function(e){e.destroy()})),$r.splice(0)}var Sn=/url\(\"(blob\:.*?)\"\)/g;function _n(e){return r(this,void 0,void 0,(function(){var t,r;return n(this,(function(n){switch(n.label){case 0:return t=[],je(Sn,e,1).forEach((function(e){var r=S(e);t.push(r)})),[4,Promise.all(t)];case 1:return r=n.sent(),[2,e.replace(Sn,(function(){return'url("'+r.shift()+'")'}))]}}))}))}function En(){return r(this,void 0,void 0,(function(){function e(e,r){var n=document.querySelector(e);n&&n.textContent&&(t.push("/* "+r+" */"),t.push(n.textContent),t.push(""))}var t,r,o,a,i;return n(this,(function(n){switch(n.label){case 0:return t=['/*\n _______\n / \\\n .==. .==.\n (( ))==(( ))\n / "==" "=="\\\n /____|| || ||___\\\n ________ ____ ________ ___ ___\n | ___ \\ / \\ | ___ \\ | | / /\n | | \\ \\ / /\\ \\ | | \\ \\| |_/ /\n | | ) / /__\\ \\ | |__/ /| ___ \\\n | |__/ / ______ \\| ____ \\| | \\ \\\n_______|_______/__/ ____ \\__\\__|___\\__\\__|___\\__\\____\n| ___ \\ | ____/ / \\ | ___ \\ | ____| ___ \\\n| | \\ \\| |___ / /\\ \\ | | \\ \\| |___| | \\ \\\n| |__/ /| ____/ /__\\ \\ | | ) | ____| |__/ /\n| ____ \\| |__/ ______ \\| |__/ /| |___| ____ \\\n|__| \\__\\____/__/ \\__\\_______/ |______|__| \\__\\\n https://darkreader.org\n*/\n\n/*! Dark reader generated CSS | Licensed under MIT https://github.com/darkreader/darkreader/blob/master/LICENSE */\n'],e(".darkreader--fallback","Fallback Style"),e(".darkreader--user-agent","User-Agent Style"),e(".darkreader--text","Text Style"),e(".darkreader--invert","Invert Style"),e(".darkreader--variables","Variables Style"),r=[],document.querySelectorAll(".darkreader--sync").forEach((function(e){D(e.sheet.cssRules,(function(e){e&&e.cssText&&r.push(e.cssText)}))})),r.length?(o=function(e){function t(e){return e.replace(/^\s+/,"")}function r(e){return 0===e?"":" ".repeat(4*e)}if(e.length<5e4)for(var n=/[^{}]+{\s*}/;n.test(e);)e=e.replace(n,"");for(var o=e.replace(/\s{2,}/g," ").replace(/\{/g,"{\n").replace(/\}/g,"\n}\n").replace(/\;(?![^\(|\"]*(\)|\"))/g,";\n").replace(/\,(?![^\(|\"]*(\)|\"))/g,",\n").replace(/\n\s*\n/g,"\n").split("\n"),a=0,i=[],u=0,s=o.length;u<s;u++){var c=o[u]+"\n";c.includes("{")?i.push(r(a++)+t(c)):c.includes("}")?i.push(r(--a)+t(c)):i.push(r(a)+t(c))}return i.join("").trim()}(r.join("\n")),t.push("/* Modified CSS */"),i=(a=t).push,[4,_n(o)]):[3,2];case 1:i.apply(a,[n.sent()]),t.push(""),n.label=2;case 2:return e(".darkreader--override","Override Style"),[2,t.join("\n")]}}))}))}var xn=!1,Cn=function(){try{return window.self!==window.top}catch(e){return console.warn(e),!0}}();function Vn(e,r){void 0===e&&(e={}),void 0===r&&(r=null);var n=t(t({},j),e);if(n.engine!==L)throw new Error("Theme engine is not supported.");wn(n,r,Cn),xn=!0}function Tn(){kn(),xn=!1}var Rn=matchMedia("(prefers-color-scheme: dark)"),Mn={themeOptions:null,fixes:null};function An(){Rn.matches?Vn(Mn.themeOptions,Mn.fixes):Tn()}var Ln=function(e){x=e||E};e.auto=function(e,t){void 0===e&&(e={}),void 0===t&&(t=null),e?(Mn={themeOptions:e,fixes:t},An(),y?Rn.addEventListener("change",An):Rn.addListener(An)):(y?Rn.removeEventListener("change",An):Rn.removeListener(An),Tn())},e.disable=Tn,e.enable=Vn,e.exportGeneratedCSS=function(){return r(this,void 0,void 0,(function(){return n(this,(function(e){switch(e.label){case 0:return[4,En()];case 1:return[2,e.sent()]}}))}))},e.isEnabled=function(){return xn},e.setFetchMethod=Ln,Object.defineProperty(e,"__esModule",{value:!0})}));
+//# sourceMappingURL=/sm/5be885d11df3ea74a4395d7b62c89b39f3ea920787b81a23ef27e58e905733ef.map
+DarkReader.enable({brightness:100,contrast:100,sepia:0});