Compare commits

...

323 Commits

Author SHA1 Message Date
9136ab2565 small style tweak 2024-10-15 11:21:35 +02:00
1438d3037a fix CTRL | SHIFT to just CTRL 2024-09-19 22:56:15 +02:00
fdf688cba2 generalize filterByKeyword function 2024-09-19 16:45:54 +02:00
82584d6a59 don't show brave download button 2024-09-19 15:40:27 +02:00
5e3cab2a63 add custom filter command (Ctrl+F) 2024-09-19 15:16:15 +02:00
2a5f09ce7c tweak style
I thought I wanted to add something for the no domain case
(e.g., a document with file://) but I don't
2024-09-19 14:28:04 +02:00
7a54b7bd99 restore bloomberg -> archive.is redirection 2024-09-13 09:31:53 -04:00
b922d15f98 redlib.ducks.party => redlib.tux.pizza 2024-08-28 18:01:18 -04:00
c4a4a73302 tweak: rename variable name 2024-08-15 19:16:04 -04:00
708193f82a don't redirect bloomberg 2024-08-15 19:15:46 -04:00
459784029b add backup shortcut to open in a different browser 2024-07-28 19:14:05 -04:00
c3d627f922 remove old google.com frontend 2024-07-28 13:52:28 -04:00
9c2c34743f change keyboard shortcuts & update deprecated gtk command 2024-07-28 13:48:05 -04:00
20a0c15caa add shortcut to save current uri to a file 2024-07-24 12:58:54 -04:00
c3ac0c0333 fix some small typos 2024-07-22 21:59:00 -04:00
51287bc420 backport some small tweaks to rosenrot3.c & cleanup 2024-07-22 21:54:36 -04:00
56ed98703d formatting pass 2024-07-22 21:14:15 -04:00
bdfddd3a3a more fengshui 2024-07-22 19:29:15 -04:00
b138c2c83a fengshui & add resize window shortcut 2024-07-22 19:04:39 -04:00
db9d3e66f2 GTK4: fix duplicate loading error when opening new tabs 2024-07-21 14:54:32 -04:00
e03b6cc447 re-enable custom page styles again 2024-07-21 11:29:08 -04:00
258aa8dd3c GTK4: Continue updating, tweak makefile 2024-07-21 11:17:43 -04:00
6fd0a9e40f GTK4: cleanup extra files &c. 2024-07-21 11:17:40 -04:00
3294947ad4 GTK4: savepoint 2024-07-21 11:17:39 -04:00
d7781d308d GTK4: formatting pass 2024-07-21 11:17:38 -04:00
db4f980af9 GTK4: More tweaks, e.g., don't show tabs if only one 2024-07-21 11:17:37 -04:00
b2d518e184 GTK4: restore most functionality 2024-07-21 11:17:36 -04:00
6f6a327aa6 GTK4: Add webview settings back 2024-07-21 11:17:33 -04:00
d2d74b3ef9 GTK4: Continue buffing up GTK4 version
Also, some of the webview configs were caused by the
custom user agent!!
Note from rebasing later: Nope, caused by the custom *css*
2024-07-21 11:17:16 -04:00
418cb6f150 GTK4: Use toggle_bar function to focus on bar when toggled. 2024-07-21 11:17:14 -04:00
37d00ae8ee GTK4: add signal for top bar enter 2024-07-21 11:17:12 -04:00
0f8885995a GTK4: buff up features again. 2024-07-21 11:17:07 -04:00
e85c727798 GTK4: add another file, rosenot4_beta.c to continue development 2024-07-21 11:16:58 -04:00
ad840fe91d GTK4: bypass bug by directly adding signal listener to webview
It took me a while to arrive at this solution. Sad that I can't come up
with anything better
2024-07-21 11:16:16 -04:00
d03dbede60 GTK4: Try to isolate keypress signal bug 2024-07-21 11:16:14 -04:00
7f1074b318 GTK4: try to isolate signal bug 2024-07-21 11:16:12 -04:00
42d09714a8 GTK4: savepoint, insidious bug somewhere 2024-07-21 11:16:09 -04:00
143b6c76d8 GTK4: add a few debug statements 2024-07-21 11:16:06 -04:00
6f3f56c604 GTK4: try diagnosing again 2024-07-21 11:16:05 -04:00
61a1d4f0f3 GTK4: savepoint before trying to figure out signals 2024-07-21 11:16:03 -04:00
c716e6b5c5 GTK4: Fix bar visiblity shortcuts 2024-07-21 11:16:01 -04:00
83e80a7dda GTK: Savepoint with most functionality (except css) 2024-07-21 11:15:59 -04:00
4902ed2398 GTK4: GTK_WINDOW(window) => window 2024-07-21 11:15:57 -04:00
cbbb5fe83c GTK4: Try switching type of GTK window 2024-07-21 11:15:55 -04:00
ac0cd38fea GTK4: savepoint 2024-07-21 11:15:54 -04:00
4ce1a4265e GTK4: add other functions 2024-07-21 11:15:53 -04:00
d19fd76a0c GTK4: handle signal bar press enter 2024-07-21 11:15:52 -04:00
805fd6d45a GTK4: add top bar 2024-07-21 11:15:51 -04:00
6f98d00f28 GTK4: Get shortcuts working. 2024-07-21 11:15:49 -04:00
db4fe9a0cf GTK4: formatting pass 2024-07-21 11:15:46 -04:00
3ac35677a5 GTK4: Now able to capture keypresses!! 2024-07-21 11:15:41 -04:00
b2793329c8 GTK4: formatting pass 2024-07-21 11:15:37 -04:00
4f3a90daaf GTK4: Add a few more niceties 2024-07-21 11:15:35 -04:00
e124f5c561 GTK4: Add forward declarations, uncomment some other stuff. 2024-07-21 11:15:34 -04:00
2c5129ccaa GTK4: Greenfield loads both URI and notebook! 2024-07-21 11:15:31 -04:00
d069578e61 GTK4: add a few structs to greenfield file 2024-07-21 11:15:29 -04:00
e6c1913f0d GTK: continue GTK4 greenfield restart 2024-07-21 11:15:23 -04:00
6e7966b3b3 GTK4: start building similar thing through scratchpad 2024-07-21 11:15:20 -04:00
a7e0a98b1d GTK4: savepoint for the day 2024-07-21 11:15:13 -04:00
bf23c75dfd GTK4: get to state where GTK error doesn't show 2024-07-21 11:15:09 -04:00
4155862a6a GTK4: start deleting stuff to see where the gtk error comes from 2024-07-21 11:15:06 -04:00
d09bb0d51d GTK4: try fixing signals 2024-07-21 11:15:03 -04:00
b1adaef7e3 GTK4: get gtk4 to compile.
... but dimensions are not working, and neither are shortcuts
2024-07-21 11:15:00 -04:00
68b6d1cdb6 GTK4: use gtk_widget_set_visible instead of show_all/hide 2024-07-21 11:14:58 -04:00
90521e0a18 GTK4: web_context => network_session 2024-07-21 11:14:54 -04:00
f44bd92891 GTK4: add missing semicolon :^| 2024-07-21 11:14:40 -04:00
80e7e576c2 GTK4: gtk_css_provider_load_from_path fix 2024-07-21 11:14:38 -04:00
6c6c84ec3b GTK4: fix another gtk error 2024-07-21 11:14:35 -04:00
20a5699818 GTK4: start solving gtk4 errors 2024-07-21 11:14:31 -04:00
84d35b197d GTK4: split into 2 files rather than using #if guards 2024-07-21 11:14:15 -04:00
286dc05d45 GTK4: gkg.h => gtk; k => t.
gkg is lower level
2024-07-21 11:13:38 -04:00
bb9ff083b3 GTK4: validate compilation with gtk3 2024-07-21 11:13:32 -04:00
de1e608d06 GTK4: start trying to compile with gtk4 2024-07-21 11:13:19 -04:00
1c9fbe1122 quality of life tweaks, particularly around x.com 2024-07-20 17:25:54 -04:00
a0f79388e9 extend twitter.com style to x.com, as it sometimes redirects 2024-06-12 07:40:59 -04:00
126fdc32fd change height for new computer 2024-06-09 23:55:12 +02:00
40da9afd4d make makefile slightly prettier, update invidious frontend 2024-05-09 14:20:52 +01:00
10fca6af34 update redirects 2024-05-09 10:33:12 +01:00
15451be030 add forecasting newsletter shortcut 2024-04-28 19:48:40 +02:00
80424d2854 passthrough for toggle custom style switch 2024-04-14 09:14:58 -04:00
f5a03f4d05 formattign pass 2024-04-14 09:00:54 -04:00
99ad21b850 organize shortcuts a bit better 2024-04-14 08:56:03 -04:00
8aa43e81fc add custom style toggle 2024-04-14 08:53:45 -04:00
c4581f3fd5 redirect reddit + vitalik buterin's website 2024-03-29 16:40:13 -04:00
7d6c478c9c fix off by one error when adding https:// to url 2024-03-29 14:13:32 -04:00
9cb8bd5818 tweak: restore hover behaviour 2024-03-29 14:13:13 -04:00
0e3956fea1 mark to-do, add two types of page down 2024-03-25 15:14:54 -04:00
c95ed11bc3 specify c99 2024-03-24 07:54:33 -04:00
0c282697bc simplify link references 2024-03-24 07:45:21 -04:00
70849e74d6 don't show brave donwload button 2024-03-24 07:44:44 -04:00
136ad04678 tweaks: readd adblock, refactor toggle_bar, simplify 2024-03-24 07:07:29 -04:00
a1a22bb282 tweak home 2024-03-23 23:34:12 -03:00
3aa9e5fa39 tweak pointer to min branch 2024-03-23 23:33:25 -03:00
0556d10bb8 add pointer to min branch 2024-03-23 22:59:09 -03:00
875b6fec05 remove unneeded config options 2024-03-23 22:32:50 -03:00
ed76b7e9e7 change home directory 2024-03-23 21:46:28 -03:00
18ac2627ad tweaks 2024-03-23 18:18:20 -03:00
cbc9d35811 remove dead code 2024-03-23 17:56:24 -03:00
e322621698 tweak usage of str replacement code 2024-03-23 17:54:15 -03:00
5097a1982b formatting & tweaks pass 2024-03-23 17:48:42 -03:00
978c7ca1cc change formatting + refactor string code 2024-03-23 17:35:44 -03:00
c8ff246cc2 remove extraneous tmp vars in libre_redirect 2024-03-23 16:58:23 -03:00
43cac7f3f1 simplify libre_redirect code 2024-03-23 16:46:28 -03:00
8f4b4b9abf formatting/syntax tweaks
in particular, for switch cases which declare const, use a new block
2024-03-23 16:26:26 -03:00
f2e06785f9 Add https automatically if url contains .com or .org
also delete extraneous shortcut
2024-03-23 16:18:00 -03:00
b4c3e3a0e3 add anna's archive shortcut 2024-03-23 11:14:29 -03:00
8707adb983 don't save binary file 2024-03-22 10:54:31 -03:00
dbf1146bc2 change invidious frontend 2024-03-22 09:40:21 -03:00
e98f5e9b29 fix pageup/pagedown shortcuts 2024-03-22 09:38:13 -03:00
5c56652e87 refactor toggle bar code. 2024-03-22 07:48:49 -03:00
38eee1eb44 rework style code to use a switch statement 2024-03-21 08:47:57 -03:00
8829166139 reorg custom style code again 2024-03-21 08:40:09 -03:00
71751283e1 update default search engine 2024-03-21 08:29:47 -03:00
a1f4b0604f add nationstates css snippet; reformat css 2024-03-21 08:29:13 -03:00
386941e51e update archive.today to archive.is 2024-03-20 04:18:51 -03:00
a7192d5e5c typos & use /opt/rosenrot folder 2024-03-17 21:31:11 -03:00
af4184c664 tweaks personal usage 2024-03-16 07:57:32 -03:00
8a091dd1bf remove custom forum style, add twitter shortcut 2024-03-15 17:56:33 -03:00
7eaa3fc29b Write down shortcuts problem 2024-03-15 08:58:37 -03:00
7fc771eaad tweak bottom margin 2024-03-14 21:42:46 -03:00
ca016f5a6d update rosenrot desktop file 2024-03-14 21:20:09 -03:00
cf1e9bb911 Fix case where rosenrot is called with url arg 2024-03-14 21:05:56 -03:00
6fbcb549fd formatting pass 2024-03-14 19:38:20 -03:00
6a2c4c9084 small makefile tweaks 2024-03-14 19:33:52 -03:00
af208844b5 reorg makefile and make runtime locations less messy
In particular, stop using the installation directory for anything
and instead move to /opt/rosenrot

The user specific cache remains at /home/user/.cache
2024-03-14 19:31:04 -03:00
878d6a890b change images 2024-03-14 16:37:18 -03:00
e9950d648a make initial page blank 2024-03-14 16:31:07 -03:00
6d925ea23a remove most custom style (but leave large font)
gtk default already looks amazing
2024-03-14 16:05:54 -03:00
0f2ca9b9f7 document how to add a shortcut in Debian 2024-03-14 16:00:10 -03:00
a66bcf5840 add README clarification about updating apis 2024-03-14 15:49:55 -03:00
d5dda17b48 remove outdated line in README 2024-03-14 15:48:40 -03:00
d6456e4357 cleanup & change binary name to rosenrot 2024-03-14 15:47:36 -03:00
94326a8cad minor tweaks 2024-03-14 15:16:47 -03:00
d63ccd10cf formatting pass 2024-03-14 14:59:27 -03:00
9a27469a52 cleanup makefile slightly, restore ubuntu-20.04 files 2024-03-14 14:58:59 -03:00
e75605959e cleanup & add list of similar projects 2024-03-14 14:53:37 -03:00
ed8f2dd230 compile adblock with newer webkit 2024-03-12 16:11:26 -03:00
da776bebc4 finish webkit update & update readme 2024-03-12 16:01:31 -03:00
ce1ad43ac2 remove extraneous rgba visuals code 2024-03-12 15:12:12 -03:00
d9d18bf7f3 gtk3 to gtk4: don't access GdkEvent fields directly 2024-03-12 15:10:20 -03:00
4663cb3a70 gtk3 to gtk4: notes on transition 2024-03-12 14:46:41 -03:00
bb9d791a62 get shortcuts working again 2024-03-12 14:40:50 -03:00
8907cbb063 formatting pass 2024-03-12 14:16:29 -03:00
0f940a7460 webkit upgrade: remove deprecated opts and change variable names.
References for the removed opts:

https://webkitgtk.org/reference/webkit2gtk/stable/property.WebContext.local-storage-directory.html?q=
https://webkitgtk.org/reference/webkit2gtk/stable/property.WebsiteDataManager.disk-cache-directory.html
https://webkitgtk.org/reference/webkit2gtk/stable/property.WebsiteDataManager.indexeddb-directory.html
https://webkitgtk.org/reference/webkit2gtk/stable/property.WebsiteDataManager.service-worker-registrations-directory.html
https://webkitgtk.org/reference/webkit2gtk/stable/property.WebsiteDataManager.itp-directory.html
https://webkitgtk.org/reference/webkit2gtk/stable/property.WebsiteDataManager.hsts-cache-directory.html
2024-03-12 14:13:47 -03:00
641b4055c2 remove inert function call
See:
<https://webkitgtk.org/reference/webkit2gtk/stable/method.WebContext.set_process_model.html>
2024-03-12 13:55:44 -03:00
97032cd83c webkitgtk update: replace run_javascript function 2024-03-12 13:53:45 -03:00
3bf48009d1 update webkit dep to 4.1 in makefile 2024-03-12 13:37:28 -03:00
79ff9e86f5 start transition to webkitgtk-6.0 2024-03-12 13:32:34 -03:00
8a1e0be30d tweak README 2024-02-12 00:16:25 +01:00
c52f203e21 tweak README 2024-02-12 00:07:17 +01:00
4e7f546d3c tweak README, extract TODO to separate file 2024-02-12 00:00:05 +01:00
e52293d78a tweak README to add architecture, tweak makefile to make fast. 2024-02-11 22:13:53 +01:00
d2e210c56a move images, add architecture image 2024-02-11 21:28:20 +01:00
bddfb5bfc8 add local -march=native compilation option 2024-02-11 19:00:04 +01:00
e3d5757e2a add note about other compilers 2024-02-11 18:33:02 +01:00
0f5baf1129 formatting pass. 2024-02-11 18:25:46 +01:00
e5e194f1eb remove unneeded function call, reorder. 2024-02-11 18:23:04 +01:00
b5801975d4 fix custom css bug 2024-02-11 18:10:55 +01:00
e1fc467795 remove repeated code. 2024-02-11 18:06:41 +01:00
59b174e4bb small reorg 2024-02-11 18:01:51 +01:00
ca9d1004ed continue reorg 2024-02-11 17:26:20 +01:00
312f99c6f2 rename notebook_append to notebook_create_new_tab
Also add note on README about static files
2024-02-11 17:15:24 +01:00
f6a65b066e rename "keys" to shortcuts, put bar functions together 2024-02-11 17:14:01 +01:00
5e42ab4b00 move plugins code to config.h 2024-02-11 16:58:35 +01:00
cdf35fa832 make signal code more self evident. 2024-02-11 16:57:06 +01:00
d4847b1525 start making initializations less messy. 2024-02-11 16:29:36 +01:00
605b5ade22 simplify bar struct slightly. 2024-02-11 16:22:14 +01:00
4ad9d35ee8 put all bar stuff into the same struct. 2024-02-11 16:15:18 +01:00
70e8cb880e simplify plugins code a bit. 2024-02-11 15:56:53 +01:00
afe93518a9 update bar_entry_mode declaration to one liner 2024-02-11 15:47:38 +01:00
90fef3b468 refactor bar variable names 2024-02-11 14:08:19 +01:00
d8522eb827 remove stdbool from rose.c, as already in config.h 2024-02-11 13:59:44 +01:00
31f26f7540 rationalize config.h a bit 2024-02-11 13:58:38 +01:00
9113aac957 some code simplification
- don't have main and "setup" as two separate functions
- declare all global variables at the same time
2024-02-11 13:52:38 +01:00
2896ff4e52 remove change in colors for twitter 2024-01-18 16:15:41 +01:00
c33fc76b02 add cycling through tabs 2024-01-06 16:30:09 +01:00
da8a0d7624 add pointer to capturing mouse events. 2023-12-29 18:51:07 +01:00
75848c63a2 formatting + remake pass 2023-12-29 18:38:54 +01:00
c344180055 reorder argument order 2023-12-29 18:38:29 +01:00
6ed0181a0c fix F11 screen toggling 2023-12-29 18:37:50 +01:00
f2535db66f recompute after changing style 2023-11-28 16:31:14 +00:00
a2c465f504 remove hover from twitter 2023-11-28 16:30:56 +00:00
a2f5a864bf more twitter tweaks 2023-11-22 20:41:21 +00:00
292a3f6761 undo some tweaks 2023-11-20 11:04:32 +00:00
6a3581b7e0 tweak: more twitter tweaks 2023-11-20 10:54:40 +00:00
39bb8510c1 tweaks: more twitter tweaks 2023-11-20 01:03:01 +00:00
f280b6f0f8 more twitter style tweaks 2023-11-20 00:50:27 +00:00
ca5f731912 tweaks: change twitter css style 2023-11-20 00:29:44 +00:00
a590cc708d check out that ubuntu 20 installation files also work with debian 12 2023-11-14 22:42:47 +00:00
c90c819268 tweak search bar size to be smaller 2023-11-14 22:37:57 +00:00
7e23aad95f tweak: savepoint 2023-11-09 10:13:11 +00:00
0ba87b8cdc savepoint: add functionality to not show twitter videos 2023-11-08 23:24:06 +00:00
a7c1f8f57e try mutation listener + formatting step 2023-11-08 23:18:55 +00:00
152445c6d7 try event listener (didn't work) 2023-11-08 23:18:10 +00:00
09c9c50406 tweak: replace search engine + avoid twitter videos 2023-11-08 23:00:31 +00:00
4d94d2d2e6 rename WEBKIT_SETTINGS var to not conflict with webkitgtk 2023-10-06 15:55:37 +01:00
32a23e9a17 formatting pass 2023-10-06 15:45:47 +01:00
fb340ed3fa feat: add uft-8 encoding as default setting 2023-10-06 15:44:26 +01:00
568c039895 recompute constants after prettier pass 2023-09-15 12:41:48 +03:00
f75442ac2b prettier pass on style.js 2023-09-15 12:41:31 +03:00
58b522be65 prettier pass. 2023-09-15 12:40:50 +03:00
2ce2830351 in readability, center images and add max-width. 2023-09-15 12:40:27 +03:00
aaeb755c64 archive.is => archive.today 2023-08-30 22:11:59 +02:00
799e4c4ab7 fix code path error detected by clang-tidy. 2023-08-19 19:45:25 +02:00
67b46c6420 Add clang-tidy linting, callable with make lint. 2023-08-19 19:37:30 +02:00
aec21c71a6 tweaks: add code to block twitter ads 2023-08-03 14:41:03 +02:00
cd2b6a3257 tweak: change cache path in config.h 2023-08-01 11:37:34 +02:00
d65dc93af7 tweak twitter css 2023-07-27 17:36:04 +02:00
b87693e4c5 use -O3 -Wall gcc flags, add old.reddit.com css 2023-07-27 14:34:16 +02:00
e2c81f2595 add genius frontend. 2023-07-25 12:47:13 +02:00
0253c5e80a reworded misdiagnosed Espanso issue, added another redirection. 2023-07-12 14:44:56 +02:00
d17fb92bb6 small tweaks 2023-06-26 11:26:53 +01:00
eefa3cfb45 restore rose homepage. 2023-06-26 11:01:19 +01:00
16d43ac601 fix libreredirect, use true user agent. 2023-06-25 23:22:15 +01:00
4784a0ad26 changes to protonmail style; semicolon to hide bar. 2023-06-20 08:30:36 -06:00
3beef82ca6 add newline in shortcut expand message. 2023-06-20 07:14:52 -06:00
38cee8fd24 change keybinding to not overlap with my own shortcut 2023-06-20 05:19:55 -06:00
5b1aab5e0c time how long it takes to add the alert (negligible) + readme 2023-06-17 00:40:05 -06:00
98f6d5630f alerts v2, formatting 2023-06-17 00:29:27 -06:00
1cf68bb1fe custom alert first pass, with GPT-4 help 2023-06-17 00:19:29 -06:00
a24af4aad1 change max num tabs to 10 2023-06-10 20:14:10 -06:00
8d2811c5f9 add max number of tabs 2023-06-10 20:11:19 -06:00
995f455ece revert to full width 2023-06-04 19:16:34 -06:00
28a28b491d tweaks, add private royalroad frontend. 2023-06-04 19:11:45 -06:00
c08c4f48de add pointer to half width 2023-05-19 18:37:27 -04:00
8dc67aaa16 Revert "css tweaks; to be reverted"
This reverts commit 84df2273eb.
2023-05-15 12:11:34 -04:00
84df2273eb css tweaks; to be reverted 2023-05-15 12:11:21 -04:00
6ef555fc44 small README tweaks. Also Ctrl+K for hiding top bar! 2023-05-15 11:33:12 -04:00
a8be16b1ee debug shortcuts plugin 2023-05-13 23:50:14 -04:00
c46e2ba398 incorporate shortcuts plugin into rose.c and makefile 2023-05-13 23:26:39 -04:00
5fb7e79ad5 feat: add shortcuts plugin 2023-05-13 23:24:34 -04:00
49a005f929 tweak: add another screenshot 2023-05-13 00:07:20 -04:00
c2bffc09ce tweak: give some love to the README. 2023-05-12 00:56:16 -04:00
00d498851c make tabs larger, document. 2023-05-08 23:02:33 -04:00
98114362d9 feat: make search bar gigantic, document GTK inspect. 2023-05-08 22:48:22 -04:00
85942a60bd tweak: update simply translate endpoint 2023-05-07 11:53:51 -04:00
574cdd30ce tweak: remove twitter from redirection blacklist
+ tweak styles.
2023-05-05 20:08:53 -04:00
230f472e3a tweak: try ignoring twitter 2023-05-05 19:42:19 -04:00
5331760a83 start keeping track of rose binary 2023-05-03 22:22:55 -04:00
6ae0811000 readme clarification 2023-05-03 22:22:38 -04:00
3734dcd2d1 document bug fix after breaking library installation paths on my machine 2023-05-03 22:14:46 -04:00
4e3bb826ba tweak: add redirection google -> whoogle 2023-05-03 18:02:49 -04:00
0ba58087e0 tweak: savepoint 2023-04-29 18:33:09 -04:00
52aacc6dac fix: bug with make and cd not working as expected 2023-04-21 21:31:11 -04:00
b129954d4d feat: improve compilation a bit.
- tcc -> gcc (noticeably faster compilation)
2023-04-21 19:19:11 -04:00
b32749aa6e fix: zoom + forum.nunosempere.com, Matt Levine's newsletter 2023-04-21 19:08:55 -04:00
a4f8ad8ae2 tweak: continue cat and mouse chase with Matt Levine newsletter 2023-04-21 09:44:33 -04:00
f8b4e9ff4a feat: use my own instance of whoogle search
Tried duckduckgo for a while, but loss in quality was noticeable.
2023-04-08 20:54:07 -04:00
17ff6bb780 feat: integrate new ea forum frontend. 2023-04-07 16:51:25 -04:00
f1982d015d feat: add video to README, fix install typos. 2023-03-28 22:50:18 -06:00
9202a1f9b2 fix: fix makefile typo 2023-03-28 22:27:02 -06:00
b49a808739 feat: makefile handles git and cache paths 2023-03-28 22:07:25 -06:00
fc9cc67538 tweak: add some to-dos to readme 2023-03-28 21:43:30 -06:00
b125b26891 tweak: tweak ubuntu 20.04 install instructions. 2023-03-28 21:12:12 -06:00
33b30cfe05 fixes: fix bugs found when running in a virtual machine 2023-03-28 13:25:32 -06:00
dbc334e870 chore: more cleanup 2023-03-28 12:01:08 -06:00
b2bc83ce80 tweak: add more TODOs to readme 2023-03-28 11:53:30 -06:00
ce069bdd73 tweak: add make uninstall, make clean 2023-03-28 11:44:54 -06:00
0b9386f5fe chore: add installation section to README.md 2023-03-28 11:42:59 -06:00
20d0becba9 chore: more upkeep. In particular, document wyebadblock better 2023-03-28 11:32:47 -06:00
37e3e7bcae tweak: delete config.def.h
it's a bit redundant, and no longer necessary once compatibility
with the original rose is no longer a goal
2023-03-28 11:19:55 -06:00
bbcf1dabd2 Revert "tweak: move things around"
This reverts commit ca59138a2a.
2023-03-28 11:19:11 -06:00
ca59138a2a tweak: move things around 2023-03-28 11:18:54 -06:00
cc959fda4f chore: more simplifications 2023-03-28 11:16:51 -06:00
18f4e3e3cb tweak: add formatter to makefile 2023-03-28 11:11:18 -06:00
1fca042b0b tweak: add rudimentary makefile 2023-03-28 10:59:38 -06:00
3483af0f0f style: enforce webkit style for plugins
$ clang-format -style=webkit -i */.c
$ clang-format -style=webkit -i */*/.c
2023-03-28 10:16:14 -06:00
ec97a8f3f3 style: start enforcing coding style
Previous .clang-format wasn't processed

$ clang-format -style=webkit -dump-config > .clang-format
$ clang-format -i rose.c
2023-03-28 10:14:13 -06:00
527d88efa6 Revert "tweak: resize screenshots"
This reverts commit 06a0d6d808.
2023-03-27 19:45:41 -06:00
aeb196837e Revert "tweak: resize screenshots again?"
This reverts commit bb4ba366ee.
2023-03-27 19:44:09 -06:00
bb4ba366ee tweak: resize screenshots again? 2023-03-27 19:43:19 -06:00
06a0d6d808 tweak: resize screenshots 2023-03-27 19:41:57 -06:00
1eb9f98dc8 tweak: change readme to point to screenshots 2023-03-27 19:37:35 -06:00
42c7565b7f tweak: save screenshots 2023-03-27 19:36:27 -06:00
7cecf5ae3a fix: rename filepath after dirchange 2023-03-27 19:34:01 -06:00
49df138b36 feat: rename after very strong simplification on the upstream rose
Compare with: <https://github.com/NunoSempere/rose-browser/tree/patch-1>
in Feb 7
2023-03-27 19:21:56 -06:00
ff033646cc tweak: add changes to README 2023-03-27 19:08:46 -06:00
0f4866f520 tweak: add tweak to remove annoying parts for Money Stuff 2023-02-27 15:29:30 -06:00
53cc700748 tweak: add custom user agent. 2023-02-15 20:34:17 +01:00
bcaad22c17 tweak: fihnish the readability upgrades for bloomberg 2023-02-15 18:46:07 +01:00
25dedb09e1 tweaks: around bloomberg webpage 2023-02-15 03:24:47 +01:00
a27b4357af tweak: add fancy quotes. 2023-02-15 03:23:57 +01:00
6a330e9b09 tweak: nicer blockquotes
also fix bug in archive.is / bloomberg.
2023-02-14 02:07:23 +01:00
86fef30c22 tweak: proton stylesheet 2023-02-11 14:40:42 +01:00
95829b06a2 tweak: tweak. desktop so that it opens links correctly 2023-02-09 16:31:33 +01:00
4f43648a84 tweak: update README 2023-02-08 14:31:28 +01:00
c10b7632eb feat: add possibility of launching many tabs at once.
also, personalize this:
- enable extensions
- change to my css
- change relative paths.

fix various bugs:
- set the zoom level in notebook_append, not in notebook_init
- have a handly debug option for valgrind
2023-02-08 14:29:36 +01:00
2db650d7cc tweak: enable all plugins. 2023-02-07 14:43:00 +01:00
33e4d0cdd1 tweak: todos 2023-02-07 14:41:58 +01:00
d1439d16f5 tweak: continue personal development from master. 2023-02-07 14:28:21 +01:00
b50d30851b fix: fix some warts
- stuff to deal with plugin code wasn't actually compiling
  - created a "stand_in" plugin to provide headers and function
definitions
  - when these are not used
  - it is likely there are better approaches here
- hidebar, newtab -> hide_bar, new_tab
2023-02-07 14:17:10 +01:00
fenze
35f968f29b
Merge pull request #38 from NunoSempere/patch-1
Tweak license mention in the readme
2023-02-07 12:49:54 +01:00
fenze
1ba5fd7ecd
Merge pull request #39 from davidovski/shell_fix
Remove bash-only features for sh scripts
2023-02-07 12:48:14 +01:00
davidovki
122437115d Remove bash-only features for sh scripts
Fix order of CC arguments to aid in linking on newer versions
2023-02-07 11:37:05 +00:00
08c19abc1d
Tweak license mention in the readme 2023-02-06 18:17:46 +01:00
fenze
4e0b961fcb
Merge pull request #37 from mini-rose/add-license-1
Create license
2023-02-06 18:09:16 +01:00
fenze
5b958d5faf
Create license 2023-02-06 18:08:24 +01:00
fenze
327344ee40
Merge pull request #36 from NunoSempere/feats-and-tweaks
Various feats and tweaks
2023-02-06 18:05:33 +01:00
b48c504871 feat: use flags rather than uncommenting code
- Significantly simpler
- Easier for me to keep up with upstream
- Alternatives:
  - Comments as before
  - git patches, as in the suckless community: eventually leads to
confusion about conflicting patches.
  - some other option
2023-02-05 03:57:29 +01:00
cbaa97a766 tweak: add shebangs. 2023-02-05 03:23:23 +01:00
353d0ffad7 feat: add plugin to customize css for individual websites...
and how to enable it.

Also tweak README.mds
2023-02-05 03:21:30 +01:00
be043958f0 feat: add readability mode, and explain how to enable it. 2023-02-05 03:13:12 +01:00
9a533b7e26 feat: disable plugins code by default and explain how to enable it. 2023-02-05 03:02:03 +01:00
6b3c830c3b tweak: add two style improvements that I consider unambiguous
1. Make top tab wider
2. Make tab title have a maximum width
2023-02-05 02:52:27 +01:00
4fd1c83660 tweak: add alternatives styles.css
also keep track in README of steps.
2023-02-05 02:48:25 +01:00
e928ee1c89 feat: add open in new tab functionality
for <a href=_blank... links, and when clicking on a link,
sometimes you want to open that link in a new tab.

This commit adds that functionality.
2023-02-05 02:31:57 +01:00
fenze
584a5d68a8 Fixed formatting in some libre_redirect files 2022-12-18 16:54:07 +00:00
fenze
d97045bf47 Add hidebar keybind 2022-12-18 16:42:50 +00:00
fenze
3325e17195
Merge pull request #32 from NunoSempere/ubuntu-20.04-scripts
tweak: add user scripts to get this running on ubuntu 20.04
2022-12-18 16:27:54 +00:00
fenze
b16665809c
Merge pull request #33 from NunoSempere/libre_redirect
feat: redirect websites to open-source frontends
2022-12-18 16:27:20 +00:00
f5d1c0f93d tweak: integrate "plugins" into build.sh 2022-12-17 20:54:47 +01:00
98abdb39c4 feat: integrate libre_redirect code into rose.c 2022-12-17 20:54:27 +01:00
6ff86dcc44 feat: redirect websites to open-source frontends
1. Adds code for redirecting annoying websites to their open-source
frontends, when these exist.

2. Organize this in a "plugins" folder
2022-12-17 20:47:44 +01:00
7ad3e023f8 tweak: add user scripts to get this running on ubuntu 20.04
I thought these might be useful. Feel free to not accept them,
though
2022-12-17 20:33:37 +01:00
fenze
62b1bd6785 Add newtab binding 2022-12-16 09:07:43 +00:00
fenze
055e50c9ef
Merge pull request #31 from NunoSempere/upstream
Some quality of life tweaks.
2022-12-13 18:15:35 +00:00
981c15bf93 feat: add less sucky duckduckgo homepage. 2022-12-13 16:33:04 +00:00
5ab887db47 trivial tweak: fix README layout error. 2022-12-13 15:31:36 +00:00
f6119ff7db tweak: Add reference to how to use normal browser controls. 2022-12-13 15:22:49 +00:00
5e403cad14 fix: small sh/bash incompatibility in rose-mklink
'echo -e' throws a warning in sh, but not in bash
2022-12-12 22:10:49 +00:00
1bed196381 tweak: suggest bg color for bright theme 2022-12-12 15:44:48 +00:00
a69d72f42b tweak: allow configurable width and height
and set a default of 500, 400
2022-12-12 15:38:48 +00:00
374128fccc tweak: boot up with the correct zoom 2022-12-12 15:37:31 +00:00
81 changed files with 6910 additions and 484 deletions

View File

@ -1,37 +0,0 @@
# vim:ft=yaml
IndentWidth: 8
BreakBeforeBraces: Linux
UseTab: Always
AlignArrayOfStructures: Left
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: True
AlwaysBreakBeforeMultilineStrings: True
BreakBeforeTernaryOperators: True
BreakStringLiterals: True
ColumnLimit: 100
IncludeBlocks: Regroup
KeepEmptyLinesAtTheStartOfBlocks: True
RemoveBracesLLVM: True
SortIncludes: CaseInsensitive
SortUsingDeclarations: True
SpaceAfterLogicalNot: True
SpaceAfterCStyleCast: True
SpaceAfterTemplateKeyword: False
PointerAlignment: Right
SpaceBeforeAssignmentOperators: True
SpaceBeforeCaseColon: False
SpaceBeforeCpp11BracedList: True
SpaceBeforeCtorInitializerColon: False
SpaceBeforeInheritanceColon: False
SpaceBeforeParens: Custom
SpaceBeforeParensOptions:
AfterControlStatements: True
AfterForeachMacros: True
AfterFunctionDeclarationName: False
AfterFunctionDefinitionName: False
AfterIfMacros: True
AfterOverloadedOperator: False
BeforeNonEmptyParentheses: False
SpaceBeforeRangeBasedForLoopColon: True

6
.gitignore vendored
View File

@ -1,3 +1,3 @@
rose
config.h
.clang-format
rosenrot
# don't save the binary file, as it doesn't play nicely with https://difftastic.wilfred.me.uk
webkit/

132
README.md
View File

@ -1,21 +1,117 @@
<h3 align=center> Rose Browser</h1>
<h4 align=center>Minimal browser based on webkit2gtk</h4>
# Rosenrot
#### Features
- tabs, cookies, caching
- minimal ui, autohiding elements
- ~400L code base
- custom gtk and websites css
- hackable without any knowledge
- builtin rose-mklink script for in-shell static links
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. Because of the ease of hackability, the minimalism, the unobstrusiveness, it gives me a more comfortable way of navigating the web than normal browsers.
#
### 👐 Contribute
See [contributing.md](https://github.com/mini-rose/rose/.github/contributing.md).
![](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/), for Debian 12 in particular—though they should generalize easily to other distributions.
The general steps are to install dependencies, and then
```
make build # by default using webkitgtk6/gtk4; see also build3
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
- For now, both GTK3 and GTK4-based versions—eventually only the GTK4 version will remain
You can see some screenshots in the [images](./images) folder.
## 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/LadybirdBrowser/ladybird). Initially from the InitialSerenityOS, it later became its own project. Uses its own html and javascript engine. Compiling it on a mainstream linux distribution is now doable.
- [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).
- Rosenrot is my (@NunoSempere's) fork from that earlier minimal rose, the GTK 3 version. It has accumulated quality of life features and, honestly, cruft, that I like, like a "readability" plugin that simplifies annoying websites like [Matt Levine's Money Stuff newsletter](https://www.bloomberg.com/opinion/articles/2022-10-18/matt-levine-s-money-stuff-credit-suisse-was-a-reverse-meme-stock). It also incorporates ad-blocking.
- rose updated to allow compilation with an up-to-date version of webkit on both GTK3 and GTK4 earlier, though rosenrot now offers this as well.
- 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 not so long ago, it [uses](https://git.suckless.org/surf/file/config.mk.html#l15) an obsolete & deprecated version of [webkit](https://blogs.gnome.org/mcatanzaro/2023/03/21/webkitgtk-api-for-gtk-4-is-now-stable/) (2.40, with GTK3)
- 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/style-gtk4.css style/style-gtk3.css files.
- The gtk style usage isn't updated until installation. This is because by default rose uses the theme located in /opt/rosenrot/style-gtk3/4.css, and that file isn't updated until make install.
- The [min](https://git.nunosempere.com/open.source/rosenrot/src/branch/min) branch contains a minimalistic version of rosenrot, in one c file with 320 lines (256 without comments and extra newlines). It might be of interest to developers and those seeking to understand the code.
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 currently supports both the stable webkit2gtk-4.1/GTK3 release, and a newer release using webkit2gtk-6.0/GTK4. Eventually the later will become the only version. Readers might want to look through the history to see a bit about the updating process; commits related to the transition are tagged with the "GTK4: " label.
### 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.
### 📜 License
Rose is released under own license, which grants the following permissions:
- Commercial use
- Distribution
- Modification
- Private use

70
TODO.md Normal file
View File

@ -0,0 +1,70 @@
# To do
- [ ] Move to a later C standard (C11?) and use safer string handling functions provided by it.
- The thing is, I kinda feel attached to C89-C99
- [ ] Consider
- 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
- [ ] Finish cleaning up GTK4 version
- [ ] Think about best way of having GTK4 version alongside
- [ ] Shortcut to resize window
# Previously done
- [x] Check that this compiles with the c99 standard
- [x] Add minimalist version of rosenrot to its own branch
- [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>)
- [x] Upgrade to GTK-4 / Webkitgtk 6.0? Will take a fair amount of time, since GTK4 redesigns the application model somewhat.
- Instructions for webkit-6.0 [here](https://github.com/WebKit/WebKit/blob/ed1422596dce5ff012e64a38faf402ac1674fc7e/Source/WebKit/gtk/migrating-to-webkitgtk-6.0.md)
- Instructions for GTK-4 [here](https://docs.gtk.org/gtk4/migrating-3to4.html)
- [x] Prepare for GTK-3 to GTK-4 transition
- [x] Understand wtf is going on with signals and events: <https://docs.gtk.org/gtk4/migrating-3to4.html#stop-using-gtkwidget-event-signals>. <https://github.com/mini-rose/rose-browser/blob/288bf060d095c4895946669ae50d14193168b69c/src/window.c#L42>
- [x] Stop using direct access to GdkEvent structs
- [ ] ~~Remove webkit2gtk-4.1 and download webkit2gtk-6.0~~ => Actually just use both
- [x] Attempt to compile
- Notes for others:
- Searching github
- Creating a minimal version, e.g., having only one signal going on
- Looking at how https://github.com/mini-rose/rose-browser/ does things
- Printf statements
- GTK ressources: https://docs.gtk.org/gtk4, https://docs.gtk.org/gobject/, https://docs.gtk.org/gdk4/

View File

@ -1,11 +0,0 @@
CC=clang
SRC=rose.c
DEPS=('webkit2gtk-4.0')
INCS=`pkg-config --cflags ${DEPS[@]}`
LIBS=`pkg-config --libs ${DEPS[@]}`
# Optional adblocking depends on https://github.com/jun7/wyebadblock
WYEBAB='-L/usr/lib/wyebrowser/adblock.so'
$CC $INCS $LIBS $SRC $WYEBAB -o rose

View File

@ -1,76 +0,0 @@
/*
* Copyright (c) 2022 mini-rose
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and any associated documentation
* files to modify, copy, merge, publish, distribute and/or
* sublicense copies of this sotware for their own use.
* This code does not come with any warranty.
*
* Author: fenze <contact@fenze.dev>
*/
#include <gdk/gdkkeysyms.h>
/* See more:
* https://webkitgtk.org/reference/webkit2gtk/stable/class.Settings.html */
#define WEBKIT \
"enable-back-forward-navigation-gestures", true, "enable-developer-extras", true, \
"enable-smooth-scrolling", false
#define GTK "gtk-application-prefer-dark-theme", true, "gtk-enable-animations", false
#define HOME "https://duckduckgo.com"
#define SEARCH "https://duckduckgo.com/?q=%s"
#define CACHE_DIR "/home/fenze/.cache/rose"
#define KEY(x) GDK_KEY_##x
#define ZOOM 1 /* Starting zoom level */
#define ZOOM_VAL .1 /* Zooming value in zoomin/zoomout functions */
#define BG_COLOR "#1E1E2E"
typedef enum {
goback,
goforward,
refresh,
refresh_force,
back_to_home,
toggle_fullscreen,
zoomin,
zoomout,
zoom_reset,
next_tab,
prev_tab,
close_tab,
show_searchbar,
show_finder,
finder_next,
finder_prev
} func;
#define SFT 1 << 0
#define CTRL 1 << 2
#define ALT 1 << 3
static struct {
unsigned mod;
unsigned key;
func id;
} keys[] = {
{ 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 },
{ 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 }
};

144
config.h Normal file
View File

@ -0,0 +1,144 @@
#include <stdbool.h>
#include <gtk/gtk.h>
/* Key user config */
#define HEIGHT 1080
#define FULL_WIDTH 1920
#define WIDTH FULL_WIDTH
#define BAR_WIDTH FULL_WIDTH/2
/* More user config */
#define ZOOM_START_LEVEL 1.8
#define ZOOM_STEPSIZE .1
#define MAX_NUM_TABS 8 // 0 or false for unlimited tabs
#define SEARCH "https://search.brave.com/search?q=%s"
#define HOME "https://search.brave.com/search"
// #define SEARCH "https://search.nunosempere.com/search?q=%s"
// #define SEARCH "https://lite.duckduckgo.com/html/?q=%s"
// #define HOME "file:///opt/rosenrot/flower-imgs/rose-homepage.png"
/* Plugins */
#define LIBRE_REDIRECT_ENABLED true
#define READABILITY_ENABLED true
#define CUSTOM_USER_AGENT false
/*
To disable plugins:
1. set their corresponding variable to false
2. recompile
To remove plugins completely;
1. Remove the corresponding code in rosenrot.c by looking for the variables above, as well as custom_style_enabled
2. Remove PLUGIN and $(PLUGIN) from the makefile
3. Recompile
You could also look into commit afe93518a for an approach using stand-in code.
*/
/* Webkit */
// 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"
#define DATA_DIR "/home/nuno/.cache/rosenrot"
#define DATA_MANAGER_OPTS "base-cache-directory", DATA_DIR, "base-data-directory", DATA_DIR
#define NETWORK_SESSION_OPTS DATA_DIR, DATA_DIR
/* GTK */
// https://gitlab.gnome.org/GNOME/gtk/-/blob/main/gdk/gdkkeysyms.h
// https://gitlab.gnome.org/GNOME/gtk/-/blob/main/gdk/gdkenums.h
#define GTK_SETTINGS_CONFIG_H "gtk-application-prefer-dark-theme", false, "gtk-enable-animations", false
#define KEY(x) GDK_KEY_##x
#define SFT 1 << 0
#define CTRL 1 << 2
#define ALT 1 << 3
/* Misc helpers */
#define ABORT_REQUEST_ON_CURRENT_TAB NULL
#define NULLCHECK(x) \
do { \
if (x == NULL) { \
printf("\nNULL check not passed"); \
printf("@ %s (%d): ", __FILE__, __LINE__); \
exit(0); \
} \
} while (0)
/* Shortcuts */
typedef enum {
goback,
goforward,
refresh,
refresh_force,
back_to_home,
toggle_fullscreen,
toggle_custom_style,
zoomin,
zoomout,
zoom_reset,
new_tab,
next_tab,
prev_tab,
close_tab,
show_searchbar,
hide_bar,
show_finder,
finder_next,
finder_prev,
filter,
halve_window,
rebig_window,
prettify,
save_uri_to_txt,
open_uri_in_brave,
} func;
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 },
{ 0x0, KEY(F11), toggle_fullscreen },
{ CTRL, KEY(S), toggle_custom_style },
{ CTRL, KEY(equal), zoomin },
{ CTRL, KEY(minus), zoomout },
{ CTRL, KEY(0), zoom_reset },
{ CTRL | SFT, KEY(KP_Page_Up), prev_tab }, // use SFT just to show one can
{ CTRL | SFT, KEY(KP_Page_Down), next_tab },
{ CTRL | SFT, KEY(Page_Up), prev_tab },
// working hypothesis: Page_UP vs KP_Page_Up might depend on whether the user has a numpad
{ CTRL | SFT, KEY(Page_Down), next_tab },
{ CTRL, KEY(t), new_tab },
{ CTRL, KEY(w), close_tab },
{ CTRL, KEY(l), show_searchbar },
{ CTRL, KEY(o), hide_bar }, // previously: KEY(semicolon)
{ CTRL, KEY(f), show_finder },
{ CTRL, KEY(n), finder_next },
{ CTRL, KEY(N), finder_prev },
{ CTRL, KEY(F), filter },
{ CTRL, KEY(Up), halve_window },
{ CTRL, KEY(Down), rebig_window },
{ CTRL, KEY(p), prettify },
{ CTRL, KEY(s), save_uri_to_txt },
{ CTRL, KEY(b), open_uri_in_brave }
};

