Compare commits

...

4 Commits

Author SHA1 Message Date
e583fd0fd2 remove stdbool 2024-03-23 22:29:41 -03:00
86989d878e formatting pass 2024-03-23 22:25:10 -03:00
db67b513d2 remove more stuff! 2024-03-23 22:24:38 -03:00
07cae73c71 remove extra files 2024-03-23 21:51:55 -03:00
70 changed files with 127 additions and 5933 deletions

115
README.md
View File

@ -1,116 +1,7 @@
# Rosenrot
Rosenrot is a small browser forked from an earlier version of [rose](https://github.com/mini-rose/rose). It has some additional quality of life improvements tailored to my (@NunoSempere) tastes and setup, and detailed installation instructions for Debian 12.
This branch contains a minimalist version of rosenrot, similar in many ways to the original version of rose.
![](https://raw.githubusercontent.com/NunoSempere/rosenrot-browser/master/images/3-init.png)
![](https://raw.githubusercontent.com/NunoSempere/rosenrot-browser/master/images/7-hello-world-search.png)
![](https://raw.githubusercontent.com/NunoSempere/rosenrot-browser/master/images/6-multiple-tabs.png)
### Installation and usage
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
```
make build
make install # or sudo make install
rose
```
You can also collect some profiling info, and then use that to get a perhaps faster version:
```
make fast ## will ask you to use the browser for a bit
make install
rose
```
You can also create a rose.desktop file so that it will show up in your desktop environment. You can see this documented [here](./user-scripts/debian-12/install-with-dependencies.sh).
## Features
- Tabs, cookies, caching
- Minimal ui, autohiding elements
- ~454L core code (the rose.c file)
- Customize appearance of the browser through css
- Built-in rose-mklink script for in-shell static links
- Optional adblocking through [wyebadblock](https://github.com/jun7/wyebadblock)
- Plugin system, seeded with:
- Libre redirect: Redirect annoying websites to open source frontends
- Readability: Strip webpages of unnecessary elements for ease of reading with a custom shortcut
- Custom style: Override the css of predetermined websites
- 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
You can see some screenshots in the [images](./images) folder.
## Similar projects
Here are some similar projects that I could find (minimalist, mostly based on webkit):
- [Surf](https://git.suckless.org/surf/). Suckless community. Similar goals, higher coding standards, less actively maintained.
- [Rose](https://github.com/mini-rose/rose-browser). Lua integrations, supports compilation with GTK4. Every now and then, the developer nukes the git history and tries some different approach.
- [Epiphany](https://gitlab.gnome.org/GNOME/epiphany). GNOME. Clean browser, distributed via flathub, aimed at nontechnical users. Seems actively maintained.
- [Vimb](https://github.com/fanglingsu/vimb). Reasonably actively maintained, vim keybindings.
- [Nyxt](https://github.com/atlas-engineer/nyxt). Emphasis on sophisticated key bindings.
- [Wyeb](https://github.com/jun7/wyeb)
- [Luakit](https://github.com/luakit/luakit)
- ~~[Qutebrowser](https://github.com/qutebrowser/qutebrowser). More actively maintained. I don't understand the tech stack.~~ [Based](https://github.com/qutebrowser/qutebrowser/blob/main/doc/faq.asciidoc) on [Chromium](https://wiki.qt.io/QtWebEngine)
Here are other projects I haven't checked out as much: [netsurf](https://www.netsurf-browser.org/), [uzbl](https://www.uzbl.org/), [edbrowse](https://github.com/CMB/edbrowse),
Here are projects with their own rendering engines which could appeal to users of rosenrot:
- [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.
- [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.
### 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).
- The current version offers compilation with both GTK3 and GTK4, and an up to date version of webkit.
- 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).
### Comparison with [surf](https://git.suckless.org/surf/file/surf.c.html)
- Surf is another browser based on GTK/Webkit, from the suckless community.
- It is significantly more complex: surf.c has [2170](https://git.suckless.org/surf/file/surf.c.html) lines, vs rose.c's [454](https://git.nunosempere.com/open.source/rosenrot/src/branch/master/rose.c).
- I find its code messier and harder to understand.
- Conversely, surf has significantly more configuration options, and digs deeper into webkit internals.
- Anecdotically, surf feels slower, though I haven't tested this rigorously.
- surf has a larger community, with patches and modifications.
- surf is more opinionated, but also less amateurish.
- 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.
## Folk wisdom
Of general interest:
- I just found out that you can inspect a GTK application with the GTK explorer if you set a certain command-line variable. Try this with `make inspect`.
- Static variables keep their value between invocations.
- By default the searchbar is pretty gigantic. I've made this so because I'm a bit myopic, but also work with my laptop in a laptop stand. Anyways, if you are a more normal person you can change this in the style.css.
- The style.css usage isn't updated until installation. This is because by default rose uses the theme located in /usr/share/themes/rose/style.css, and that file isn't updated until make install.
The "architecture" of the application looks as follows:
![](https://raw.githubusercontent.com/NunoSempere/rosenrot-browser/master/images/0-architecture.png)
## webkit2gtk-4.0 vs webkit2gtk-4.1 vs webkit2gtk-6.0
See [this blog post](https://blogs.gnome.org/mcatanzaro/2023/03/21/webkitgtk-api-for-gtk-4-is-now-stable/) for details. webkit2gtk-4.0 is deprecated, webkit2gtk-4.1 is the current [stable](https://webkitgtk.org/reference/webkit2gtk/stable/index.html) release and uses GTK3. webkit2gtk-6.0 is the current [unstable](https://webkitgtk.org/reference/webkitgtk/unstable/index.html) release, and uses GTK4.
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 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
A previous version of this repository was based on Ubuntu 20.04. You can still see documentation for that distribution [here](https://git.nunosempere.com/open.source/rosenrot/src/commit/8a1e0be30df52d5a21109297fd5bbc20efec1b3b), particularly a video installing rosenrot in a fresh Ubuntu 20.04 virtual machine [here](https://video.nunosempere.com/w/t3oAvJLPHTSAMViQ6zbwTV). However, that uses the webkit2gtk-4.0 library. Instead, I recommend adapting the Debian 12 instructions.
# To do
- [x] Create minimalist version of rosenrot

57
TODO.md
View File

@ -1,57 +0,0 @@
# To do
- [ ] Settle on a C standard (C11?), and use safer string handling functions provided by it.
- See make lint for purported insecurities
- [ ] Document creating new applications, e.g., as in [Asana for Linux](https://git.nunosempere.com/NunoSempere/asana-for-linux)
- [ ] 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>)?
- See whether it even exists at all
- [ ] 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)
- [ ] 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
- [x] Fix PageUp/PageDown shortcuts.
- ~~[ ] Set [`webkit_web_context_set_sandbox_enabled`](<https://webkitgtk.org/reference/webkit2gtk/2.36.8/WebKitWebContext.html#webkit-web-context-set-sandbox-enabled>), as recommended [here](<https://blogs.gnome.org/mcatanzaro/2022/11/04/stop-using-qtwebkit/>)~~. Irrelevant with upgrade to libsoup3.
- [x] Update to webkit2gtk-4.1
- [x] Change README and point to last Ubuntu 20.04 commit
- [x] Add list of similar projects: <https://github.com/qutebrowser/qutebrowser#similar-projects>
- [x] Add comparisons against rose & surf
- [x] Compare against rose
- [x] Compare against surf
- [x] ~~Doesn't work with when Spanish is selected as the language, for some reason~~ => Previously misdiagnosed. The real issue was that it freezes when interacting with [Espanso](https://espanso.org/) substitutions, which I had set-up automatically on my machine when using words containing an ñ, like my own name, Nuño.
- [x] Add css for js alerts
- [x] Add custom alert whose css can be customized
- [ ] ~~Debug problems, e.g., this version is non-blocking.~~ => will leave as is
- [x] Figure out better way to have plugins => stand_in code seems superfluous
- [x] Double check newtab/next-tab behavior => custom style now loading correctly.
- [x] Add a shortcut for hiding the search tab. => Already exists: Ctrl+K
- [x] Find out what each of the css elements refers to. => done, see make inspect
- [x] Figure out if downloading files is doable. => it is
- [x] Look at using relative rather than absolute paths for configuration. => now makefile is a bit smarter
- [x] Streamline installation a bit
- [x] Substitute paths in makefile
- [x] Create cache directory automatically
- [x] Add an installation video walkthrough. Done, [here](https://video.nunosempere.com/w/t3oAvJLPHTSAMViQ6zbwTV)
- [x] Document `stand_in.c` better
- [x] Use a makefile.
- [x] Add clean, uninstall to makefile
- [x] Mask user agent
- [x] Launch with more than one tab from command line
- [x] Figure out merge with upstream
- [x] String substitution on uri in order to redirect to better frontends.
- [x] Present "standard" browser keybindings as an alternative.
- [x] Fix zoom in new tab
- [x] Reader mode
- [x] Add reader mode to config.def.
- [x] Make tab bar slightly prettier.
- [x] Add "open in new window" functionality.
- 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.
- 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>)

142
config.h
View File

@ -1,142 +0,0 @@
#include <stdbool.h>
#include <gdk/gdk.h>
// Previously: #include <gdk/gdkkeysyms.h>
// But GTK3 discourages including the individual headers
// In GTK4, the location also changes to <gdk/gdkenums.h>
// Key user config
#define WIDTH 1920 // 960 for half-width, 1920 for full width
#define HEIGHT 1080
#define BAR_SIZE 1000
// More user config
#define ZOOM 1.6 /* Starting zoom level.*/
#define ZOOM_VAL .1 /* Zooming value in zoomin/zoomout functions */
#define BG_COLOR "#FEFEFE" /* "FEFEFE", "#1E1E2E" */
#define DEBUG false
#define MAX_NUM_TABS 8 // set to 0 or false if you want unlimited tabs, or look at the relevant rose.c code.
#define SEARCH "https://search.brave.com/search?q=%s"
// #define SEARCH "https://search.nunosempere.com/search?q=%s"
// #define SEARCH "https://lite.duckduckgo.com/html/?q=%s"
#define HOME "https://search.brave.com/search?q=%s"
// ^ Could also be a website ("https://search.nunosempere.com"), or a file ("file:///opt/rose/homepage.png")
// #define HOME "https://search.nunosempere.com/"
// #define HOME "file:///opt/rosenrot/rose.png"
// Plugins
#define LIBRE_REDIRECT_ENABLED true
#define READABILITY_ENABLED true
#define CUSTOM_STYLE_ENABLED true
#define CUSTOM_USER_AGENT false
/*
To disable plugins:
1. set their corresponding variable to false
2. you could also look into this file at commit afe93518a for an approach using stand-in code.
3. recompile
To remove plugins completely;
1. Remove the corresponding code in the rosenrot.c by looking for the variables above.
2. Remove PLUGIN and $(PLUGIN) from the makefile
3. Recompile
*/
// Webkit settings
// See: https://webkitgtk.org/reference/webkit2gtk/stable/class.Settings.html
#define WEBKIT_DEFAULT_SETTINGS \
"enable-back-forward-navigation-gestures", true, "enable-developer-extras", true, \
"enable-smooth-scrolling", false, \
"default-charset", "utf-8"
/* CACHE */
#define DATA_DIR "/home/nuno/.cache/rosenrot"
#define DATA_MANAGER_OPTS "base-cache-directory", DATA_DIR, "base-data-directory", DATA_DIR
// GTK
#define GTK_SETTINGS_CONFIG_H "gtk-application-prefer-dark-theme", false, "gtk-enable-animations", false
#define KEY(x) GDK_KEY_##x
/*
There are two different constants for Page_Up/Page_Down:
This could possibly have something to so with having Page_Down/Page_Up
as part of a keypad with/without NumLock
See: https://docs.gtk.org/gdk3/?q=Page_Up
See: https://docs.gtk.org/gdk3/?q=GDK_KEY_KP
*/
// Shortcuts
typedef enum {
goback,
goforward,
refresh,
refresh_force,
back_to_home,
toggle_fullscreen,
zoomin,
zoomout,
zoom_reset,
new_tab,
next_tab,
prev_tab,
close_tab,
show_searchbar,
show_finder,
finder_next,
finder_prev,
prettify,
hide_bar
} func;
#define SFT 1 << 0
#define CTRL 1 << 2
#define ALT 1 << 3
// reference: <https://github.com/GNOME/gtk/blob/7ea7d5c3906ccd231b04654101bb742f157d82f6/gdk/gdkenums.h#L140>
static struct {
unsigned mod;
unsigned key;
func id;
} shortcut[] = {
{ CTRL, KEY(h), goback },
{ CTRL, KEY(j), goforward },
{ CTRL, KEY(r), refresh },
{ CTRL, KEY(R), refresh_force },
{ CTRL, KEY(H), back_to_home },
{ CTRL, KEY(equal), zoomin },
{ CTRL, KEY(minus), zoomout },
{ CTRL, KEY(0), zoom_reset },
{ CTRL, KEY(KP_Page_Up), prev_tab }, /* also try KEY(Page_Up) if this doesn't work on your machine */
{ CTRL, KEY(KP_Page_Down), next_tab }, /* ditto for KEY(Page_Down) */
{ CTRL, KEY(t), new_tab },
{ CTRL, KEY(w), close_tab },
{ 0x0, KEY(F11), toggle_fullscreen },
{ CTRL, KEY(l), show_searchbar },
{ CTRL, KEY(semicolon), hide_bar },
{ CTRL, KEY(f), show_finder },
{ CTRL, KEY(n), finder_next },
{ CTRL, KEY(N), finder_prev },
{ CTRL, KEY(p), prettify }
};
/* ^ For controls more akin to normal browsers */
/* Reference for the key shorthand:
* <https://gitlab.gnome.org/GNOME/gtk/-/blob/main/gdk/gdkkeysyms.h> */
/* Old controls: {
{ CTRL, KEY(h), goback },
{ CTRL, KEY(l), goforward },
{ CTRL, KEY(r), refresh },
{ CTRL | SFT, KEY(R), refresh_force },
{ CTRL | SFT, KEY(H), back_to_home },
{ CTRL, KEY(equal), zoomin },
{ CTRL, KEY(minus), zoomout },
{ CTRL, KEY(0), zoom_reset },
{ ALT, KEY(h), prev_tab },
{ CTRL, KEY(k), hide_searchbar },
{ ALT, KEY(l), next_tab },
{ CTRL, KEY(w), close_tab },
{ 0x0, KEY(F11), toggle_fullscreen },
{ CTRL, KEY(e), show_searchbar },
{ CTRL, KEY(f), show_finder },
{ CTRL, KEY(n), finder_next },
{ CTRL | SFT, KEY(N), finder_prev },
{ CTRL, KEY(p), prettify }
};
*/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 534 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 KiB

View File

@ -1 +0,0 @@
https://www.onlygfx.com/red-rose-png-image-transparent/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 739 KiB

View File

@ -1,9 +1,5 @@
# C compiler
CC=gcc # alternatives: tcc, clang, zig cc
WARNINGS=-Wall
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
DEBUG= # -g
# Dependencies
DEPS='webkit2gtk-4.1'
@ -12,29 +8,13 @@ LIBS=`pkg-config --libs ${DEPS}`
# Code
SRC=rosenrot.c
CONFIG=config.h
# Plugins
include plugins/plugins.mk
# PLUGINS=./plugins/stand_in/stand_in.c
## Formatter
STYLE_BLUEPRINT="{BasedOnStyle: webkit, AllowShortIfStatementsOnASingleLine: true, IndentCaseLabels: true, AllowShortEnumsOnASingleLine: true}"
FORMATTER=clang-format -i -style=$(STYLE_BLUEPRINT)
# Runtime files
## Runtime files
MAINTAINER_CACHE_DIR=/home/nuno/.cache/rosenrot
USER_CACHE_DIR=/home/`whoami`/.cache/rosenrot
RUNTIME_FILES_DIR=/opt/rosenrot/
build: $(SRC) $(PLUGINS) $(CONFIG) constants user_cache
$(CC) $(WARNINGS) $(OPTIMIZED_MORE) $(DEBUG) $(INCS) $(PLUGINS) $(SRC) -o rosenrot $(LIBS) $(ADBLOCK)
constants:
@echo "# Computing constants"
cd plugins/readability/ && sh recompute_READABILITY_N.sh
cd plugins/style && sh recompute_STYLE_N.sh
@echo
build: $(SRC) user_cache
$(CC) $(INCS) $(SRC) -o rosenrot $(LIBS) $(ADBLOCK)
user_cache:
@if [ `id -u` -eq 0 ]; then echo "can't run make user_cache with sudo, because USER_CACHE_DIR would be /home/root/.cache"; return 1; fi
@ -44,55 +24,27 @@ user_cache:
sed -i "s|$(MAINTAINER_CACHE_DIR)|$(USER_CACHE_DIR)|g" {} +
@echo
runtime_files:
sudo mkdir -p /opt/rosenrot/
sudo cp style.css /opt/rosenrot/
sudo cp -r images/flower-imgs /opt/rosenrot/
sudo cp plugins/style/style.js /opt/rosenrot/
sudo cp plugins/readability/readability.js /opt/rosenrot/
install: rosenrot runtime_files
install: rosenrot
cp -f rosenrot /usr/bin
cp rosenrot-mklink /usr/bin
## Additional niceties
### Formatter
STYLE_BLUEPRINT="{BasedOnStyle: webkit, AllowShortIfStatementsOnASingleLine: true, IndentCaseLabels: true, AllowShortEnumsOnASingleLine: true}"
FORMATTER=clang-format -i -style=$(STYLE_BLUEPRINT)
format: $(SRC)
$(FORMATTER) $(SRC)
lint:
clang-tidy $(SRC) -- -Wall $(INCS) -o rosenrot $(LIBS)
### Cleanup functions
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) $(SRC) $(PLUGINS) $(rosenrot.h)
lint:
clang-tidy $(SRC) $(PLUGINS) -- -Wall -O3 $(INCS) -o rosenrot $(LIBS)
## A few more commands:
fast: $(SRC) $(PLUGINS) $(CONFIG)
rm -f *.gcda
GIO_MODULE_DIR=/usr/lib/x86_64-linux-gnu/gio/modules/
$(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"
sleep 2
./rosenrot
$(CC) $(WARNINGS) $(OPTIMIZED_MORE) -fprofile-use $(INCS) $(PLUGINS) $(SRC) -o rosenrot $(LIBS) $(ADBLOCK)
rm -f *.gcda
inspect: rosenrot
GTK_DEBUG=interactive ./rosenrot
diagnose_deprecations: rosenrot
G_ENABLE_DIAGNOSTIC=1 ./rosenrot
view-gtk3-version:
dpkg -l libgtk-3-0
twitter:
sudo mkdir -p /usr/bin/rosenrot-browser
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

@ -1,3 +0,0 @@
## About
This code automatically redirects webpage to their open-source frontends. It is based on <https://libredirect.codeberg.page/>

View File

@ -1,66 +0,0 @@
#include <stdio.h>
#include <string.h>
#include "../strings/strings.h"
#define LIBRE_N 50
/* Inspired by https://libredirect.github.io/, but in C. */
int libre_redirect(const char* uri, char* output)
{
int len_uri = strlen(uri);
int len_output = strlen(output);
if ((len_output - len_uri) < LIBRE_N) {
fprintf(stderr, "Not enough memory\n");
return 1; // not enough memory.
} else {
char* annoying_sites[] = {
"https://www.reddit.com",
"https://www.youtube.com",
"https://google.com",
"https://medium.com",
"https://translate.google.com",
"https://www.bloomberg.com",
"https://www.royalroad.com",
"https://genius.com",
// "https://archive.org",
// "https://twitter.com"
};
char* alternatives[] = {
"https://old.reddit.com", // "https://teddit.nunosempere.com",
"https://invidious.private.coffee",
"https://search.nunosempere.com",
"https://scribe.rip",
"https://translate.riverside.rocks",
"https://archive.is/https://www.bloomberg.com",
"https://royalread.nunosempere.com",
"https://dumb.vern.cc",
// "https://wayback.nunosempere.com",
// "https://nitter.net"
};
int len = sizeof(annoying_sites) / sizeof(annoying_sites[0]);
for (int i = 0; i < len; i++) {
str_init(output, len_output);
int replace_check = str_replace_start(uri, annoying_sites[i],
alternatives[i], output);
switch (replace_check) {
case 0: // no match found
break;
case 1: // str_replace_start somehow failed
fprintf(stderr, "str_replace_start failed\n");
return 1;
break;
case 2: // match succeeded
return 2;
break;
default:
fprintf(stderr, "Unreachable state\n");
}
}
strcpy(output, uri);
}
return 0;
}

View File

@ -1,5 +0,0 @@
#pragma once
#define LIBRE_N 50
int libre_redirect(const char* uri, char* uri_filtered);

View File

@ -1,11 +0,0 @@
#!/bin/bash
CC=gcc
FLAGS="-std=c99 -Wall -lm"
SRC=example.c
REQS="../str_replace_start.c ../libre_redirect.c"
echo -e "\n\n\n"
$CC $FLAGS $SRC $REQS -o example

View File

@ -1,19 +0,0 @@
#include "../libre_redirect.h"
#include <stdio.h>
#include <string.h>
int main()
{
char uri[] = "https://reddit.com/r/blah";
int l = LIBRE_N + strlen(uri) + 1;
char uri_filtered[l];
str_init(uri_filtered, l);
if (!libre_redirect(uri, uri_filtered)) {
printf("Filtered uri: %s\n", uri_filtered);
} else {
printf("Uri: %s\n", uri);
// failure; do something with the original uri.
}
}

View File

@ -1,5 +0,0 @@
#include "strings/strings.h"
#include "libre_redirect/libre_redirect.h"
#include "readability/readability.h"
#include "shortcuts/shortcuts.h"
#include "style/style.h"

View File

@ -1,17 +0,0 @@
## Shared
COMMON_CODE=./plugins/strings/strings.c
## Plugins
CUSTOM_STYLES=./plugins/style/style.c
SHORTCUTS=./plugins/shortcuts/shortcuts.c
READABILITY=./plugins/readability/readability.c
LIBRE_REDIRECT=./plugins/libre_redirect/libre_redirect.c
ADBLOCK='-L/usr/lib/wyebrowser/adblock.so' # optional adblocking; depends on https://github.com/jun7/wyebadblock
STAND_IN=./plugins/stand_in/stand_in.c # gives function definitions for the above, which do nothing
PLUGINS=$(COMMON_CODE) $(CUSTOM_STYLES) $(SHORTCUTS) $(READABILITY) $(LIBRE_REDIRECT)
# PLUGINS=$(STAND_IN)

View File

@ -1,2 +0,0 @@
This code reimplements firefox readability mode. Code taken from <https://raw.githubusercontent.com/ushnisha/readability-reader-webextensions/master/content_scripts/tranquilize.js>

Binary file not shown.

View File

@ -1,31 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define READABILITY_N 88067 + 1000
void read_readability_js(char* string)
{
FILE* fp = fopen("/opt/rosenrot/readability.js", "r");
if (!fp) { // fp is NULL, fopen failed
fprintf(stderr, "Failed to open file\n");
fprintf(stderr, "Consider running $ sudo make runtime_files\n");
string = NULL;
return;
}
int i = 0;
int c;
while ((c = fgetc(fp)) != EOF) {
string[i++] = c;
}
string[i] = '\0';
fclose(fp);
}
/*
int main(){
char* readability_js = malloc(READABILITY_N+1);
read_readability_js(readability_js);
printf("%s", readability_js);
free(readability_js);
}
*/

View File

@ -1,5 +0,0 @@
#pragma once
#define READABILITY_N 88067 + 1000
void read_readability_js(char* string);

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +0,0 @@
#!/bin/sh
sed_wrapper()
{
find ./ -type f -exec sed -i -e "$1" {} \;
} ## e.g., sedr "s/target/replacement/g"
READABILITY_N=`wc -c readability.js | cut -d " " -f 1`
sed_wrapper "s/^#define READABILITY_N .*/#define READABILITY_N $READABILITY_N + 1000/g"

View File

@ -1,7 +0,0 @@
## About
This code automatically redirects shortcuts to their longer expansions. Similar to DuckDuckGo's bangs (<https://duckduckgo.com/bangs>)
Note that Whoogle (the default search engine) also has its own bangs!
- See: https://github.com/benbusby/whoogle-search/blob/main/app/utils/bangs.py
- and https://duckduckgo.com/bang.v255.js

View File

@ -1,65 +0,0 @@
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "../strings/strings.h"
#define SHORTCUT_N 41
#define DEBUG false
/* Inspired by https://duckduckgo.com/bangs */
int shortcut_expand(const char* uri, char* output)
{
int len_uri = strlen(uri);
int len_output = strlen(output);
if ((len_output - len_uri) < SHORTCUT_N) {
fprintf(stderr, "Not enough memory\n");
return 1; // not enough memory.
} else {
char* shortcuts[] = {
"!aa",
"!blog",
"!fnf",
"!fnc",
"!hn",
"!hnb"
"!x",
};
char* expansions[] = {
"https://annas-archive.org",
"https://nunosempere.com/blog",
"https://forum.nunosempere.com/frontpage",
"https://forum.nunosempere.com/comments",
"https://news.ycombinator.com",
"https://news.ycombinator.com/best",
"https://twitter.com",
};
// len = sizeof(shortcuts) / sizeof(shortcuts[0]);
int len = sizeof(shortcuts) / sizeof(char*);
for (int i = 0; i < len; i++) {
str_init(output, len_output);
int replace_check = str_replace_start(uri, shortcuts[i],
expansions[i], output);
switch (replace_check) {
case 0: // no match found
break;
case 1: // str_replace_start somehow failed
fprintf(stderr, "str_replace_start failed\n");
return 1;
break;
case 2: // match succeeded
return 2;
break;
default:
fprintf(stderr, "Unreachable state\n");
}
}
strcpy(output, uri);
}
if (DEBUG) printf("No match found\n\n");
return 0;
}

View File

@ -1,5 +0,0 @@
#pragma once
#define SHORTCUT_N 41
int shortcut_expand(const char* uri, char* output);

View File

@ -1,30 +0,0 @@
/* Why this file is needed:
* If the plugins are disabled,
* their conditionals will never resolve
* and their functionality never comes into play
* but the compiler still wants to know their type
*/
int libre_redirect(const char* uri, char* uri_filtered){
return 0;
}
void str_init(char* str, int n){
};
int str_replace_start(const char* string, const char* target,
const char* replacement, char* output){
return 1;
};
void read_readability_js(char* string){
}
void read_style_js(char* string){
}
int shortcut_expand(const char* uri, char* output){
return 0;
}

View File

@ -1,24 +0,0 @@
/* Why this file is needed:
* If the plugins are disabled,
* their conditionals will never resolve
* and their functionality never comes into play
* but the compiler still wants to know their type
*/
#pragma once
#define LIBRE_N 0
#define STYLE_N 0
#define READABILITY_N 84638 + 1
int libre_redirect(const char* uri, char* uri_filtered);
void str_init(char* str, int n);
int str_replace_start(const char* string, const char* target,
const char* replacement, char* output);
void read_readability_js(char* string);
void read_style_js(char* string);
int shortcut_expand(const char* uri, char* output);

View File

@ -1,61 +0,0 @@
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#define DEBUG false
// String manipulation
void str_init(char* str, int n)
{
// could also use <https://manpages.ubuntu.com/manpages/impish/man3/strinit.3pub.html>
for (int i = 0; i < n; i++)
str[i] = ' ';
str[n] = '\0';
}
int str_replace_start(const char* string, const char* target, const char* replacement, char* output)
{
int l1 = strlen(string);
int l2 = strlen(target);
int l3 = strlen(replacement);
int l4 = strlen(output);
if (DEBUG) {
printf("string: %s, target: %s, replacement: %s, output: %s\n", string, target, replacement, output);
printf("%d,%d,%d,%d\n", l1, l2, l3, l4);
}
if ((l4 < (l1 - l2 + l3)) || l4 < l1) {
printf("Not enough memory in output string.\n");
return 1;
}
int match = true;
for (int i = 0; i < l2; i++) {
if (string[i] != target[i]) {
match = false;
break;
}
}
if (match) {
if (DEBUG) printf("Found match.\n");
for (int i = 0; i < l3; i++) {
output[i] = replacement[i];
}
int counter = l3;
for (int i = l2; i < l1; i++) {
output[counter] = string[i];
counter++;
}
output[counter] = '\0';
return 2; // success
} else {
if (DEBUG) printf("Did not find match.\n");
strcpy(output, string);
}
return 0;
}
/*
See also:
* <https://web.archive.org/web/20160201212501/coding.debuntu.org/c-implementing-str_replace-replace-all-occurrences-substring>
* https://github.com/irl/la-cucina/blob/master/str_replace.c
*/

View File

@ -1,4 +0,0 @@
#pragma once
void str_init(char* str, int n);
int str_replace_start(const char* string, const char* target, const char* replacement, char* output);

View File

@ -1,5 +0,0 @@
## Customize css style for individual websites.
- Replicates: <https://addons.mozilla.org/en-GB/firefox/addon/styl-us/>.
- The template is similar to the readability folder.
- You will also want to customize the `style.c` file.

View File

@ -1,9 +0,0 @@
#!/bin/sh
sed_wrapper()
{
find ./ -type f -exec sed -i -e "$1" {} \;
} ## e.g., sedr "s/target/replacement/g"
STYLE_N=`wc -c style.js | cut -d " " -f 1`
sed_wrapper "s/^#define STYLE_N .*/#define STYLE_N $STYLE_N + 1000/g"

View File

@ -1,21 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STYLE_N 7624 + 1000
void read_style_js(char* string)
{
FILE* fp = fopen("/opt/rosenrot/style.js", "r");
if (!fp) { // fp is NULL, fopen failed
fprintf(stderr, "Failed to open file\n");
string = NULL;
return;
}
int i = 0;
int c;
while ((c = fgetc(fp)) != EOF) {
string[i++] = c;
}
string[i] = '\0';
fclose(fp);
}

View File

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

View File

@ -1,286 +0,0 @@
// Inspired by the Stylus app: <https://addons.mozilla.org/en-GB/firefox/addon/styl-us/>
// Main part of the code: switch on the domain and select the corresponding style
var styles = null;
switch (document.domain) {
case "forum.effectivealtruism.org":
styles = `
/*
.Layout-main {
margin-left: 100px;
}
.SingleColumnSection-root {
width: 1000px !important;
max-width: 1400px !important;
padding-left: 100px !important;
}
.NavigationStandalone-sidebar {
display: none;
}
.intercom-lightweight-app{
display: none;
}
*/
`;
break;
case "nationstates.net":
styles = `
.adidentifier {
display: none;
}
`;
break;
case "mail.proton.me":
styles = `
/*
.item-container-row.read, .item-container.read {
background-color: white;
}
.item-container-row.unread, .item-container.unread {
background-color: #E8E8E8;
}
.selection .item-container-row.item-is-selected, .item-container.item-is-selected {
background-color: var(--selection-background-color) !important;
}
zoom: 0.625 !important;
*/
`;
break;
case "forum.nunosempere.com":
styles = `
body {
zoom: 0.625 !important;
}
`;
break;
case "search.nunosempere.com":
styles = `
/*
body {
zoom: 1.8;
}
*/
footer {
display: none;
}
`;
break;
case "reddit.com":
// fallthrough
case "old.reddit.com":
styles = `
/* kill sidebar ads */
.ad-container,
a[href^="https://alb.reddit.com"]
a[href="/premium"],
[data-promoted^="true"],
#eu-cookie-policy,
.infobar-toaster-container,
.listingsignupbar,
.native-ad-container,
.native-sidebar-ad,
.premium-banner-outer,
{
display: none !important;
}
`;
break;
case "twitter.com":
styles = `
/* hide promoted tweets */
:has(meta[property="og:site_name"][content="Twitter"])
[data-testid="cellInnerDiv"]:has(svg + [dir="auto"]) {
display: none;
}
[data-testid^="placementTracking"] {
display: none;
}
/* hide what's happening section */
:has(meta[property="og:site_name"][content="Twitter"])
[aria-label="Timeline: Trending now"] {
display: none !important;
}
[data-testid^="sidebarColumn"] {
display: none;
}
/* Hide DMs v2 */
[data-testid^="DMDrawerHeader"] {
display: none;
}
/* Tweak main column */
[data-testid^="primaryColumn"] {
min-width: 900px;
max-width: 900px;
}
[data-testid^="cellInnerDiv"] {
min-width: 700px;
max-width: 700px;
}
[aria-label^="Timeline: Conversation"]{
margin-left: 145px;
}
[data-testid^="DMDrawer"]{
display: none;
}
/* Delete a few unused or annoying elements */
[aria-label^="Verified Orgs"] {
display: none;
}
[aria-label^="Lists"] {
display: none;
}
[aria-label^="Communities"] {
display: none;
}
[aria-label^="Primary"] {
margin-top: 50px;
}
[role^="progressbar"]{
display: none;
}
/* hide video */
[data-testid^="videoPlayer"] {
display: none !important;
}
/* No change of colors in hover */
*:hover {
/* background-color: white !important; */
background-color: !important;
transition: none !important;
}*/
/*
*:hover {
background-color: inherit !important;
transition: none !important;
}*/
/* Hide go to top button */
[aria-label^="New posts are available. Push the period key to go to the them."]{
display: none;
}
/* No transparency at the top */
[aria-live^="polite"]{
background: white !important;
}
`;
break;
default:
console.log("No custom style");
}
if (styles != null) {
var styleSheet = document.createElement("style");
styleSheet.innerText = styles;
document.head.appendChild(styleSheet);
console.log("Style changed");
}
// Extra: Replace default alert with new function
// whose style can be changed!
window.alert = (message) => {
let alertDiv = document.getElementById("customAlert");
if (!alertDiv) {
const html = `
<div id="customAlert" class="custom-alert">
<div class="custom-alert-content">
<p id="alertMessage"></p>
<button id="alertOkButton">OK</button>
</div>
</div>
<style>
.custom-alert {
display: none;
position: fixed;
z-index: 999;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.4);
}
.custom-alert-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
font-family: monospace; /* Use monospace font */
}
.visible {
display: block;
}
</style>
`;
document.body.insertAdjacentHTML("beforeend", html);
alertDiv = document.getElementById("customAlert");
document.getElementById("alertOkButton").onclick = () => {
alertDiv.classList.remove("visible");
document.removeEventListener("keydown", dismissAlert);
};
}
const dismissAlert = (event) => {
if (
event.key === "Enter" /*&& event.ctrlKey*/ &&
alertDiv.classList.contains("visible")
) {
alertDiv.classList.remove("visible");
document.removeEventListener("keydown", dismissAlert);
}
};
document.addEventListener("keydown", dismissAlert);
document.getElementById("alertMessage").textContent = message;
alertDiv.classList.add("visible");
};
// Extra: hide video players on twitter
if (document.domain == "twitter.com") {
// Function to hide the grandparent of video players
// takes 0.014ms to run, so performance is not the concern here.
// timed with console.time, console.timeEnd
function hideVideoPlayerGrandparent() {
document
.querySelectorAll('[data-testid="videoPlayer"]')
.forEach(function (videoPlayer) {
var grandparentElement =
videoPlayer.parentElement.parentElement.parentElement.parentElement
.parentElement.parentElement;
var newTextElement = document.createElement("div");
newTextElement.textContent = " [ twitter video ] ";
newTextElement.style["margin-top"] = "10px";
newTextElement.style["margin-left"] = "10px";
newTextElement.style["margin-bottom"] = "10px";
grandparentElement.replaceWith(newTextElement);
});
}
// Create a new MutationObserver instance
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.addedNodes.length) {
hideVideoPlayerGrandparent(); // Call the function to hide video players
}
});
});
// Options for the observer (which mutations to observe)
var config = { childList: true, subtree: true };
// Start observing the target node for configured mutations
observer.observe(document.body, config);
// Call the function initially to hide any video players on initial load
hideVideoPlayerGrandparent();
}
document.body.style.visibility = "visible";

View File

@ -1,17 +0,0 @@
#!/bin/sh
test "$1" = "--help" || test -z "$1" && {
printf "%s\n" "usage: rosenrot-mklink <alias> <url>" \
"Create a /usr/bin link to a website."
exit
}
test -z "$2" || {
test -f "/usr/bin/$1" && {
echo "/usr/bin/$1 already exists, remove it first"
exit 1
}
printf "#!/bin/sh\n\nrosenrot %s" "$2" > /usr/bin/$1
chmod +x /usr/bin/$1
}

View File

@ -3,8 +3,85 @@
#include <string.h>
#include <webkit2/webkit2.h>
#include "config.h"
#include "plugins/plugins.h"
// User config
#define WIDTH 1920 // 960 for half-width, 1920 for full width
#define HEIGHT 1080
#define BAR_SIZE 1000
#define SEARCH "https://lite.duckduckgo.com/html/?q=%s"
#define HOME "https://lite.duckduckgo.com/html"
// Minimal niceties
#define ZOOM 1 /* Starting zoom level.*/
#define ZOOM_VAL .1 /* Zooming value in zoomin/zoomout functions */
#define MAX_NUM_TABS 8
// Webkit settings
// See: https://webkitgtk.org/reference/webkit2gtk/stable/class.Settings.html
#define WEBKIT_DEFAULT_SETTINGS \
"enable-back-forward-navigation-gestures", 1, "enable-developer-extras", 1, \
"enable-smooth-scrolling", 0, \
"default-charset", "utf-8"
/* CACHE */
#define DATA_DIR "/home/nuno/.cache/rosenrot"
#define DATA_MANAGER_OPTS "base-cache-directory", DATA_DIR, "base-data-directory", DATA_DIR
// GTK
#define GTK_SETTINGS_CONFIG_H "gtk-application-prefer-dark-theme", 0, "gtk-enable-animations", 0
#define KEY(x) GDK_KEY_##x
// Shortcuts
typedef enum {
goback,
goforward,
refresh,
refresh_force,
back_to_home,
toggle_fullscreen,
zoomin,
zoomout,
zoom_reset,
new_tab,
next_tab,
prev_tab,
close_tab,
show_searchbar,
show_finder,
finder_next,
finder_prev,
prettify,
hide_bar
} func;
#define SFT 1 << 0
#define CTRL 1 << 2
#define ALT 1 << 3
static struct {
unsigned mod;
unsigned key;
func id;
} shortcut[] = {
{ CTRL, KEY(h), goback },
{ CTRL, KEY(j), goforward },
{ CTRL, KEY(r), refresh },
{ CTRL, KEY(R), refresh_force },
{ CTRL, KEY(H), back_to_home },
{ CTRL, KEY(equal), zoomin },
{ CTRL, KEY(minus), zoomout },
{ CTRL, KEY(0), zoom_reset },
{ CTRL, KEY(KP_Page_Up), prev_tab }, /* also try KEY(Page_Up) if this doesn't work on your machine */
{ CTRL, KEY(KP_Page_Down), next_tab }, /* ditto for KEY(Page_Down) */
{ CTRL, KEY(t), new_tab },
{ CTRL, KEY(w), close_tab },
{ 0x0, KEY(F11), toggle_fullscreen },
{ CTRL, KEY(l), show_searchbar },
{ CTRL, KEY(semicolon), hide_bar },
{ CTRL, KEY(f), show_finder },
{ CTRL, KEY(n), finder_next },
{ CTRL, KEY(N), finder_prev },
{ CTRL, KEY(p), prettify }
};
/* Global declarations */
static GtkNotebook* notebook;
@ -13,12 +90,13 @@ static struct {
GtkHeaderBar* widget;
GtkEntry* line;
GtkEntryBuffer* line_text;
enum { _SEARCH, _FIND, _HIDDEN } entry_mode;
enum { _SEARCH,
_FIND,
_HIDDEN } entry_mode;
} bar;
static int num_tabs = 0;
// Forward declarations
void toggle_bar(GtkNotebook* notebook);
void notebook_create_new_tab(GtkNotebook* notebook, const char* uri);
/* Utils */
@ -33,63 +111,19 @@ void load_uri(WebKitWebView* view, const char* uri)
{
if (strlen(uri) == 0) {
webkit_web_view_load_uri(view, "");
bar.entry_mode = _SEARCH;
toggle_bar(notebook);
} else if (g_str_has_prefix(uri, "http://") || g_str_has_prefix(uri, "https://") || g_str_has_prefix(uri, "file://") || g_str_has_prefix(uri, "about:")) {
webkit_web_view_load_uri(view, uri);
} else if (strstr(uri, ".com") || strstr(uri, ".org")) {
char tmp[strlen("https://") + strlen(uri)];
snprintf(tmp, sizeof(tmp), "https://%s", uri);
webkit_web_view_load_uri(view, tmp);
} else {
// Check for shortcuts
int l = SHORTCUT_N + strlen(uri) + 1;
char uri_expanded[l];
str_init(uri_expanded, l);
int check = shortcut_expand(uri, uri_expanded);
if (check == 2) {
webkit_web_view_load_uri(view, uri_expanded);
} else {
// Feed into search engine.
char tmp[strlen(uri) + strlen(SEARCH)];
snprintf(tmp, sizeof(tmp), SEARCH, uri);
webkit_web_view_load_uri(view, tmp);
}
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) {
// see <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: {
/* Add gtk tab title */
const char* webpage_title = webkit_web_view_get_title(self);
@ -106,7 +140,6 @@ void handle_signal_load_changed(WebKitWebView* self, WebKitLoadEvent load_event,
}
gtk_notebook_set_tab_label_text(notebook, GTK_WIDGET(self),
webpage_title == NULL ? "" : tab_title);
// gtk_widget_hide(GTK_WIDGET(bar));
}
}
}
@ -119,9 +152,8 @@ GtkWidget* handle_signal_create_new_tab(WebKitWebView* self,
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);
gtk_notebook_set_show_tabs(notebook, 1);
} else {
webkit_web_view_evaluate_javascript(self, "alert('Too many tabs, not opening a new one')", -1, NULL, "rosenrot-alert-numtabs", NULL, NULL, NULL);
}
@ -143,13 +175,6 @@ WebKitWebView* create_new_webview()
WebKitUserContentManager* contentmanager;
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/110.0.0.0 Safari/537.36");
// See: <https://www.useragents.me/> for some common user agents
}
web_context = webkit_web_context_new_with_website_data_manager(webkit_website_data_manager_new(DATA_MANAGER_OPTS, NULL));
contentmanager = webkit_user_content_manager_new();
cookiemanager = webkit_web_context_get_cookie_manager(web_context);
@ -158,11 +183,6 @@ WebKitWebView* create_new_webview()
webkit_cookie_manager_set_accept_policy(cookiemanager, WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
if (g_file_get_contents("~/.config/rose/style.css", &style, NULL, NULL)) {
webkit_user_content_manager_add_style_sheet(
contentmanager, webkit_user_style_sheet_new(style, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, WEBKIT_USER_STYLE_LEVEL_USER, NULL, NULL));
}
return g_object_new(WEBKIT_TYPE_WEB_VIEW, "settings", settings, "web-context", web_context, "user-content-manager", contentmanager, NULL);
}
void notebook_create_new_tab(GtkNotebook* notebook, const char* uri)
@ -174,13 +194,10 @@ void notebook_create_new_tab(GtkNotebook* notebook, const char* uri)
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);
gtk_notebook_set_tab_reorderable(notebook, GTK_WIDGET(view), 1);
gtk_widget_show_all(GTK_WIDGET(window));
gtk_widget_hide(GTK_WIDGET(bar.widget));
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);
@ -191,34 +208,6 @@ void notebook_create_new_tab(GtkNotebook* notebook, const char* uri)
}
}
/* Top bar */
void toggle_bar(GtkNotebook* notebook)
{
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_show(GTK_WIDGET(bar.widget));
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_show(GTK_WIDGET(bar.widget));
gtk_window_set_focus(window, GTK_WIDGET(bar.line));
break;
}
case _HIDDEN:
gtk_widget_hide(GTK_WIDGET(bar.widget));
}
}
// Handle what happens when the user is on the bar and presses enter
void handle_signal_bar_press_enter(GtkEntry* self, GtkNotebook* notebook)
{
@ -230,12 +219,9 @@ void handle_signal_bar_press_enter(GtkEntry* self, GtkNotebook* notebook)
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 */
// Act when a particular shortcut is detected
int handle_shortcut(func id, GtkNotebook* notebook)
{
static double zoom = ZOOM;
@ -291,16 +277,9 @@ int handle_shortcut(func id, GtkNotebook* notebook)
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;
if (gtk_notebook_get_n_pages(notebook) == 0) {
exit(0);
}
break;
case toggle_fullscreen:
@ -311,14 +290,25 @@ int handle_shortcut(func id, GtkNotebook* notebook)
is_fullscreen = !is_fullscreen;
break;
case show_searchbar:
case show_searchbar: {
bar.entry_mode = _SEARCH;
toggle_bar(notebook);
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_show(GTK_WIDGET(bar.widget));
gtk_window_set_focus(window, GTK_WIDGET(bar.line));
break;
case show_finder:
}
case show_finder: {
bar.entry_mode = _FIND;
toggle_bar(notebook);
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_window_set_focus(window, GTK_WIDGET(bar.line));
break;
}
case finder_next:
webkit_find_controller_search_next(webkit_web_view_get_find_controller(view));
@ -329,25 +319,7 @@ int handle_shortcut(func id, GtkNotebook* notebook)
case new_tab:
notebook_create_new_tab(notebook, NULL);
gtk_notebook_set_show_tabs(notebook, true);
bar.entry_mode = _SEARCH;
toggle_bar(notebook);
break;
case hide_bar:
bar.entry_mode = _HIDDEN;
toggle_bar(notebook);
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;
@ -362,28 +334,9 @@ int handle_signal_keypress(void* self, GdkEvent* event, GtkNotebook* notebook)
GdkModifierType event_state = 0;
gdk_event_get_state(event, &event_state);
int debug_shortcuts = 0;
if (debug_shortcuts) {
printf("Keypress state: %d\n", event_state);
if (event_state & GDK_CONTROL_MASK) {
printf("Keypress state is: CONTROL\n");
}
printf("Keypress value: %d\n", event_keyval);
printf("PageUp: %d %d\n", KEY(Page_Up), GDK_KEY_KP_Page_Up);
printf("PageDown: %d %d\n", KEY(Page_Down), GDK_KEY_KP_Page_Down);
}
for (int i = 0; i < sizeof(shortcut) / sizeof(shortcut[0]); i++)
if ((event_state & shortcut[i].mod || shortcut[i].mod == 0x0) && event_keyval == shortcut[i].key)
return handle_shortcut(shortcut[i].id, notebook);
/*
If I wanted to bind button presses, like the extra button in the mouse,
I would have to bind the button-press-event signal instead.
Some links in case I go down that road:
- <https://docs.gtk.org/gtk3/signal.Widget.button-press-event.html>
- <https://docs.gtk.org/gdk3/union.Event.html>
- https://docs.gtk.org/gdk3/struct.EventButton.html
*/
// This API is deprecated in GTK4 :(
return 0;
}
@ -393,15 +346,12 @@ int main(int argc, char** argv)
/* Initialize GTK in general */
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>
GtkCssProvider* css = gtk_css_provider_new();
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);
/* Initialize GTK objects. These are declared as static globals at the top of this file */
// Notebook
notebook = GTK_NOTEBOOK(gtk_notebook_new());
gtk_notebook_set_show_tabs(notebook, false);
gtk_notebook_set_show_border(notebook, false);
gtk_notebook_set_show_tabs(notebook, 0);
gtk_notebook_set_show_border(notebook, 0);
// Window
window = GTK_WINDOW(gtk_window_new(0));
@ -427,11 +377,10 @@ int main(int argc, char** argv)
/* Show to user */
gtk_widget_show_all(GTK_WIDGET(window));
if (argc != 0) gtk_widget_hide(GTK_WIDGET(bar.widget));
gtk_notebook_set_show_tabs(notebook, 1);
/* 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]);
}

View File

@ -1,41 +0,0 @@
* {
font-size: 25px;
color: #333;
}
/* Make titlebar pretty gigantic. I'm pretty myopic. */
.titlebar {
padding: 10px;
font-size: 30px;
}
.titlebar * {
padding: 10px;
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,27 +0,0 @@
-I/usr/include/webkitgtk-4.0
-I/usr/include/glib-2.0
-I/usr/lib/glib-2.0/include
-I/usr/include/sysprof-4
-I/usr/include/gtk-3.0
-I/usr/include/pango-1.0
-I/usr/include/harfbuzz
-I/usr/include/freetype2
-I/usr/include/libpng16
-I/usr/include/libmount
-I/usr/include/blkid
-I/usr/include/fribidi
-I/usr/include/cairo
-I/usr/include/lzo
-I/usr/include/pixman-1
-I/usr/include/gdk-pixbuf-2.0
-I/usr/include/gio-unix-2.0
-I/usr/include/cloudproviders
-I/usr/include/atk-1.0
-I/usr/include/at-spi2-atk/2.0
-I/usr/include/at-spi-2.0
-I/usr/include/dbus-1.0
-I/usr/lib/dbus-1.0/include
-I/usr/include/libsoup-2.4
-I/usr/include/libxml2
-pthread

View File

@ -1,5 +0,0 @@
DEPS='webkit2gtk-4.0'
INCS=`pkg-config --cflags ${DEPS}`
LIBS=`pkg-config --libs ${DEPS}`
echo $INCS
echo $LIBS

View File

@ -1,42 +0,0 @@
# Key dependencies
sudo apt install git vim gcc make
sudo apt install libwebkit2gtk-4.1-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 build # or just make
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"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 739 KiB

View File

@ -1,9 +0,0 @@
#!/usr/bin/env xdg-open
[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Exec=/bin/rosenrot %u
Name=Rosenrot
Comment=Minimalistic browser
Icon=/opt/rosenrot/rosenrot-desktop-icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

View File

@ -1,37 +0,0 @@
@define-color Surface0 #313244;
@define-color Surface1 #45475a;
@define-color Base #1e1e2e;
@define-color Mantle #181825;
@define-color Lavender #b4befe;
@define-color Text #cdd6f4;
* {
padding: 0px;
margin: 0px;
outline-color: @Lavender;
color: @Text;
border-bottom-color: @Base;
}
window, notebook, headerbar {
background: @Base;
}
tabs {
background-color: @Base;
padding: 3px;
}
tab {
background-color: @Base;
margin: 5px;
}
entry {
background-color: @Surface0;
padding-left: 10px;
}
entry:focus {
box-shadow: none;
}

View File

@ -1,52 +0,0 @@
@define-color Surface0 #313244;
@define-color Surface1 #45475a;
@define-color Base #1e1e2e;
@define-color Mantle #181825;
@define-color Lavender #b4befe;
@define-color Text #cdd6f4;
* {
padding: 0px;
margin: 0px;
outline-color: @Lavender;
color: @Text;
border-color: white;
font-size: 16px;
/*@Base; */
/* border-bottom-color: @Base; */
}
window, notebook, headerbar {
background: @Base;
}
tabs {
background-color: @Base;
padding: 3px;
outline-color: white;
border-color: @Base;
}
tab {
background-color: @Base;
margin: 2px 5px 2px 0px;
padding: 5px;
border-style: solid;
/*border-color: white;
border-bottom-color: white;
outline-color: white;
margin: 5px;
padding-left: 10px;
padding-right: 10px; */
}
entry {
background-color: @Surface0;
padding-left: 10px;
}
entry:focus {
background-color: @Surface0;
padding-left: 10px;
}

View File

@ -1,70 +0,0 @@
@define-color Surface0 #313244;
@define-color Surface1 #45475a;
@define-color Base #1e1e2e;
@define-color Mantle #181825;
@define-color Lavender #b4befe;
@define-color Text #cdd6f4;
* {
padding: 0px;
margin: 0px;
outline-color: @Lavender;
color: @Text;
border-color: white;
font-size: 25px;
/*@Base; */
/* border-bottom-color: @Base; */
}
window, notebook, headerbar {
background: @Base;
}
/* Make titlebar pretty gigantic. I'm pretty myopic. */
.titlebar {
padding: 10px;
font-size: 30px;
}
.titlebar * {
padding: 10px;
font-size: 27px;
}
header * {
font-size: 20px;
padding: 5px;
}
tabs {
background-color: @Base;
padding: 3px;
outline-color: white;
border-color: @Base;
}
tab {
background-color: @Base;
margin: 2px 5px 2px 0px;
padding: 5px;
border-style: solid;
font-size: 27px;
/*border-color: white;
border-bottom-color: white;
outline-color: white;
margin: 5px;
padding-left: 10px;
padding-right: 10px; */
}
entry {
background-color: @Surface0;
padding-left: 10px;
}
entry:focus {
background-color: @Surface0;
padding-left: 10px;
}

View File

@ -1 +0,0 @@
Code in this directory refers to a previous version of rosenrot which used the libwebkit2gtk-4.0 api. It is deprecated. See the debian folder for how to use the -4.1 version instead. Package names might vary.

View File

@ -1,24 +0,0 @@
# Key dependencies
sudo apt install git vim gcc make
sudo apt install libwebkit2gtk-4.0-dev
# Optional adblock
git clone https://github.com/jun7/wyebadblock
cd wyebadblock
sudo apt install gstreamer1.0-plugins-good gstreamer1.0-libav
make
sudo make install
cd ..
mkdir -p ~/.config/wyebadblock
cd ~/.config/wyebadblock
wget https://easylist.to/easylist/easylist.txt
cd -
cd ../..
make build # or just make
sudo make install
cd -
# Ubuntu desktop icon
chmod +x rose.desktop
sudo cp rose.desktop /usr/share/applications

View File

@ -1,9 +0,0 @@
#!/usr/bin/env xdg-open
[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Exec=/home/nuno/Documents/workspace/rosenrot/user-scripts/ubuntu-20.04/rose.sh %u
Name=Rose
Comment=Minimalistic browser
Icon=/home/nuno/Documents/workspace/rosenrot/user-scripts/ubuntu-20.04/rose-images/rose-desktop-icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 625 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 739 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 KiB

View File

@ -1 +0,0 @@
<https://www.onlygfx.com/red-rose-png-image-transparent/>

View File

@ -1,9 +0,0 @@
#!/usr/bin/env xdg-open
[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Exec=/bin/rose %u
Name=Rose
Comment=Minimalistic browser
Icon=/home/nuno/Documents/workspace/rosenrot/user-scripts/ubuntu-20.04/rose-images/rose-desktop-icon.png

View File

@ -1,3 +0,0 @@
#!/bin/sh
GIO_MODULE_DIR=/usr/lib/x86_64-linux-gnu/gio/modules/ /bin/rose "$1"

View File

@ -1,9 +0,0 @@
In case you arrive at a segmentation fault when working on rose, you can use valgrind.
To do this, you can compile rose with the `DEBUG` value in `build.sh` set to `-g`
and then:
```
valgrind --track-origins=yes ./rose
```