Compare commits
4 Commits
ed76b7e9e7
...
e583fd0fd2
Author | SHA1 | Date | |
---|---|---|---|
e583fd0fd2 | |||
86989d878e | |||
db67b513d2 | |||
07cae73c71 |
115
README.md
|
@ -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
|
@ -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
|
@ -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 }
|
||||
};
|
||||
*/
|
||||
|
Before Width: | Height: | Size: 2.4 MiB |
Before Width: | Height: | Size: 257 KiB |
Before Width: | Height: | Size: 534 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 250 KiB |
Before Width: | Height: | Size: 198 KiB |
Before Width: | Height: | Size: 258 KiB |
Before Width: | Height: | Size: 123 KiB |
Before Width: | Height: | Size: 142 KiB |
Before Width: | Height: | Size: 474 KiB |
|
@ -1 +0,0 @@
|
|||
https://www.onlygfx.com/red-rose-png-image-transparent/
|
Before Width: | Height: | Size: 474 KiB |
Before Width: | Height: | Size: 111 KiB |
Before Width: | Height: | Size: 739 KiB |
82
makefile
|
@ -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
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
## About
|
||||
|
||||
This code automatically redirects webpage to their open-source frontends. It is based on <https://libredirect.codeberg.page/>
|
|
@ -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;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#define LIBRE_N 50
|
||||
|
||||
int libre_redirect(const char* uri, char* uri_filtered);
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
}
|
||||
}
|
|
@ -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"
|
|
@ -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)
|
||||
|
||||
|
|
@ -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>
|
||||
|
|
@ -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);
|
||||
}
|
||||
*/
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#define READABILITY_N 88067 + 1000
|
||||
|
||||
void read_readability_js(char* string);
|
|
@ -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"
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#define SHORTCUT_N 41
|
||||
|
||||
int shortcut_expand(const char* uri, char* output);
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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
|
||||
*/
|
|
@ -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);
|
|
@ -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.
|
|
@ -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"
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#define STYLE_N 7624 + 1000
|
||||
|
||||
void read_style_js(char* string);
|
|
@ -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";
|
|
@ -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
|
||||
}
|
257
rosenrot.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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:
|
||||
if (gtk_notebook_get_n_pages(notebook) == 0) {
|
||||
exit(0);
|
||||
break;
|
||||
case 1:
|
||||
gtk_notebook_set_show_tabs(notebook, false);
|
||||
break;
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
|
41
style.css
|
@ -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;
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
DEPS='webkit2gtk-4.0'
|
||||
INCS=`pkg-config --cflags ${DEPS}`
|
||||
LIBS=`pkg-config --libs ${DEPS}`
|
||||
echo $INCS
|
||||
echo $LIBS
|
|
@ -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"
|
Before Width: | Height: | Size: 739 KiB |
|
@ -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
|
Before Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 175 KiB |
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
Before Width: | Height: | Size: 625 KiB |
Before Width: | Height: | Size: 474 KiB |
Before Width: | Height: | Size: 739 KiB |
Before Width: | Height: | Size: 102 KiB |
Before Width: | Height: | Size: 142 KiB |
Before Width: | Height: | Size: 474 KiB |
|
@ -1 +0,0 @@
|
|||
<https://www.onlygfx.com/red-rose-png-image-transparent/>
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/sh
|
||||
GIO_MODULE_DIR=/usr/lib/x86_64-linux-gnu/gio/modules/ /bin/rose "$1"
|
||||
|
|
@ -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
|
||||
```
|