BIN
images/0-architecture.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
images/1-startup.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

BIN
images/2-blog.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 KiB

BIN
images/3-init.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

BIN
images/6-multiple-tabs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

View File

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

BIN
images/flower-imgs/rose.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 KiB

View File

@ -1,6 +0,0 @@
./build.sh && {
cp -f rose /usr/bin
mkdir -p /usr/share/themes/rose
cp style.css /usr/share/themes/rose/
cp rose-mklink /usr/bin
}

21
license Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022-2024 Nuño Sempere
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

123
makefile Normal file
View File

@ -0,0 +1,123 @@
# 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
STD=-std=c99 # maybe consider moving to c11 and using safer string handling
# Dependencies for WebkitGTK4/GTK3
SRC_3=rosenrot3.c
DEPS_3='webkit2gtk-4.1'
INCS_3=`pkg-config --cflags ${DEPS_3}`
LIBS_3=`pkg-config --libs ${DEPS_3}`
# Dependencies for WebkitGTK6/GTK4
SRC_4=rosenrot4.c
DEPS_4='webkitgtk-6.0'
INCS_4=`pkg-config --cflags ${DEPS_4}` `pkg-config --cflags gtk4`
LIBS_4=`pkg-config --libs ${DEPS_4}` `pkg-config --libs gtk4`
DEPRECATION_FLAGS=-DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED
# User config
CONFIG=config.h
# Plugins
include plugins/plugins.mk
# PLUGINS=./plugins/stand_in/stand_in.c
ADBLOCK='-L/usr/lib/wyebrowser/adblock.so' # optional adblocking; depends on https://github.com/jun7/wyebadblock
## Formatter
STYLE_BLUEPRINT="{BasedOnStyle: webkit, AllowShortIfStatementsOnASingleLine: true, IndentCaseLabels: true, AllowShortEnumsOnASingleLine: true}"
FORMATTER_C=clang-format -i -style=$(STYLE_BLUEPRINT)
FORMATTER_JS=npx prettier -w
# Runtime files
MAINTAINER_CACHE_DIR=/home/nuno/.cache/rosenrot
USER_CACHE_DIR=/home/`whoami`/.cache/rosenrot
RUNTIME_FILES_DIR=/opt/rosenrot/
build: $(SRC_4) $(PLUGINS) $(CONFIG) constants user_cache
$(CC) $(STD) $(WARNINGS) $(DEPRECATION_FLAGS) $(OPTIMIZED_MORE) $(DEBUG) $(INCS_4) $(PLUGINS) $(SRC_4) -o rosenrot $(LIBS_4) $(ADBLOCK)
@echo
build3: $(SRC_3) $(PLUGINS) $(CONFIG) constants user_cache
$(CC) $(STD) $(WARNINGS) $(OPTIMIZED_MORE) $(DEBUG) $(INCS_3) $(PLUGINS) $(SRC_3) -o rosenrot $(LIBS_3) $(ADBLOCK)
@echo
format: $(SRC_3) $(SRC_4) $(PLUGINS)
$(FORMATTER_C) $(SRC_3) $(PLUGINS) $(config.h)
$(FORMATTER_C) $(SRC_4_greenfield) $(PLUGINS) $(config.h)
$(FORMATTER_JS) plugins/readability/readability.js
$(FORMATTER_JS) plugins/style/style.js
# Installation
install: rosenrot runtime_files
cp -f rosenrot /usr/bin
cp rosenrot-mklink /usr/bin
@echo
uninstall:
rm -r /opt/rosenrot
rm /usr/bin/rosenrot
rm /usr/bin/rosenrot-mklink
rm $(USER_CACHE_DIR)
clean:
rm rosenrot
rm $(USER_CACHE_DIR)
constants:
@echo
@echo "# Computing constants"
cd plugins/readability/ && sh recompute_READABILITY_N.sh
cd plugins/style && sh recompute_STYLE_N.sh
@echo
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
@echo "# Create user cache"
mkdir -p $(USER_CACHE_DIR)
find . -type f -not -path "*.git*" -not -path "*makefile*" \
-exec sed -i "s|$(MAINTAINER_CACHE_DIR)|$(USER_CACHE_DIR)|g" {} +
@echo
runtime_files:
@echo
sudo mkdir -p /opt/rosenrot/
sudo cp styles-gtk/style-gtk3.css /opt/rosenrot/
sudo cp styles-gtk/style-gtk4.css /opt/rosenrot/
sudo touch /opt/rosenrot/uris.txt
sudo chmod a+rw /opt/rosenrot/uris.txt
sudo cp -r images/flower-imgs /opt/rosenrot/
sudo cp plugins/style/style.js /opt/rosenrot/
sudo cp plugins/readability/readability.js /opt/rosenrot/
# More misc recipes
lint:
clang-tidy $(SRC) $(PLUGINS) -- -Wall -O3 $(INCS) -o rosenrot $(LIBS)
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_4) $(PLUGINS) $(SRC_4) -o rosenrot $(LIBS_4) $(ADBLOCK)
@echo "Now use the browser for a while to gather some profiling data"
sleep 2
./rosenrot
$(CC) $(WARNINGS) $(OPTIMIZED_MORE) -fprofile-use $(INCS_4) $(PLUGINS) $(SRC_4) -o rosenrot $(LIBS_4) $(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

View File

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

View File

@ -0,0 +1,72 @@
#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://vitalik.ca",
"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://twitter.com"
// "https://archive.org",
// "https://twitter.com"
};
char* alternatives[] = {
"https://redlib.tux.pizza",
// previously: "https://old.reddit.com", "https://teddit.nunosempere.com",
// https://github.com/redlib-org/redlib-instances/blob/main/instances.md
"https://vitalik.eth.limo",
"https://invidious.private.coffee",
// "https://search.nunosempere.com",
"https://scribe.rip",
"https://translate.riverside.rocks",
"https://archive.ph/https://www.bloomberg.com",
"https://royalread.nunosempere.com",
"https://dumb.vern.cc",
"https://example.com"
// "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

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

View File

@ -0,0 +1,11 @@
#!/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

@ -0,0 +1,19 @@
#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.
}
}

