Compare commits

..

No commits in common. "258aa8dd3c884b96430a60b0a653c22bf0e2ceff" and "a0f79388e98a323471463ee9bbfeed74c525eb33" have entirely different histories.

14 changed files with 70 additions and 640 deletions

View File

@ -10,12 +10,12 @@ Rosenrot is a small browser forked from an earlier version of [rose](https://git
### Installation and usage ### Installation and usage
You can see detailed instructions [here](./user-scripts/debian-12/), for Debian 12 in particular—though they should generalize easily to other distributions. You can see detailed instructions [here](./user-scripts/debian-12/install-with-dependencies.sh), for Debian 12 in particular—though they should generalize easily to other distributions.
The general steps are to install dependencies, and then The general steps are to install dependencies, and then
``` ```
make build # by default using webkitgtk6/gtk4; see also build3 make build
make install # or sudo make install make install # or sudo make install
rose rose
``` ```
@ -44,7 +44,6 @@ You can also create a rose.desktop file so that it will show up in your desktop
- Custom style: Override the css of predetermined websites - Custom style: Override the css of predetermined websites
- Max number of tabs (by default 8), configurable. - Max number of tabs (by default 8), configurable.
- Stand in plugin: Mimick function definitions which do nothing for the above plugins so that they can be quickly removed - Stand in plugin: Mimick function definitions which do nothing for the above plugins so that they can be quickly removed
- For now, both GTK3 and GTK4-based versions—eventually only the GTK4 version will remain
You can see some screenshots in the [images](./images) folder. You can see some screenshots in the [images](./images) folder.
@ -67,14 +66,14 @@ Here are projects with their own rendering engines which could appeal to users o
- [lynx](https://lynx.invisible-island.net/) (links, elinks), [w3m](https://w3m.sourceforge.net/): command line browsers. - [lynx](https://lynx.invisible-island.net/) (links, elinks), [w3m](https://w3m.sourceforge.net/): command line browsers.
- [dillo](https://github.com/dillo-browser/dillo/). Has its own rendering engine, and no javascript. - [dillo](https://github.com/dillo-browser/dillo/). Has its own rendering engine, and no javascript.
- [Ladybird](https://github.com/LadybirdBrowser/ladybird). Initially from the InitialSerenityOS, it later became its own project. Uses its own html and javascript engine. Compiling it on a mainstream linux distribution is now doable. - [Ladybird](https://github.com/SerenityOS/serenity/tree/master/Ladybird). SerenityOS. Uses its own html and javascript engine. Compiling it on a mainstream Linux distribution, and documenting instructions could be an interesting project, but the few times I've tried that I've failed.
- [servo](https://github.com/servo/servo). Firefox/Mozilla. An in-development browser engine written in Rust, meant to replace Gecko. Could be extremely cool once it is ready, but it has been many years in development. - [servo](https://github.com/servo/servo). Firefox/Mozilla. An in-development browser engine written in Rust, meant to replace Gecko. Could be extremely cool once it is ready, but it has been many years in development.
### Relationship with [rose](https://github.com/mini-rose/rose) ### Relationship with [rose](https://github.com/mini-rose/rose)
- Rose is a small browser based on webkit2gtk. Previously, it described itself as aiming to be a "basement for creating your own browser using [the] gtk and webkit libraries". It has since diverged into a more featureful small browser with lua bindings, and rebased its history. You can see the original, minimal version [here](https://github.com/NunoSempere/rosenrot-browser/blob/a45d1c70f58586fed97df70650e5d066b73d0a0d/rose.c). - Rose is a small browser based on webkit2gtk. Previously, it described itself as aiming to be a "basement for creating your own browser using [the] gtk and webkit libraries". It has since diverged into a more featureful small browser with lua bindings, and rebased its history. You can see the original, minimal version [here](https://github.com/NunoSempere/rosenrot-browser/blob/a45d1c70f58586fed97df70650e5d066b73d0a0d/rose.c).
- Rosenrot is my (@NunoSempere's) fork from that earlier minimal rose, the GTK 3 version. It has accumulated quality of life features and, honestly, cruft, that I like, like a "readability" plugin that simplifies annoying websites like [Matt Levine's Money Stuff newsletter](https://www.bloomberg.com/opinion/articles/2022-10-18/matt-levine-s-money-stuff-credit-suisse-was-a-reverse-meme-stock). It also incorporates ad-blocking. - The current version offers compilation with both GTK3 and GTK4, and an up to date version of webkit.
- rose updated to allow compilation with an up-to-date version of both GTK3 and GTK4 earlier, though rosenrot now offers this as well. - Rosenrot is my (@NunoSempere's) fork from that earlier minimal rose. It has accumulated quality of life features and, honestly, cruft, that I like, like a "readability" plugin that simplifies annoying websites like [Matt Levine's Money Stuff newsletter](https://www.bloomberg.com/opinion/articles/2022-10-18/matt-levine-s-money-stuff-credit-suisse-was-a-reverse-meme-stock). It also incorporates ad-blocking.
- Rosenrot is also a song by the German hardcore rock band [Rammstein](https://www.youtube.com/watch?v=af59U2BRRAU). - Rosenrot is also a song by the German hardcore rock band [Rammstein](https://www.youtube.com/watch?v=af59U2BRRAU).
### Comparison with [surf](https://git.suckless.org/surf/file/surf.c.html) ### Comparison with [surf](https://git.suckless.org/surf/file/surf.c.html)
@ -86,8 +85,9 @@ Here are projects with their own rendering engines which could appeal to users o
- Anecdotically, surf feels slower, though I haven't tested this rigorously. - Anecdotically, surf feels slower, though I haven't tested this rigorously.
- surf has a larger community, with patches and modifications. - surf has a larger community, with patches and modifications.
- surf is more opinionated, but also less amateurish. - surf is more opinionated, but also less amateurish.
- Like rosenrot until not so long ago, it [uses](https://git.suckless.org/surf/file/config.mk.html#l15) an obsolete & deprecated version of [webkit](https://blogs.gnome.org/mcatanzaro/2023/03/21/webkitgtk-api-for-gtk-4-is-now-stable/) (2.40, with GTK3) - Like rosenrot until very recently, it [uses](https://git.suckless.org/surf/file/config.mk.html#l15) an obsolete & deprecated version of [webkit](https://blogs.gnome.org/mcatanzaro/2023/03/21/webkitgtk-api-for-gtk-4-is-now-stable/)
- My recommendation would be to use rosenrot, and if you find some feature missing, either look how surf does it and import it to rose, or move to surf. But then again, I've built rosenrot to cater to my own tastes, so I'd say that. - My recommendation would be to use rosenrot, and if you find some feature missing, either look how surf does it and import it to rose, or move to surf.
- But then again, I've built rosenrot to cater to my own tastes, so I'd say that.
## Folk wisdom ## Folk wisdom
@ -109,7 +109,7 @@ See [this blog post](https://blogs.gnome.org/mcatanzaro/2023/03/21/webkitgtk-api
Migration instructions for migration to webkit2gtk-6 and GTK4 can be seen [here](https://github.com/WebKit/WebKit/blob/ed1422596dce5ff012e64a38faf402ac1674fc7e/Source/WebKit/gtk/migrating-to-webkitgtk-6.0.md) and [here](https://docs.gtk.org/gtk4/migrating-3to4.html). Migration instructions for migration to webkit2gtk-6 and GTK4 can be seen [here](https://github.com/WebKit/WebKit/blob/ed1422596dce5ff012e64a38faf402ac1674fc7e/Source/WebKit/gtk/migrating-to-webkitgtk-6.0.md) and [here](https://docs.gtk.org/gtk4/migrating-3to4.html).
Rosenrot currently supports both the stable webkit2gtk-4.1/GTK3 release, and a newer release using webkit2gtk-6.0/GTK4. Eventually the later will become the only version. Readers might want to look through the history to see a bit about the updating process. Rosenrot is currently on the stable webkit2gtk-4.1 release using GTK3, and has removed deprecated webkit apis. It has plans to eventually migrate to webkit2gtk-6.0 eventually but not soon, because the GTK4 rewrite seems onerous.
### Ubuntu 20.04 ### Ubuntu 20.04

24
TODO.md
View File

@ -8,8 +8,13 @@
- [ ] This time, use something other than Whatsapp as an example syslink. - [ ] This time, use something other than Whatsapp as an example syslink.
- [ ] Fix bug about distorted audio. Maybe related to [this pipewire issue](<https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/1547>)? - [ ] Fix bug about distorted audio. Maybe related to [this pipewire issue](<https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/1547>)?
- See whether it even exists at all - See whether it even exists at all
- [ ] Finish cleaning up GTK4 version - [ ] Upgrade to GTK-4 / Webkitgtk 6.0? Will take a fair amount of time, since GTK4 redesigns the application model somewhat.
- [ ] Think about best way of having GTK4 version alongside - Instructions for webkit-6.0 [here](https://github.com/WebKit/WebKit/blob/ed1422596dce5ff012e64a38faf402ac1674fc7e/Source/WebKit/gtk/migrating-to-webkitgtk-6.0.md)
- Instructions for GTK-4 [here](https://docs.gtk.org/gtk4/migrating-3to4.html)
- [ ] Prepare for GTK-3 to GTK-4 transition
- [ ] Understand wtf is going on with signals and events: <https://docs.gtk.org/gtk4/migrating-3to4.html#stop-using-gtkwidget-event-signals>. <https://github.com/mini-rose/rose-browser/blob/288bf060d095c4895946669ae50d14193168b69c/src/window.c#L42>
- [ ] Remove webkit2gtk-4.1 and download webkit2gtk-6.0
- [ ] Attempt to compile
# Previously done # Previously done
@ -53,17 +58,4 @@
- Useful for opening links in new tab when clicking on them and selecting that option - Useful for opening links in new tab when clicking on them and selecting that option
- And for actually opening links with the href new_tab option. - And for actually opening links with the href new_tab option.
- Links: [1](<https://docs.gtk.org/gobject/func.signal_connect.html>), [2](<https://webkitgtk.org/reference/webkit2gtk/2.37.90/signal.AutomationSession.create-web-view.html>), [3](<https://webkitgtk.org/reference/webkit2gtk/2.26.0/WebKitWebView.html#WebKitWebView-create>), [4](<https://stackoverflow.com/questions/40180757/webkit2gtk-get-new-window-link>) - Links: [1](<https://docs.gtk.org/gobject/func.signal_connect.html>), [2](<https://webkitgtk.org/reference/webkit2gtk/2.37.90/signal.AutomationSession.create-web-view.html>), [3](<https://webkitgtk.org/reference/webkit2gtk/2.26.0/WebKitWebView.html#WebKitWebView-create>), [4](<https://stackoverflow.com/questions/40180757/webkit2gtk-get-new-window-link>)
- [x] Upgrade to GTK-4 / Webkitgtk 6.0? Will take a fair amount of time, since GTK4 redesigns the application model somewhat.
- Instructions for webkit-6.0 [here](https://github.com/WebKit/WebKit/blob/ed1422596dce5ff012e64a38faf402ac1674fc7e/Source/WebKit/gtk/migrating-to-webkitgtk-6.0.md)
- Instructions for GTK-4 [here](https://docs.gtk.org/gtk4/migrating-3to4.html)
- [x] Prepare for GTK-3 to GTK-4 transition
- [x] Understand wtf is going on with signals and events: <https://docs.gtk.org/gtk4/migrating-3to4.html#stop-using-gtkwidget-event-signals>. <https://github.com/mini-rose/rose-browser/blob/288bf060d095c4895946669ae50d14193168b69c/src/window.c#L42>
- [x] Stop using direct access to GdkEvent structs
- [ ] ~~Remove webkit2gtk-4.1 and download webkit2gtk-6.0~~ => Actually just use both
- [x] Attempt to compile
- Notes for others:
- Searching github
- Creating a minimal version, e.g., having only one signal going on
- Looking at how https://github.com/mini-rose/rose-browser/ does things
- Printf statements
- GTK ressources: https://docs.gtk.org/gtk4, https://docs.gtk.org/gobject/, https://docs.gtk.org/gdk4/

View File

@ -1,16 +1,14 @@
#include <stdbool.h> #include <stdbool.h>
// #include <gdk/gdk.h> // <gdk/gdkenums.h>, <gdk/gdkkeysyms.h> #include <gdk/gdk.h> // <gdk/gdkenums.h>, <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
// #include "/usr/include/gtk-4.0/gtk/gtk.h"
// Key user config // Key user config
#define WIDTH 1920 // 960 for half-width, 1920 for full width #define WIDTH 1920 // 960 for half-width, 1920 for full width
#define HEIGHT_GTK3 990 // GTK4 and GTK3 interpret this differently. In GTK4, this includes the height of the top bar // #define HEIGHT 1080
#define HEIGHT_GTK4 1080 // GTK4 and GTK3 interpret this differently. In GTK4, this includes the height of the top bar #define HEIGHT 1000
#define BAR_SIZE 960 #define BAR_SIZE 960
// More user config // More user config
#define ZOOM_START_LEVEL 2 #define ZOOM_START_LEVEL 1.6
#define ZOOM_STEPSIZE .1 #define ZOOM_STEPSIZE .1
#define MAX_NUM_TABS 8 // 0/false for unlimited tabs #define MAX_NUM_TABS 8 // 0/false for unlimited tabs
#define SEARCH "https://search.brave.com/search?q=%s" // "https://search.nunosempere.com/search?q=%s", "https://lite.duckduckgo.com/html/?q=%s" #define SEARCH "https://search.brave.com/search?q=%s" // "https://search.nunosempere.com/search?q=%s", "https://lite.duckduckgo.com/html/?q=%s"
@ -41,7 +39,6 @@ You could also look into commit afe93518a for an approach using stand-in code.
"default-charset", "utf-8" "default-charset", "utf-8"
#define DATA_DIR "/home/nuno/.cache/rosenrot" #define DATA_DIR "/home/nuno/.cache/rosenrot"
#define DATA_MANAGER_OPTS "base-cache-directory", DATA_DIR, "base-data-directory", DATA_DIR #define DATA_MANAGER_OPTS "base-cache-directory", DATA_DIR, "base-data-directory", DATA_DIR
#define NETWORK_SESSION_OPTS DATA_DIR, DATA_DIR
// GTK // GTK
#define GTK_SETTINGS_CONFIG_H "gtk-application-prefer-dark-theme", false, "gtk-enable-animations", false #define GTK_SETTINGS_CONFIG_H "gtk-application-prefer-dark-theme", false, "gtk-enable-animations", false
@ -83,6 +80,7 @@ typedef enum {
prettify, prettify,
} func; } func;
static struct { static struct {
unsigned mod; unsigned mod;
unsigned key; unsigned key;
@ -111,7 +109,7 @@ static struct {
{ CTRL, KEY(w), close_tab }, { CTRL, KEY(w), close_tab },
{ CTRL, KEY(l), show_searchbar }, { CTRL, KEY(l), show_searchbar },
{ CTRL, KEY(o), hide_bar }, // previously: KEY(semicolon) { CTRL, KEY(semicolon), hide_bar },
{ CTRL, KEY(f), show_finder }, { CTRL, KEY(f), show_finder },
{ CTRL, KEY(n), finder_next }, { CTRL, KEY(n), finder_next },
{ CTRL, KEY(N), finder_prev }, { CTRL, KEY(N), finder_prev },

View File

@ -3,23 +3,16 @@ CC=gcc # alternatives: tcc, clang, zig cc
WARNINGS=-Wall WARNINGS=-Wall
OPTIMIZED_SOME=-O3 OPTIMIZED_SOME=-O3
OPTIMIZED_MORE=-Ofast -march=native -funit-at-a-time -flto # binary will not be compatible with other computers, but may be much faster OPTIMIZED_MORE=-Ofast -march=native -funit-at-a-time -flto # binary will not be compatible with other computers, but may be much faster
DEBUG=#-g DEBUG= # -g
STD=-std=c99 # maybe consider moving to c11 and using safer string handling STD=-std=c99 # maybe consider moving to c11 and using safer string handling
# Dependencies for WebkitGTK4/GTK3 # Dependencies
SRC_3=rosenrot3.c DEPS='webkit2gtk-4.1'
DEPS_3='webkit2gtk-4.1' INCS=`pkg-config --cflags ${DEPS}`
INCS_3=`pkg-config --cflags ${DEPS_3}` LIBS=`pkg-config --libs ${DEPS}`
LIBS_3=`pkg-config --libs ${DEPS_3}`
# Dependencies for WebkitGTK6/GTK4 # Code
SRC_4=rosenrot4.c SRC=rosenrot.c
DEPS_4='webkitgtk-6.0'
INCS_4=`pkg-config --cflags ${DEPS_4}` `pkg-config --cflags gtk4`
LIBS_4=`pkg-config --libs ${DEPS_4}` `pkg-config --libs gtk4`
DEPRECATION_FLAGS=-DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED
# User config
CONFIG=config.h CONFIG=config.h
# Plugins # Plugins
@ -37,37 +30,10 @@ MAINTAINER_CACHE_DIR=/home/nuno/.cache/rosenrot
USER_CACHE_DIR=/home/`whoami`/.cache/rosenrot USER_CACHE_DIR=/home/`whoami`/.cache/rosenrot
RUNTIME_FILES_DIR=/opt/rosenrot/ RUNTIME_FILES_DIR=/opt/rosenrot/
build3: $(SRC_3) $(PLUGINS) $(CONFIG) constants user_cache build: $(SRC) $(PLUGINS) $(CONFIG) constants user_cache
$(CC) $(STD) $(WARNINGS) $(OPTIMIZED_MORE) $(DEBUG) $(INCS_3) $(PLUGINS) $(SRC_3) -o rosenrot $(LIBS_3) $(ADBLOCK) $(CC) $(STD) $(WARNINGS) $(OPTIMIZED_MORE) $(DEBUG) $(INCS) $(PLUGINS) $(SRC) -o rosenrot $(LIBS) $(ADBLOCK)
@echo @echo
build: $(SRC_4) $(PLUGINS) $(CONFIG) constants user_cache
$(CC) $(STD) $(WARNINGS) $(DEPRECATION_FLAGS) $(OPTIMIZED_MORE) $(DEBUG) $(INCS_4) $(PLUGINS) $(SRC_4) -o rosenrot $(LIBS_4) $(ADBLOCK)
@echo
format: $(SRC_3) $(SRC_4) $(PLUGINS)
$(FORMATTER_C) $(SRC_3) $(PLUGINS) $(config.h)
$(FORMATTER_C) $(SRC_4_greenfield) $(PLUGINS) $(config.h)
$(FORMATTER_JS) plugins/readability/readability.js
$(FORMATTER_JS) plugins/style/style.js
# Installation
install: rosenrot runtime_files
cp -f rosenrot /usr/bin
cp rosenrot-mklink /usr/bin
@echo
uninstall:
rm -r /opt/rosenrot
rm /usr/bin/rosenrot
rm /usr/bin/rosenrot-mklink
rm $(USER_CACHE_DIR)
clean:
rm rosenrot
rm $(USER_CACHE_DIR)
constants: constants:
@echo @echo
@echo "# Computing constants" @echo "# Computing constants"
@ -86,25 +52,43 @@ user_cache:
runtime_files: runtime_files:
@echo @echo
sudo mkdir -p /opt/rosenrot/ sudo mkdir -p /opt/rosenrot/
sudo cp styles-gtk/style-gtk3.css /opt/rosenrot/ sudo cp style.css /opt/rosenrot/
sudo cp styles-gtk/style-gtk4.css /opt/rosenrot/
sudo cp -r images/flower-imgs /opt/rosenrot/ sudo cp -r images/flower-imgs /opt/rosenrot/
sudo cp plugins/style/style.js /opt/rosenrot/ sudo cp plugins/style/style.js /opt/rosenrot/
sudo cp plugins/readability/readability.js /opt/rosenrot/ sudo cp plugins/readability/readability.js /opt/rosenrot/
# More misc recipes install: rosenrot runtime_files
cp -f rosenrot /usr/bin
cp rosenrot-mklink /usr/bin
@echo
uninstall:
rm -r /opt/rosenrot
rm /usr/bin/rosenrot
rm /usr/bin/rosenrot-mklink
rm $(USER_CACHE_DIR)
clean:
rm rosenrot
rm $(USER_CACHE_DIR)
format: $(SRC) $(PLUGINS)
$(FORMATTER_C) $(SRC) $(PLUGINS) $(rosenrot.h)
$(FORMATTER_JS) plugins/readability/readability.js
$(FORMATTER_JS) plugins/style/style.js
lint: lint:
clang-tidy $(SRC) $(PLUGINS) -- -Wall -O3 $(INCS) -o rosenrot $(LIBS) clang-tidy $(SRC) $(PLUGINS) -- -Wall -O3 $(INCS) -o rosenrot $(LIBS)
## A few more commands:
fast: $(SRC) $(PLUGINS) $(CONFIG) fast: $(SRC) $(PLUGINS) $(CONFIG)
rm -f *.gcda rm -f *.gcda
GIO_MODULE_DIR=/usr/lib/x86_64-linux-gnu/gio/modules/ GIO_MODULE_DIR=/usr/lib/x86_64-linux-gnu/gio/modules/
$(CC) $(WARNINGS) $(OPTIMIZED_MORE) -fprofile-generate $(INCS_4) $(PLUGINS) $(SRC_4) -o rosenrot $(LIBS_4) $(ADBLOCK) $(CC) $(WARNINGS) $(OPTIMIZED_MORE) -fprofile-generate $(INCS) $(PLUGINS) $(SRC) -o rosenrot $(LIBS) $(ADBLOCK)
@echo "Now use the browser for a while to gather some profiling data" @echo "Now use the browser for a while to gather some profiling data"
sleep 2 sleep 2
./rosenrot ./rosenrot
$(CC) $(WARNINGS) $(OPTIMIZED_MORE) -fprofile-use $(INCS_4) $(PLUGINS) $(SRC_4) -o rosenrot $(LIBS_4) $(ADBLOCK) $(CC) $(WARNINGS) $(OPTIMIZED_MORE) -fprofile-use $(INCS) $(PLUGINS) $(SRC) -o rosenrot $(LIBS) $(ADBLOCK)
rm -f *.gcda rm -f *.gcda
inspect: rosenrot inspect: rosenrot
@ -119,3 +103,5 @@ view-gtk3-version:
twitter: twitter:
sudo mkdir -p /usr/bin/rosenrot-browser sudo mkdir -p /usr/bin/rosenrot-browser
sudo cp rosenrot /usr/bin/rosenrot-browser/twitter sudo cp rosenrot /usr/bin/rosenrot-browser/twitter
# COMPILETIME_DEPRECATION_WARNINGS=#-DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED # turns out that webkit2gtk-4.1 is using some deprecated stuff, lol

View File

@ -35,7 +35,7 @@ int libre_redirect(const char* uri, char* output)
// previously: "https://old.reddit.com", "https://teddit.nunosempere.com", // previously: "https://old.reddit.com", "https://teddit.nunosempere.com",
// https://github.com/redlib-org/redlib-instances/blob/main/instances.md // https://github.com/redlib-org/redlib-instances/blob/main/instances.md
"https://vitalik.eth.limo", "https://vitalik.eth.limo",
"https://invidious.private.coffee", "https://invidious.nerdvpn.de",
"https://search.nunosempere.com", "https://search.nunosempere.com",
"https://scribe.rip", "https://scribe.rip",
"https://translate.riverside.rocks", "https://translate.riverside.rocks",

View File

@ -1,7 +1,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define STYLE_N 8049 + 1000 #define STYLE_N 7831 + 1000
void read_style_js(char* string) void read_style_js(char* string)
{ {

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#define STYLE_N 8049 + 1000 #define STYLE_N 7831 + 1000
void read_style_js(char* string); void read_style_js(char* string);

View File

@ -1,10 +1,8 @@
// Inspired by the Stylus app: <https://addons.mozilla.org/en-GB/firefox/addon/styl-us/> // Inspired by the Stylus app: <https://addons.mozilla.org/en-GB/firefox/addon/styl-us/>
// NOTE: This file is moved to /opt/rosenrot, so editing it here doesn't have direct effects on the runtime!!
// Main part of the code: switch on the domain and select the corresponding style // Main part of the code: switch on the domain and select the corresponding style
var styles = null; var styles = null;
// console.log(document.domain); console.log(document.domain);
switch (document.domain) { switch (document.domain) {
case "forum.effectivealtruism.org": case "forum.effectivealtruism.org":
styles = ` styles = `
@ -100,7 +98,6 @@ switch (document.domain) {
`; `;
break; break;
case "twitter.com": case "twitter.com":
case "x.com":
styles = ` styles = `
/* hide promoted tweets */ /* hide promoted tweets */
:has(meta[property="og:site_name"][content="Twitter"]) :has(meta[property="og:site_name"][content="Twitter"])
@ -117,7 +114,7 @@ switch (document.domain) {
display: none !important; display: none !important;
} }
[data-testid^="sidebarColumn"] { [data-testid^="sidebarColumn"] {
display: none !important; display: none;
} }
/* Hide DMs v2 */ /* Hide DMs v2 */
@ -184,7 +181,6 @@ switch (document.domain) {
`; `;
break; break;
default: default:
console.log(`Domain: ${document.domain}`);
console.log("No custom style"); console.log("No custom style");
} }

View File

@ -1,9 +1,9 @@
#include <gdk/gdk.h> #include <gdk/gdk.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <webkit2/webkit2.h>
#include "config.h" #include "config.h"
#include <webkit2/webkit2.h>
#include "plugins/plugins.h" #include "plugins/plugins.h"
/* Global declarations */ /* Global declarations */
@ -91,7 +91,6 @@ void handle_signal_load_changed(WebKitWebView* self, WebKitLoadEvent load_event,
redirect_if_annoying(self, webkit_web_view_get_uri(self)); redirect_if_annoying(self, webkit_web_view_get_uri(self));
break; break;
case WEBKIT_LOAD_FINISHED: { case WEBKIT_LOAD_FINISHED: {
set_custom_style(self);
/* Add gtk tab title */ /* Add gtk tab title */
const char* webpage_title = webkit_web_view_get_title(self); const char* webpage_title = webkit_web_view_get_title(self);
const int max_length = 25; const int max_length = 25;
@ -380,7 +379,7 @@ int handle_signal_keypress(void* self, GdkEvent* event, GtkNotebook* notebook)
- https://docs.gtk.org/gdk3/union.Event.html - https://docs.gtk.org/gdk3/union.Event.html
- https://docs.gtk.org/gdk3/struct.EventButton.html - https://docs.gtk.org/gdk3/struct.EventButton.html
*/ */
// This API is deprecated in GTK4 :(. // This API is deprecated in GTK4 :(
return 0; return 0;
} }
@ -390,8 +389,8 @@ int main(int argc, char** argv)
gtk_init(NULL, NULL); // https://docs.gtk.org/gtk3/func.init.html gtk_init(NULL, NULL); // https://docs.gtk.org/gtk3/func.init.html
g_object_set(gtk_settings_get_default(), GTK_SETTINGS_CONFIG_H, NULL); // https://docs.gtk.org/gobject/method.Object.set.html g_object_set(gtk_settings_get_default(), GTK_SETTINGS_CONFIG_H, NULL); // https://docs.gtk.org/gobject/method.Object.set.html
GtkCssProvider* css = gtk_css_provider_new(); GtkCssProvider* css = gtk_css_provider_new();
gtk_css_provider_load_from_path(css, "/opt/rosenrot/style-gtk3.css", NULL); gtk_css_provider_load_from_path(css, "/opt/rosenrot/style.css", NULL);
gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(css), 800); /* might change with GTK4/webkitgtk6.0 */ gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(css), 800);
/* Initialize GTK objects. These are declared as static globals at the top of this file */ /* Initialize GTK objects. These are declared as static globals at the top of this file */
// Notebook // Notebook
@ -401,11 +400,10 @@ int main(int argc, char** argv)
// Window // Window
window = GTK_WINDOW(gtk_window_new(0)); window = GTK_WINDOW(gtk_window_new(0));
gtk_window_set_default_size(window, WIDTH, HEIGHT_GTK3); gtk_window_set_default_size(window, WIDTH, HEIGHT);
g_signal_connect(window, "key-press-event", G_CALLBACK(handle_signal_keypress), notebook); g_signal_connect(window, "key-press-event", G_CALLBACK(handle_signal_keypress), notebook);
g_signal_connect(window, "destroy", G_CALLBACK(exit), notebook); g_signal_connect(window, "destroy", G_CALLBACK(exit), notebook);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(notebook));
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(notebook)); /* deprecated in GTK */
// Bar // Bar
bar.line_text = GTK_ENTRY_BUFFER(gtk_entry_buffer_new("", 0)); bar.line_text = GTK_ENTRY_BUFFER(gtk_entry_buffer_new("", 0));
@ -434,5 +432,5 @@ int main(int argc, char** argv)
} }
} }
gtk_main(); /* deprecated in GKT4: https://docs.gtk.org/gtk4/migrating-3to4.html#stop-using-gtk_main-and-related-apis */ gtk_main();
} }

View File

@ -1,457 +0,0 @@
#include <gdk/gdk.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "plugins/plugins.h"
#include <webkit/webkit.h>
#define NULLCHECK(x) \
do { \
if (x == NULL) { \
printf("\nNULL check not passed"); \
printf("@ %s (%d): ", __FILE__, __LINE__); \
exit(0); \
} \
} while (0)
/* Global variables */
static GtkNotebook* notebook;
static GtkWindow* window;
typedef enum { _SEARCH,
_FIND,
_HIDDEN } Bar_entry_mode;
static struct {
GtkHeaderBar* widget;
GtkEntry* line;
GtkEntryBuffer* line_text;
Bar_entry_mode entry_mode;
} bar;
static int num_tabs = 0;
static int custom_style_enabled = 1;
/* Forward declarations */
void toggle_bar(GtkNotebook* notebook, Bar_entry_mode mode);
void notebook_create_new_tab(GtkNotebook* notebook, const char* uri);
static int handle_signal_keypress(void* self, int keyval, int keycode,
GdkModifierType state, void* controller);
/* Utils */
WebKitWebView* notebook_get_webview(GtkNotebook* notebook) /* TODO: Think through whether to pass global variables or not */
{
WebKitWebView* view = WEBKIT_WEB_VIEW(gtk_notebook_get_nth_page(notebook, gtk_notebook_get_current_page(notebook)));
NULLCHECK(view);
return view;
}
/* Load content */
void load_uri(WebKitWebView* view, const char* uri)
{
bool is_empty_uri = (strlen(uri) == 0);
bool has_direct_uri_prefix = (g_str_has_prefix(uri, "http://") || g_str_has_prefix(uri, "https://") || g_str_has_prefix(uri, "file://") || g_str_has_prefix(uri, "about:"));
bool has_common_domain_extension = (strstr(uri, ".com") || strstr(uri, ".org"));
bool has_shortcut;
int l = SHORTCUT_N + strlen(uri) + 1;
char uri_expanded[l];
str_init(uri_expanded, l);
int check = shortcut_expand(uri, uri_expanded);
has_shortcut = (check == 2);
if (is_empty_uri) {
webkit_web_view_load_uri(view, "");
toggle_bar(notebook, _SEARCH);
} else if (has_direct_uri_prefix){
webkit_web_view_load_uri(view, uri);
} else if (has_common_domain_extension){
char tmp[strlen("https://") + strlen(uri) + 1];
snprintf(tmp, sizeof(tmp) + 1, "https://%s", uri);
webkit_web_view_load_uri(view, tmp);
} else if (has_shortcut){
webkit_web_view_load_uri(view, uri_expanded);
} else {
char tmp[strlen(uri) + strlen(SEARCH)];
snprintf(tmp, sizeof(tmp), SEARCH, uri);
webkit_web_view_load_uri(view, tmp);
}
}
/* Deal with new load or changed load */
void redirect_if_annoying(WebKitWebView* view, const char* uri)
{
if (LIBRE_REDIRECT_ENABLED) {
int l = LIBRE_N + strlen(uri) + 1;
char uri_filtered[l];
str_init(uri_filtered, l);
int check = libre_redirect(uri, uri_filtered);
if (check == 2) webkit_web_view_load_uri(view, uri_filtered);
}
}
void set_custom_style(WebKitWebView* view)
{
if (custom_style_enabled) {
char* style_js = malloc(STYLE_N + 1);
read_style_js(style_js);
// webkit_web_view_evaluate_javascript(view, style_js, -1, NULL, "rosenrot-style-plugin", NULL, NULL, NULL);
free(style_js);
}
}
void handle_signal_load_changed(WebKitWebView* self, WebKitLoadEvent load_event,
GtkNotebook* notebook)
{
switch (load_event) {
// https://webkitgtk.org/reference/webkit2gtk/2.5.1/WebKitWebView.html
case WEBKIT_LOAD_STARTED:
case WEBKIT_LOAD_COMMITTED:
set_custom_style(self);
case WEBKIT_LOAD_REDIRECTED:
redirect_if_annoying(self, webkit_web_view_get_uri(self));
break;
case WEBKIT_LOAD_FINISHED: {
set_custom_style(self);
/* Add gtk tab title */
const char* webpage_title = webkit_web_view_get_title(self);
const int max_length = 25;
char tab_title[max_length + 1];
if (webpage_title != NULL) {
for (int i = 0; i < (max_length); i++) {
tab_title[i] = webpage_title[i];
if (webpage_title[i] == '\0') {
break;
}
}
tab_title[max_length] = '\0';
}
gtk_notebook_set_tab_label_text(notebook, GTK_WIDGET(self),
webpage_title == NULL ? "" : tab_title);
}
}
}
/* New tabs */
WebKitWebView* create_new_webview()
{
WebKitSettings* settings = webkit_settings_new_with_settings(WEBKIT_DEFAULT_SETTINGS, NULL);
if (CUSTOM_USER_AGENT) {
webkit_settings_set_user_agent(
settings,
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, "
"like Gecko) Chrome/120.0.0.0 Safari/537.3");
// https://www.useragents.me
}
WebKitNetworkSession* network_session = webkit_network_session_new(DATA_DIR, DATA_DIR);
WebKitUserContentManager* contentmanager = webkit_user_content_manager_new();
WebKitCookieManager* cookiemanager = webkit_network_session_get_cookie_manager(network_session);
webkit_cookie_manager_set_persistent_storage(cookiemanager, DATA_DIR "/cookies.sqlite", WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
webkit_cookie_manager_set_accept_policy(cookiemanager, WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
WebKitWebView* view = g_object_new(WEBKIT_TYPE_WEB_VIEW, "settings", settings, "network-session", network_session, "user-content-manager", contentmanager, NULL);
NULLCHECK(view);
GtkEventController* event_controller = gtk_event_controller_key_new();
g_signal_connect(event_controller, "key-pressed", G_CALLBACK(handle_signal_keypress), NULL);
gtk_widget_add_controller(GTK_WIDGET(view), event_controller);
return view;
}
GtkWidget* handle_signal_create_new_tab(WebKitWebView* self,
WebKitNavigationAction* navigation_action,
GtkNotebook* notebook)
{
NULLCHECK(self);
NULLCHECK(notebook);
if (num_tabs < MAX_NUM_TABS || num_tabs == 0) {
WebKitURIRequest* uri_request = webkit_navigation_action_get_request(navigation_action);
const char* uri = webkit_uri_request_get_uri(uri_request);
printf("Creating new window: %s\n", uri);
notebook_create_new_tab(notebook, uri);
gtk_notebook_set_show_tabs(notebook, true);
} else {
webkit_web_view_evaluate_javascript(self, "alert('Too many tabs, not opening a new one')", -1, NULL, "rosenrot-alert-numtabs", NULL, NULL, NULL);
}
return GTK_WIDGET(self); // or NULL
}
void notebook_create_new_tab(GtkNotebook* notebook, const char* uri)
{
if (num_tabs < MAX_NUM_TABS || MAX_NUM_TABS == 0) {
WebKitWebView* view = create_new_webview();
NULLCHECK(view);
g_signal_connect(view, "load_changed", G_CALLBACK(handle_signal_load_changed), notebook);
g_signal_connect(view, "create", G_CALLBACK(handle_signal_create_new_tab), notebook);
int n = gtk_notebook_append_page(notebook, GTK_WIDGET(view), NULL);
gtk_notebook_set_tab_reorderable(notebook, GTK_WIDGET(view), true);
NULLCHECK(window);
NULLCHECK(bar.widget);
gtk_widget_set_visible(GTK_WIDGET(window), 1);
gtk_widget_set_visible(GTK_WIDGET(bar.widget), 0);
load_uri(view, (uri) ? uri : HOME);
set_custom_style(view);
gtk_notebook_set_current_page(notebook, n);
gtk_notebook_set_tab_label_text(notebook, GTK_WIDGET(view), "-");
webkit_web_view_set_zoom_level(view, ZOOM_START_LEVEL);
num_tabs += 1;
} else {
webkit_web_view_evaluate_javascript(notebook_get_webview(notebook), "alert('Too many tabs, not opening a new one')",
-1, NULL, "rosenrot-alert-numtabs", NULL, NULL, NULL);
}
}
/* Top bar */
void toggle_bar(GtkNotebook* notebook, Bar_entry_mode mode)
{
bar.entry_mode = mode;
switch (bar.entry_mode) {
case _SEARCH: {
const char* url = webkit_web_view_get_uri(notebook_get_webview(notebook));
gtk_entry_set_placeholder_text(bar.line, "Search");
gtk_entry_buffer_set_text(bar.line_text, url, strlen(url));
gtk_widget_set_visible(GTK_WIDGET(bar.widget), 1);
gtk_window_set_focus(window, GTK_WIDGET(bar.line));
break;
}
case _FIND: {
const char* search_text = webkit_find_controller_get_search_text(
webkit_web_view_get_find_controller(notebook_get_webview(notebook)));
if (search_text != NULL)
gtk_entry_buffer_set_text(bar.line_text, search_text, strlen(search_text));
gtk_entry_set_placeholder_text(bar.line, "Find");
gtk_widget_set_visible(GTK_WIDGET(bar.widget), 1);
gtk_window_set_focus(window, GTK_WIDGET(bar.line));
break;
}
case _HIDDEN:
gtk_widget_set_visible(GTK_WIDGET(bar.widget), 0);
}
}
// Handle what happens when the user is on the bar and presses enter
void handle_signal_bar_press_enter(GtkEntry* self, GtkNotebook* notebook) /* consider passing notebook as the data here? */
{
WebKitWebView* view = notebook_get_webview(notebook);
if (bar.entry_mode == _SEARCH)
load_uri(view, gtk_entry_buffer_get_text(bar.line_text));
else if (bar.entry_mode == _FIND)
webkit_find_controller_search(
webkit_web_view_get_find_controller(view),
gtk_entry_buffer_get_text(bar.line_text),
WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE | WEBKIT_FIND_OPTIONS_WRAP_AROUND,
G_MAXUINT);
gtk_widget_hide(GTK_WIDGET(bar.widget));
}
/* Handle shortcuts */
int handle_shortcut(func id)
{
static double zoom = ZOOM_START_LEVEL;
static bool is_fullscreen = 0;
WebKitWebView* view = notebook_get_webview(notebook);
NULLCHECK(notebook);
NULLCHECK(view);
switch (id) {
case goback:
webkit_web_view_go_back(view);
break;
case goforward:
webkit_web_view_go_forward(view);
break;
case toggle_custom_style: /* Ctrl s + Ctrl Shift R to reload */
if (custom_style_enabled)
custom_style_enabled = 0;
else
custom_style_enabled = 1;
// break; passthrough
case refresh:
webkit_web_view_reload(view);
break;
case refresh_force:
webkit_web_view_reload_bypass_cache(view);
break;
case back_to_home:
load_uri(view, HOME);
break;
case zoomin:
webkit_web_view_set_zoom_level(view,
(zoom += ZOOM_STEPSIZE));
break;
case zoomout:
webkit_web_view_set_zoom_level(view,
(zoom -= ZOOM_STEPSIZE));
break;
case zoom_reset:
webkit_web_view_set_zoom_level(view,
(zoom = ZOOM_START_LEVEL));
break;
case prev_tab:; // declarations aren't statements
// https://stackoverflow.com/questions/92396/why-cant-variables-be-declared-in-a-switch-statement
int n = gtk_notebook_get_n_pages(notebook);
int k = gtk_notebook_get_current_page(notebook);
int l = (n + k - 1) % n;
gtk_notebook_set_current_page(notebook, l);
break;
case next_tab:;
int m = gtk_notebook_get_n_pages(notebook);
int i = gtk_notebook_get_current_page(notebook);
int j = (i + 1) % m;
gtk_notebook_set_current_page(notebook, j);
break;
case close_tab:
gtk_notebook_remove_page(notebook, gtk_notebook_get_current_page(notebook));
num_tabs -= 1;
switch (gtk_notebook_get_n_pages(notebook)) {
case 0:
exit(0);
break;
case 1:
gtk_notebook_set_show_tabs(notebook, false);
break;
}
break;
case toggle_fullscreen:
if (is_fullscreen)
gtk_window_unfullscreen(window);
else
gtk_window_fullscreen(window);
is_fullscreen = !is_fullscreen;
break;
case show_searchbar:
toggle_bar(notebook, _SEARCH);
break;
case show_finder:
toggle_bar(notebook, _FIND);
break;
case finder_next:
webkit_find_controller_search_next(webkit_web_view_get_find_controller(view));
break;
case finder_prev:
webkit_find_controller_search_previous(webkit_web_view_get_find_controller(view));
break;
case new_tab:
notebook_create_new_tab(notebook, NULL);
gtk_notebook_set_show_tabs(notebook, true);
toggle_bar(notebook, _SEARCH);
break;
case hide_bar:
gtk_widget_set_visible(GTK_WIDGET(bar.widget), 0);
toggle_bar(notebook, _HIDDEN);
break;
case prettify: {
if (READABILITY_ENABLED) {
char* readability_js = malloc(READABILITY_N + 1);
read_readability_js(readability_js);
webkit_web_view_evaluate_javascript(view, readability_js, -1, NULL, "rosenrot-readability-plugin", NULL, NULL, NULL);
free(readability_js);
}
break;
}
}
return 1;
}
/* Listen to keypresses */
static int handle_signal_keypress(void* self, int keyval, int keycode,
GdkModifierType state, void* controller)
{
if (0) {
printf("New keypress\n");
printf("Keypress state: %d\n", state);
printf("Keypress value: %d\n", keyval);
}
for (int i = 0; i < sizeof(shortcut) / sizeof(shortcut[0]); i++) {
if ((state & shortcut[i].mod || shortcut[i].mod == 0x0) && keyval == shortcut[i].key) {
printf("New shortcut, with id: %d\n", shortcut[i].id);
return handle_shortcut(shortcut[i].id);
}
}
return 0;
}
int main(int argc, char** argv)
{
/* Initialize GTK in general */
gtk_init();
g_object_set(gtk_settings_get_default(), GTK_SETTINGS_CONFIG_H, NULL); // https://docs.gtk.org/gobject/method.Object.set.html
GtkCssProvider* css = gtk_css_provider_new();
gtk_css_provider_load_from_path(css, "/opt/rosenrot/style-gtk4.css");
gtk_style_context_add_provider_for_display(gdk_display_get_default(), GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_USER);
// Create the main window
window = GTK_WINDOW(gtk_window_new());
gtk_window_set_default_size(window, WIDTH, HEIGHT_GTK4);
// Set up notebook
notebook = GTK_NOTEBOOK(gtk_notebook_new());
gtk_notebook_set_show_tabs(notebook, false);
gtk_notebook_set_show_border(notebook, false);
gtk_window_set_child(window, GTK_WIDGET(notebook));
// Bar
bar.line_text = GTK_ENTRY_BUFFER(gtk_entry_buffer_new("", 0));
bar.line = GTK_ENTRY(gtk_entry_new_with_buffer(bar.line_text));
gtk_entry_set_alignment(bar.line, 0.48);
gtk_widget_set_size_request(GTK_WIDGET(bar.line), BAR_SIZE, -1);
bar.widget = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_header_bar_set_title_widget(bar.widget, GTK_WIDGET(bar.line));
gtk_window_set_titlebar(window, GTK_WIDGET(bar.widget));
// Signals
GtkEventController* event_controller = gtk_event_controller_key_new();
g_signal_connect(event_controller, "key-pressed", G_CALLBACK(handle_signal_keypress), NULL);
gtk_widget_add_controller(GTK_WIDGET(window), event_controller);
g_signal_connect(bar.line, "activate", G_CALLBACK(handle_signal_bar_press_enter), notebook);
g_signal_connect(GTK_WIDGET(window), "destroy", G_CALLBACK(exit), notebook);
// Show the application window
gtk_window_present(window);
char* first_uri = argc > 1 ? argv[1] : HOME;
notebook_create_new_tab(notebook, first_uri);
/* Show to user */
gtk_widget_set_visible(GTK_WIDGET(window), 1);
if (argc != 0) gtk_widget_set_visible(GTK_WIDGET(bar.widget), 0);
/* Deal with more tabs */
if (argc > 2) {
gtk_notebook_set_show_tabs(notebook, true);
for (int i = 2; i < argc; i++) {
notebook_create_new_tab(notebook, argv[i]);
}
}
// Enter the main event loop, and wait for user interaction
printf("Entering main loop\n");
while (g_list_model_get_n_items(gtk_window_get_toplevels()) > 0 && num_tabs > 0)
g_main_context_iteration(NULL, TRUE);
return 0;
}

View File

@ -1,41 +0,0 @@
* {
font-size: 25px;
color: #333;
}
/* Make titlebar pretty gigantic. I'm pretty myopic. */
.titlebar {
padding: 5px;
font-size: 30px;
}
.titlebar * {
padding: 5px;
font-size: 27px;
}
header * {
font-size: 20px;
padding: 5px;
}
tabs {
padding: 3px;
}
tab {
margin: 2px 5px 4px 0px; /* top right bottom left */
padding: 5px;
border-style: solid;
font-size: 27px;
}
entry {
padding-left: 10px;
}
entry:focus {
padding-left: 10px;
}

View File

@ -1,42 +0,0 @@
# Key dependencies
sudo apt install libwebkitgtk-6.0-dev
sudo apt install libgtk-4-dev
# Optional adblock
git clone https://github.com/jun7/wyebadblock
cd wyebadblock
sudo apt install gstreamer1.0-plugins-good gstreamer1.0-libav
WEBKITVER=4.1 make
sudo WEBKITVER=4.1 make install
cd ..
mkdir -p ~/.config/wyebadblock
cd ~/.config/wyebadblock
wget https://easylist.to/easylist/easylist.txt
cd -
cd ../..
make build4
sudo make install
cd -
# Debian desktop icon
chmod +x rosenrot.desktop
sudo cp rosenrot.desktop /usr/share/applications
mkdir -p /opt/rosenrot
sudo cp rosenrot-desktop-icon.png /opt/rosenrot/
# Optionally, set a shortcut (within GNOME)
# https://askubuntu.com/questions/597395/how-to-set-custom-keyboard-shortcuts-from-terminal/1007035#1007035
name="rose"
binding="<CTRL><SHIFT>W"
action="/usr/bin/rosenrot"
media_keys=org.gnome.settings-daemon.plugins.media-keys
custom_kbd=org.gnome.settings-daemon.plugins.media-keys.custom-keybinding
kbd_path=/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/$name/
new_bindings=`gsettings get $media_keys custom-keybindings | sed -e"s>'\]>','$kbd_path']>"| sed -e"s>@as \[\]>['$kbd_path']>"`
gsettings set $media_keys custom-keybindings "$new_bindings"
gsettings set $custom_kbd:$kbd_path name "$name"
gsettings set $custom_kbd:$kbd_path binding "$binding"
gsettings set $custom_kbd:$kbd_path command "$action"

View File

@ -16,7 +16,7 @@ wget https://easylist.to/easylist/easylist.txt
cd - cd -
cd ../.. cd ../..
make build3 # or just make make build # or just make
sudo make install sudo make install
cd - cd -