5
plugins/plugins.h Normal file
View File

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

15
plugins/plugins.mk Normal file
View File

@ -0,0 +1,15 @@
## 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
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

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

BIN
plugins/readability/readability Executable file

Binary file not shown.

View File

@ -0,0 +1,31 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define READABILITY_N 88097 + 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

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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
#!/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

@ -0,0 +1,7 @@
## 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

@ -0,0 +1,69 @@
#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",
"!fs",
"!hn",
"!hnb",
"!ww",
"!x"
};
char* expansions[] = {
"https://annas-archive.org",
"https://nunosempere.com/blog",
"https://forum.nunosempere.com/frontpage",
"https://forum.nunosempere.com/comments",
"https://forecasting.substack.com",
"https://news.ycombinator.com",
"https://news.ycombinator.com/best",
"https://web.whatsapp.com",
"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

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

View File

@ -0,0 +1,30 @@
/* 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

@ -0,0 +1,24 @@
/* 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);

61
plugins/strings/strings.c Normal file
View File

@ -0,0 +1,61 @@
#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

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

5
plugins/style/README.md Normal file
View File

@ -0,0 +1,5 @@
## 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

@ -0,0 +1,9 @@
#!/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"

21
plugins/style/style.c Normal file
View File

@ -0,0 +1,21 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STYLE_N 9278 + 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);
}

5
plugins/style/style.h Normal file
View File

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

346
plugins/style/style.js Normal file
View File

@ -0,0 +1,346 @@
// Inspired by the Stylus app: <https://addons.mozilla.org/en-GB/firefox/addon/styl-us/>
// NOTE: This file is moved to /opt/rosenrot, so editing it here doesn't have direct effects on the runtime!!
// Main part of the code: switch on the domain and select the corresponding style
var styles = null;
// console.log(document.domain);
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.brave.com":
styles = `
.download-button,
a[href^="https://brave.com/download/"], .download-cta
{
display: none !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,
.promotedlink,
.promoted
{
display: none !important;
}
`;
break;
case "twitter.com":
case "x.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 !important;
}
/* 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: seemed like a good idea
but it fucks up going back and forth
*:hover {
background-color: white !important;
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;
case "":
break;
default:
console.log(`Domain: ${document.domain}`);
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" || document.domain == "x.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";
// Add some code to filter out articles for Sentinel
function filterByKeyword(str) {
// e.g., "keyword" (equivalent to "keyword, p, 1")
// e.g., "keyword, div, 3"
// might not work with level=0, but not sure why
const args = str.split(", ");
let keword = null;
let selector = "p"; /* or "*" for all */
let level = 1;
if (args.length > 0) {
keyword = args[0].trim();
}
if (args.length > 1) {
selector = args[1].trim();
}
if (args.length > 2) {
level = Number(args[2].trim());
}
console.log(keyword, selector, level);
// Get all elements matching the selector
const elements = document.querySelectorAll(selector);
// Convert NodeList to Array to use array methods
const elementsArray = Array.from(elements);
// Filter elements containing the keyword
const matchingElements = elementsArray.filter((element) =>
element.textContent.toLowerCase().includes(keyword.toLowerCase()),
);
// Remove parent of each matching element
matchingElements.forEach((element) => {
let ancestor = element; // Start with the current element
// Loop to climb up the DOM tree according to the level required
for (let i = 0; i < level && ancestor !== null; i++) {
ancestor = ancestor.parentNode; // Move up in the DOM tree
}
if (ancestor) {
ancestor.style.display = "none";
}
});
}

View File

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

316
rose.c
View File

@ -1,316 +0,0 @@
/*
* Copyright (c) 2022 mini-rose
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and any associated documentation
* files to modify, copy, merge, publish, distribute and/or
* sublicense copies of this sotware for their own use.
* This code does not come with any warranty.
*
* Author: fenze <contact@fenze.dev>
*/
#include "config.h"
#include <webkit2/webkit2.h>
#define CACHE \
"base-cache-directory", CACHE_DIR, \
"base-data-directory", CACHE_DIR, \
"disk-cache-directory", CACHE_DIR, \
"dom-cache-directory", CACHE_DIR, \
"hsts-cache-directory", CACHE_DIR, \
"indexeddb-directory", CACHE_DIR, \
"itp-directory", CACHE_DIR, \
"local-storage-directory", CACHE_DIR, \
"offline-application-cache-directory", CACHE_DIR, \
"service-worker-registrations-directory", CACHE_DIR
enum { _SEARCH, _FIND };
static int entry_mode;
static GtkWindow *window;
static GtkHeaderBar *bar;
static GtkEntryBuffer *search_buf;
static GtkEntry *search;
WebKitWebView *webview_new()
{
char *style;
WebKitSettings *settings;
WebKitWebContext *web_context;
WebKitCookieManager *cookiemanager;
WebKitUserContentManager *contentmanager;
settings = webkit_settings_new_with_settings(WEBKIT, NULL);
web_context = webkit_web_context_new_with_website_data_manager(
webkit_website_data_manager_new(CACHE, NULL));
contentmanager = webkit_user_content_manager_new();
cookiemanager = webkit_web_context_get_cookie_manager(web_context);
webkit_cookie_manager_set_persistent_storage(cookiemanager, CACHE_DIR "/cookies.sqlite",
WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
webkit_cookie_manager_set_accept_policy(cookiemanager, WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
webkit_web_context_set_process_model(web_context,
WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);
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 load_uri(WebKitWebView *view, const char *uri)
{
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 {
char tmp[strlen(uri) + strlen(SEARCH)];
snprintf(tmp, sizeof(tmp), SEARCH, uri);
webkit_web_view_load_uri(view, tmp);
}
}
void load_changed(WebKitWebView *self, WebKitLoadEvent load_event, GtkNotebook *notebook)
{
if (load_event == WEBKIT_LOAD_FINISHED) {
gtk_notebook_set_tab_label_text(notebook, GTK_WIDGET(self),
webkit_web_view_get_title(self));
gtk_widget_hide(GTK_WIDGET(bar));
}
}
void notebook_append(GtkNotebook *notebook, const char *uri)
{
GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(window));
GdkVisual *rgba_visual = gdk_screen_get_rgba_visual(screen);
GdkRGBA rgba;
gdk_rgba_parse(&rgba, BG_COLOR);
WebKitWebView *view = webview_new();
gtk_widget_set_visual(GTK_WIDGET(window), rgba_visual);
g_signal_connect(view, "load_changed", G_CALLBACK(load_changed), notebook);
int n = gtk_notebook_append_page(notebook, GTK_WIDGET(view), NULL);
gtk_notebook_set_tab_reorderable(notebook, GTK_WIDGET(view), true);
gtk_widget_show_all(GTK_WIDGET(window));
gtk_widget_hide(GTK_WIDGET(bar));
webkit_web_view_set_background_color(view, &rgba);
load_uri(view, (uri) ? uri : HOME);
gtk_notebook_set_current_page(notebook, n);
}
WebKitWebView *notebook_get_webview(GtkNotebook *notebook)
{
return WEBKIT_WEB_VIEW(
gtk_notebook_get_nth_page(notebook, gtk_notebook_get_current_page(notebook)));
}
void show_bar(GtkNotebook *notebook)
{
if (entry_mode == _SEARCH) {
const char *url = webkit_web_view_get_uri(notebook_get_webview(notebook));
gtk_entry_set_placeholder_text(search, "Search");
gtk_entry_buffer_set_text(search_buf, url, strlen(url));
gtk_widget_show(GTK_WIDGET(bar));
gtk_window_set_focus(window, GTK_WIDGET(search));
} else {
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(search_buf, search_text, strlen(search_text));
gtk_entry_set_placeholder_text(search, "Find");
gtk_widget_show(GTK_WIDGET(bar));
gtk_window_set_focus(window, GTK_WIDGET(search));
}
}
int handle_key(func id, GtkNotebook *notebook)
{
static double zoom = ZOOM;
static bool is_fullscreen = 0;
switch (id) {
case goback:
webkit_web_view_go_back(notebook_get_webview(notebook));
break;
case goforward:
webkit_web_view_go_forward(notebook_get_webview(notebook));
break;
case refresh:
webkit_web_view_reload(notebook_get_webview(notebook));
break;
case refresh_force:
webkit_web_view_reload_bypass_cache(notebook_get_webview(notebook));
break;
case back_to_home:
load_uri(notebook_get_webview(notebook), HOME);
break;
case zoomin:
webkit_web_view_set_zoom_level(notebook_get_webview(notebook), (zoom += ZOOM_VAL));
break;
case zoomout:
webkit_web_view_set_zoom_level(notebook_get_webview(notebook), (zoom -= ZOOM_VAL));
break;
case zoom_reset:
webkit_web_view_set_zoom_level(notebook_get_webview(notebook), (zoom = ZOOM));
break;
case prev_tab:
if (gtk_notebook_get_current_page(notebook) == 0) {
gtk_notebook_set_current_page(notebook,
gtk_notebook_get_n_pages(notebook) - 1);
} else {
gtk_notebook_prev_page(notebook);
}
break;
case next_tab:
if (gtk_notebook_get_current_page(notebook) ==
gtk_notebook_get_n_pages(notebook) - 1) {
notebook_append(notebook, NULL);
gtk_notebook_set_show_tabs(notebook, true);
} else {
gtk_notebook_next_page(notebook);
}
break;
case close_tab:
gtk_notebook_remove_page(notebook, gtk_notebook_get_current_page(notebook));
switch (gtk_notebook_get_n_pages(notebook)) {
case 0:
exit(0);
break;
case 1:
gtk_notebook_set_show_tabs(notebook, false);
break;
}
break;
case toggle_fullscreen:
if (is_fullscreen)
gtk_window_unfullscreen(window);
else
gtk_window_fullscreen(window);
is_fullscreen = ! is_fullscreen;
break;
case show_searchbar:
entry_mode = _SEARCH;
show_bar(notebook);
break;
case show_finder:
entry_mode = _FIND;
show_bar(notebook);
break;
case finder_next:
webkit_find_controller_search_next(
webkit_web_view_get_find_controller(notebook_get_webview(notebook)));
break;
case finder_prev:
webkit_find_controller_search_previous(
webkit_web_view_get_find_controller(notebook_get_webview(notebook)));
break;
}
return 1;
}
int keypress(void *self, GdkEvent *e, GtkNotebook *notebook)
{
(void) self;
for (int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++)
if (e->key.keyval == keys[i].key && e->key.state == keys[i].mod)
return handle_key(keys[i].id, notebook);
return 0;
}
void search_activate(GtkEntry *self, GtkNotebook *notebook)
{
if (entry_mode == _SEARCH)
load_uri(notebook_get_webview(notebook), gtk_entry_buffer_get_text(search_buf));
else if (entry_mode == _FIND)
webkit_find_controller_search(
webkit_web_view_get_find_controller(notebook_get_webview(notebook)),
gtk_entry_buffer_get_text(search_buf),
WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE | WEBKIT_FIND_OPTIONS_WRAP_AROUND,
G_MAXUINT);
gtk_widget_hide(GTK_WIDGET(bar));
}
void window_init(GtkNotebook *notebook)
{
GtkCssProvider *css = gtk_css_provider_new();
gtk_css_provider_load_from_path(css, "/usr/share/themes/rose/style.css", NULL);
gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(css),
800);
gtk_entry_buffer_new("", 0);
gtk_entry_set_alignment(search, 0.48);
gtk_widget_set_size_request(GTK_WIDGET(search), 300, -1);
gtk_header_bar_set_custom_title(bar, GTK_WIDGET(search));
gtk_window_set_titlebar(window, GTK_WIDGET(bar));
g_signal_connect(search, "activate", G_CALLBACK(search_activate), notebook);
g_signal_connect(window, "key-press-event", G_CALLBACK(keypress), notebook);
g_signal_connect(window, "destroy", G_CALLBACK(exit), notebook);
}
void notebook_init(GtkNotebook *notebook, const char *uri)
{
gtk_notebook_set_show_border(notebook, false);
gtk_notebook_set_show_tabs(notebook, false);
notebook_append(notebook, uri);
}
void setup(GtkNotebook *notebook, const char *uri)
{
window = GTK_WINDOW(gtk_window_new(0));
notebook = GTK_NOTEBOOK(gtk_notebook_new());
bar = GTK_HEADER_BAR(gtk_header_bar_new());
search_buf = GTK_ENTRY_BUFFER(gtk_entry_buffer_new("", 0));
search = GTK_ENTRY(gtk_entry_new_with_buffer(search_buf));
window_init(notebook);
notebook_init(notebook, uri);
g_object_set(gtk_settings_get_default(), GTK, NULL);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(notebook));
gtk_widget_show_all(GTK_WIDGET(window));
gtk_widget_hide(GTK_WIDGET(bar));
}
int main(int argc, char **argv)
{
GtkNotebook *notebook;
gtk_init(NULL, NULL);
setup(notebook, argc > 1 ? argv[1] : NULL);
gtk_main();
}

17
rosenrot-mklink Executable file
View File

@ -0,0 +1,17 @@
#!/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
}

442
rosenrot3.c Normal file
View File

@ -0,0 +1,442 @@
#include <gdk/gdk.h>
#include <stdlib.h>
#include <string.h>
#include <webkit2/webkit2.h>
#include "config.h"
#include "plugins/plugins.h"
/* Global variables */
static GtkNotebook* notebook;
static GtkWindow* window;
typedef enum { _SEARCH, _FIND, _HIDDEN } Bar_entry_mode;
static struct {
GtkHeaderBar* widget;
GtkEntry* line;
GtkEntryBuffer* line_text;
Bar_entry_mode entry_mode;
} bar;
static int num_tabs = 0;
static int custom_style_enabled = 1;
/* Forward declarations */
void toggle_bar(GtkNotebook* notebook, Bar_entry_mode mode);
void notebook_create_new_tab(GtkNotebook* notebook, const char* uri);
/* Utils */
WebKitWebView* notebook_get_webview(GtkNotebook* notebook)
{
return WEBKIT_WEB_VIEW(gtk_notebook_get_nth_page(notebook, gtk_notebook_get_current_page(notebook)));
}
/* Load content*/
void load_uri(WebKitWebView* view, const char* uri)
{
bool is_empty_uri = (strlen(uri) == 0);
if (is_empty_uri) {
webkit_web_view_load_uri(view, "");
toggle_bar(notebook, _SEARCH);
return;
}
bool has_direct_uri_prefix = g_str_has_prefix(uri, "http://") || g_str_has_prefix(uri, "https://") || g_str_has_prefix(uri, "file://") || g_str_has_prefix(uri, "about:");
if (has_direct_uri_prefix){
webkit_web_view_load_uri(view, uri);
return;
}
bool has_common_domain_extension = (strstr(uri, ".com") || strstr(uri, ".org"));
if (has_common_domain_extension){
char tmp[strlen("https://") + strlen(uri) + 1];
snprintf(tmp, sizeof(tmp) + 1, "https://%s", uri);
webkit_web_view_load_uri(view, tmp);
return;
}
int l = SHORTCUT_N + strlen(uri) + 1;
char uri_expanded[l];
str_init(uri_expanded, l);
int check = shortcut_expand(uri, uri_expanded);
bool has_shortcut = (check == 2);
if (has_shortcut){
webkit_web_view_load_uri(view, uri_expanded);
return;
}
char tmp[strlen(uri) + strlen(SEARCH)];
snprintf(tmp, sizeof(tmp), SEARCH, uri);
webkit_web_view_load_uri(view, tmp);
}
/* Deal with new load or changed load */
void redirect_if_annoying(WebKitWebView* view, const char* uri)
{
if (LIBRE_REDIRECT_ENABLED) {
int l = LIBRE_N + strlen(uri) + 1;
char uri_filtered[l];
str_init(uri_filtered, l);
int check = libre_redirect(uri, uri_filtered);
if (check == 2) webkit_web_view_load_uri(view, uri_filtered);
}
}
void set_custom_style(WebKitWebView* view)
{
if (custom_style_enabled) {
char* style_js = malloc(STYLE_N + 1);
read_style_js(style_js);
webkit_web_view_evaluate_javascript(view, style_js, -1, NULL, "rosenrot-style-plugin", NULL, NULL, NULL);
free(style_js);
}
}
void handle_signal_load_changed(WebKitWebView* self, WebKitLoadEvent load_event,
GtkNotebook* notebook)
{
switch (load_event) {
// https://webkitgtk.org/reference/webkit2gtk/2.5.1/WebKitWebView.html
case WEBKIT_LOAD_STARTED:
case WEBKIT_LOAD_COMMITTED:
set_custom_style(self);
case WEBKIT_LOAD_REDIRECTED:
redirect_if_annoying(self, webkit_web_view_get_uri(self));
break;
case WEBKIT_LOAD_FINISHED: {
set_custom_style(self);
/* Add gtk tab title */
const char* webpage_title = webkit_web_view_get_title(self);
const int max_length = 25;
char tab_title[max_length + 1];
if (webpage_title != NULL) {
for (int i = 0; i < (max_length); i++) {
tab_title[i] = webpage_title[i];
if (webpage_title[i] == '\0') {
break;
}
}
tab_title[max_length] = '\0';
}
gtk_notebook_set_tab_label_text(notebook, GTK_WIDGET(self),
webpage_title == NULL ? "" : tab_title);
}
}
}
/* New tabs */
WebKitWebView* create_new_webview()
{
char* style;
WebKitSettings* settings = webkit_settings_new_with_settings(WEBKIT_DEFAULT_SETTINGS, NULL);
if (CUSTOM_USER_AGENT) {
webkit_settings_set_user_agent(
settings,
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, "
"like Gecko) Chrome/120.0.0.0 Safari/537.3");
// https://www.useragents.me
}
WebKitWebContext* web_context = webkit_web_context_new_with_website_data_manager(webkit_website_data_manager_new(DATA_MANAGER_OPTS, NULL));
WebKitUserContentManager* contentmanager = webkit_user_content_manager_new();
WebKitCookieManager* cookiemanager = webkit_web_context_get_cookie_manager(web_context);
webkit_cookie_manager_set_persistent_storage(cookiemanager, DATA_DIR "/cookies.sqlite", WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
webkit_cookie_manager_set_accept_policy(cookiemanager, WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
if (g_file_get_contents("~/opt/rosenrot/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));
}
WebKitWebView* view = g_object_new(WEBKIT_TYPE_WEB_VIEW, "settings", settings, "web-context", web_context, "user-content-manager", contentmanager, NULL);
return view;
}
GtkWidget* handle_signal_create_new_tab(WebKitWebView* self,
WebKitNavigationAction* navigation_action,
GtkNotebook* notebook)
{
if (num_tabs < MAX_NUM_TABS || num_tabs == 0) {
WebKitURIRequest* uri_request = webkit_navigation_action_get_request(navigation_action);
const char* uri = webkit_uri_request_get_uri(uri_request);
printf("Creating new window: %s\n", uri);
notebook_create_new_tab(notebook, uri);
gtk_notebook_set_show_tabs(notebook, true);
} else {
webkit_web_view_evaluate_javascript(self, "alert('Too many tabs, not opening a new one')", -1, NULL, "rosenrot-alert-numtabs", NULL, NULL, NULL);
}
return ABORT_REQUEST_ON_CURRENT_TAB;
}
void notebook_create_new_tab(GtkNotebook* notebook, const char* uri)
{
if (num_tabs < MAX_NUM_TABS || MAX_NUM_TABS == 0) {
WebKitWebView* view = create_new_webview();
g_signal_connect(view, "load_changed", G_CALLBACK(handle_signal_load_changed), notebook);
g_signal_connect(view, "create", G_CALLBACK(handle_signal_create_new_tab), notebook);
int n = gtk_notebook_append_page(notebook, GTK_WIDGET(view), NULL);
gtk_notebook_set_tab_reorderable(notebook, GTK_WIDGET(view), true);
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_START_LEVEL);
num_tabs += 1;
} else {
webkit_web_view_evaluate_javascript(notebook_get_webview(notebook), "alert('Too many tabs, not opening a new one')",
-1, NULL, "rosenrot-alert-numtabs", NULL, NULL, NULL);
}
}
/* Top bar */
void toggle_bar(GtkNotebook* notebook, Bar_entry_mode mode)
{
bar.entry_mode = mode;
switch (bar.entry_mode) {
case _SEARCH: {
const char* url = webkit_web_view_get_uri(notebook_get_webview(notebook));
gtk_entry_set_placeholder_text(bar.line, "Search");
gtk_entry_buffer_set_text(bar.line_text, url, strlen(url));
gtk_widget_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)
{
if (bar.entry_mode == _SEARCH)
load_uri(notebook_get_webview(notebook), gtk_entry_buffer_get_text(bar.line_text));
else if (bar.entry_mode == _FIND)
webkit_find_controller_search(
webkit_web_view_get_find_controller(notebook_get_webview(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));
}
/* Shortcuts */
int handle_shortcut(func id, GtkNotebook* notebook)
{
static double zoom = ZOOM_START_LEVEL;
static bool is_fullscreen = 0;
WebKitWebView* view = notebook_get_webview(notebook);
switch (id) {
case goback:
webkit_web_view_go_back(view);
break;
case goforward:
webkit_web_view_go_forward(view);
break;
case toggle_custom_style: /* Ctrl s + Ctrl Shift R to reload */
custom_style_enabled ^= 1;
// fallthrough
case refresh:
webkit_web_view_reload(view);
break;
case refresh_force:
webkit_web_view_reload_bypass_cache(view);
break;
case back_to_home:
load_uri(view, HOME);
break;
case zoomin:
webkit_web_view_set_zoom_level(view,
(zoom += ZOOM_STEPSIZE));
break;
case zoomout:
webkit_web_view_set_zoom_level(view,
(zoom -= ZOOM_STEPSIZE));
break;
case zoom_reset:
webkit_web_view_set_zoom_level(view,
(zoom = ZOOM_START_LEVEL));
break;
case prev_tab:; // declarations aren't statements
// https://stackoverflow.com/questions/92396/why-cant-variables-be-declared-in-a-switch-statement
int n = gtk_notebook_get_n_pages(notebook);
int k = gtk_notebook_get_current_page(notebook);
int l = (n + k - 1) % n;
gtk_notebook_set_current_page(notebook, l);
break;
case next_tab:;
int m = gtk_notebook_get_n_pages(notebook);
int i = gtk_notebook_get_current_page(notebook);
int j = (i + 1) % m;
gtk_notebook_set_current_page(notebook, j);
break;
case close_tab:
num_tabs -= 1;
switch(num_tabs){
case 0:
exit(0);
break;
case 1:
gtk_notebook_set_show_tabs(notebook, false);
// fallthrough
default:
gtk_notebook_remove_page(notebook, gtk_notebook_get_current_page(notebook));
}
break;
case toggle_fullscreen:
if (is_fullscreen)
gtk_window_unfullscreen(window);
else
gtk_window_fullscreen(window);
is_fullscreen = !is_fullscreen;
break;
case show_searchbar:
toggle_bar(notebook, _SEARCH);
break;
case show_finder:
toggle_bar(notebook, _FIND);
break;
case finder_next:
webkit_find_controller_search_next(webkit_web_view_get_find_controller(view));
break;
case finder_prev:
webkit_find_controller_search_previous(webkit_web_view_get_find_controller(view));
break;
case new_tab:
notebook_create_new_tab(notebook, NULL);
gtk_notebook_set_show_tabs(notebook, true);
toggle_bar(notebook, _SEARCH);
break;
case hide_bar:
toggle_bar(notebook, _HIDDEN);
break;
case halve_window:
gtk_window_resize(window, FULL_WIDTH/2, HEIGHT);
break;
case rebig_window:
gtk_window_resize(window, FULL_WIDTH, HEIGHT);
break;
case prettify: {
if (READABILITY_ENABLED) {
char* readability_js = malloc(READABILITY_N + 1);
read_readability_js(readability_js);
webkit_web_view_evaluate_javascript(view, readability_js, -1, NULL, "rosenrot-readability-plugin", NULL, NULL, NULL);
free(readability_js);
}
break;
}
}
return 1;
}
// Listen to key presses and call shortcuts if needed.
int handle_signal_keypress(void* self, GdkEvent* event, GtkNotebook* notebook)
{
(void)self;
guint event_keyval = 0;
gdk_event_get_keyval(event, &event_keyval);
GdkModifierType event_state = 0;
gdk_event_get_state(event, &event_state);
if (0) {
printf("Keypress state: %d\n", event_state);
printf("Keypress value: %d\n", event_keyval);
}
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
*/
return 0;
}
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-gtk3.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 */
// Window
window = GTK_WINDOW(gtk_window_new(0));
gtk_window_set_default_size(window, WIDTH, HEIGHT);
// Notebook
notebook = GTK_NOTEBOOK(gtk_notebook_new());
gtk_notebook_set_show_tabs(notebook, false);
gtk_notebook_set_show_border(notebook, false);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(notebook));
// Bar
bar.line_text = GTK_ENTRY_BUFFER(gtk_entry_buffer_new("", 0));
bar.line = GTK_ENTRY(gtk_entry_new_with_buffer(bar.line_text));
gtk_entry_set_alignment(bar.line, 0.48);
gtk_widget_set_size_request(GTK_WIDGET(bar.line), BAR_WIDTH, -1);
bar.widget = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_header_bar_set_custom_title(bar.widget, GTK_WIDGET(bar.line));
gtk_window_set_titlebar(window, GTK_WIDGET(bar.widget));
// Signals
g_signal_connect(window, "key-press-event", G_CALLBACK(handle_signal_keypress), notebook);
g_signal_connect(window, "destroy", G_CALLBACK(exit), notebook);
g_signal_connect(bar.line, "activate", G_CALLBACK(handle_signal_bar_press_enter), notebook);
/* Load first tab */
char* first_uri = argc > 1 ? argv[1] : HOME;
notebook_create_new_tab(notebook, first_uri);
/* Show to user */
gtk_widget_show_all(GTK_WIDGET(window));
if (argc != 0) gtk_widget_hide(GTK_WIDGET(bar.widget));
/* 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]);
}
}
gtk_main();
}

507
rosenrot4.c Normal file
View File

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

41
styles-gtk/style-gtk3.css Normal file
View File

@ -0,0 +1,41 @@
* {
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;
}

41
styles-gtk/style-gtk4.css Normal file
View File

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

View File

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

View File

@ -0,0 +1,42 @@
# 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 build3 # 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"

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 KiB

View File

@ -0,0 +1,9 @@
#!/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.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

View File

@ -0,0 +1,52 @@
@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

@ -0,0 +1,70 @@
@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

@ -0,0 +1 @@
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

@ -0,0 +1,24 @@
# 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

@ -0,0 +1,9 @@
#!/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.

After

Width:  |  Height:  |  Size: 625 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

View File

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

View File

@ -0,0 +1,9 @@
#!/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

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

View File

@ -0,0 +1,9 @@
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
```