├── ext.c ├── icons ├── 24x24 │ └── surfer.png ├── 32x32 │ └── surfer.png └── 48x48 │ └── surfer.png ├── www.youtube.com ├── surfer.desktop ├── Makefile ├── ephy-scripts.c ├── README.md ├── config.h ├── surfer.1 ├── black.css ├── LICENSE └── surfer.c /ext.c: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/24x24/surfer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihilowy/surfer/HEAD/icons/24x24/surfer.png -------------------------------------------------------------------------------- /icons/32x32/surfer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihilowy/surfer/HEAD/icons/32x32/surfer.png -------------------------------------------------------------------------------- /icons/48x48/surfer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihilowy/surfer/HEAD/icons/48x48/surfer.png -------------------------------------------------------------------------------- /www.youtube.com: -------------------------------------------------------------------------------- 1 | //block ads for www.youtube.com, place in .local/share/surfer 2 | document.getElementById('top-container').style.display = "none" 3 | document.getElementById('masthead-ad').style.display = "none" 4 | -------------------------------------------------------------------------------- /surfer.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Surfer 3 | Exec=surfer %U 4 | StartupNotify=true 5 | Terminal=false 6 | Type=Application 7 | Icon=surfer 8 | Categories=Network;GNOME;GTK;WebBrowser; 9 | MimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;multipart/related;application/x-mimearchive;message/rfc822; 10 | Actions=Incognito; 11 | 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DESTDIR=/usr 2 | EXTENSION_DIR=$(DESTDIR)/lib/surfer/ 3 | 4 | ifeq ($(DEBUG), 1) 5 | CFLAGS += -Wall -g 6 | else 7 | DEBUG = 0 8 | # CFLAGS += -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fexceptions -Wp,-D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fstack-clash-protection -fcf-protection -Wformat -Werror=format-security -fstack-clash-protection -fcf-protection -Wno-deprecated-declarations 9 | 10 | 11 | CFLAGS += -std=c99 -pipe -Wall -fPIC 12 | endif 13 | DDEBUG=-DDEBUG=${DEBUG} 14 | 15 | all: surfer ephy-scripts.so adblock.so 16 | 17 | surfer: surfer.c Makefile 18 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< \ 19 | `pkg-config --cflags --libs libnotify gtk+-3.0 glib-2.0 webkit2gtk-4.0` \ 20 | -DEXTENSION_DIR=\"$(EXTENSION_DIR)\" \ 21 | $(DDEBUG) -lm 22 | 23 | adblock.so: ext.c Makefile 24 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -shared -fPIC \ 25 | `pkg-config --cflags --libs libnotify gtk+-3.0 glib-2.0 webkit2gtk-4.0` \ 26 | $(DDEBUG) 27 | 28 | 29 | 30 | ephy-scripts.so: ephy-scripts.c Makefile 31 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -shared -fPIC \ 32 | `pkg-config --cflags --libs libnotify gtk+-3.0 glib-2.0 webkit2gtk-4.0` \ 33 | $(DDEBUG) 34 | 35 | 36 | install:all 37 | install -d $(DESTDIR)/share/surfer 38 | install -d $(DESTDIR)/lib 39 | install -d $(DESTDIR)/lib/surfer 40 | install -Dm644 ephy-scripts.so $(DESTDIR)/lib/surfer/ 41 | # install -Dm644 adblock.so $(DESTDIR)/lib/surfer/ 42 | install -Dm755 surfer $(DESTDIR)/bin/surfer 43 | install -Dm644 surfer.desktop $(DESTDIR)/share/applications/surfer.desktop 44 | install -Dm644 surfer.1 $(DESTDIR)/share/man/man1/surfer.1 45 | install -Dm644 black.css $(DESTDIR)/share/surfer/black.css 46 | install -Dm644 icons/24x24/surfer.png $(DESTDIR)/share/icons/hicolor/24x24/surfer.png 47 | install -Dm644 icons/32x32/surfer.png $(DESTDIR)/share/icons/hicolor/32x32/surfer.png 48 | install -Dm644 icons/48x48/surfer.png $(DESTDIR)/share/icons/hicolor/48x48/surfer.png 49 | # install -Dm644 icons/surfer.svg $(DESTDIR)/share/icons/hicolor/scalable/apps/surfer.svg 50 | 51 | uninstall: 52 | $(RM) $(DESTDIR)bin/surfer 53 | $(RM) $(DESTDIR)/man/man1/surfer.1 54 | $(RM) $(DESTDIR)//share/surfer/black.css 55 | $(RM) $(DESTDIR)/share/applications/surfer.desktop 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /ephy-scripts.c: -------------------------------------------------------------------------------- 1 | //most code form ephy-scripts on github.com + my fixes 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | struct script_info { 8 | gchar *str; 9 | gsize len; 10 | gchar *src; 11 | }; 12 | 13 | static gchar *universal; 14 | 15 | static GArray *script_infos; 16 | 17 | static void add_file(const gchar *dirname, const gchar *filename) 18 | { 19 | gchar *path = g_build_filename(dirname, filename, NULL); 20 | struct script_info s; 21 | if (g_file_get_contents(path, &s.str, &s.len, NULL)) { 22 | s.src = g_filename_to_uri(path, NULL, NULL); 23 | g_array_append_val(script_infos, s); 24 | } 25 | g_free(path); 26 | } 27 | 28 | static void add_path(const gchar *path) 29 | { 30 | gchar *dirname = g_build_filename(path, "surfer", NULL); 31 | GDir *dir = g_dir_open(dirname, 0, NULL); 32 | if (dir != NULL) { 33 | const gchar *filename; 34 | while ((filename = g_dir_read_name(dir)) != NULL) 35 | add_file(dirname, filename); 36 | g_dir_close(dir); 37 | } 38 | g_free(dirname); 39 | } 40 | 41 | static void on_document_loaded(WebKitWebPage *page, gpointer user_data) 42 | { 43 | 44 | (void) user_data; 45 | JSCContext *ctx = webkit_frame_get_js_context(webkit_web_page_get_main_frame(page)); 46 | JSCValue *hostname = jsc_context_evaluate(ctx,"window.location.hostname;",-1); 47 | gchar *url = jsc_value_to_string(hostname); 48 | for (gsize i = 0; i < script_infos->len; i++) { 49 | const struct script_info *s = &g_array_index(script_infos, struct script_info, i); 50 | 51 | gchar *tmp = g_strdup(s->src); 52 | gchar *last = basename(tmp); 53 | 54 | if( g_strcmp0(url,last) == 0 || g_strcmp0(universal,last) == 0){ 55 | 56 | g_object_unref(jsc_context_evaluate_with_source_uri(ctx, s->str, s->len, s->src, 0)); 57 | 58 | } 59 | 60 | } 61 | } 62 | 63 | 64 | static void on_page_created(WebKitWebExtension *extension, WebKitWebPage *page, gpointer user_data) 65 | { 66 | (void) extension; 67 | (void) user_data; 68 | g_signal_connect(page, "document-loaded", G_CALLBACK(on_document_loaded), NULL); 69 | } 70 | 71 | G_MODULE_EXPORT void webkit_web_extension_initialize(WebKitWebExtension *extension) 72 | { 73 | universal = g_strdup_printf("universal.js"); 74 | script_infos = g_array_new(FALSE, FALSE, sizeof(struct script_info)); 75 | const gchar * const *paths = g_get_system_data_dirs(); 76 | while (*paths != NULL) 77 | add_path(*(paths++)); 78 | add_path(g_get_user_data_dir()); 79 | g_signal_connect(extension, "page-created", G_CALLBACK(on_page_created), NULL); 80 | } 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Surfer 2 | 3 | Simple keyboard based web browser. No tabs. 4 | 5 | Based on webkit2gtk and gtk3. 6 | 7 | No xlibs dependency — works on sway, weston etc. 8 | 9 | Look also at manual ( man surfer). 10 | 11 | ## Adblock, videos, other info 12 | 13 | `For videos` install gstreamer packages. 14 | 15 | config.h - customize keys, dirs and some other settings before compile. 16 | 17 | It can also launch mpv( with help of youtube-dl on supported sites) on links, 18 | but remember to pkill -9 mpv if it hogs your cpu, used on non supported sites. 19 | 20 | Also possible to use other binaries/scripts - location of dirctory of that settable in config.h 21 | 22 | Beside it can toggle JS and History. Ephemeral (priv mode) on links. 23 | You can also set css for sites in .surfer/tablecss.txt file. 24 | 25 | Search or translate for selected text, settable in config.h 26 | 27 | 28 | `For adblock:` 29 | 30 | Install https://github.com/jun7/wyebadblock 31 | Then sudo ln -s /usr/lib/wyebrowser/adblock.so /usr/lib/surfer 32 | 33 | Or block through /etc/hosts 34 | 35 | Or save to .surfer/adblock.json file (ie from https://easylist-downloads.adblockplus.org/easylist_min_content_blocker.json ) 36 | 37 | 38 | `For JS scripts:` 39 | 40 | Js scripts (i.e. from greasefork site) place in .local/share/surfer/ 41 | 42 | name them in following way: 43 | -i.e. for run scripts on www.youtube.com name script file identically. 44 | -if you want script to run on all sites, name it universal.js 45 | 46 | ## Compile and install: 47 | 48 | 49 | git clone https://github.com/nihilowy/surfer.git 50 | 51 | cd surfer 52 | 53 | make && sudo make install 54 | 55 | 56 | Depends on webkit2gtk, gtk3 development files (install it on your distro) 57 | 58 | ## Hotkeys: 59 | 60 | `Ctrl + click` link — open link in new window 61 | 62 | `Ctrl + n` — new window 63 | 64 | `Ctrl + b` — go back 65 | 66 | `Ctrl + f` — go forward 67 | 68 | `Ctrl + q` — quit 69 | 70 | `Esc` — stop loading 71 | 72 | `Ctrl + h` — home (bookmarks list) 73 | 74 | `Ctrl + shift + b` — bookmark site (to remove just edit file with 75 | links: bookmarks in your SURFER_DIR dir) 76 | 77 | `Ctrl + o` — toggle url bar 78 | 79 | `Ctrl + /` — find word 80 | 81 | `Ctrl + r` — reload page 82 | 83 | `Ctrl + =` — zoom in 84 | 85 | `Ctrl + -` — zoom out 86 | 87 | `Down Arrow` — scroll down 88 | 89 | `Up arrow` — scroll up 90 | 91 | `Ctrl + w` — page up 92 | 93 | `Ctrl + s` — page down 94 | 95 | `Ctrl + Shift + i` — web inspector (page source) 96 | 97 | `Ctrl + Shift + s` — toggle user style black theme 98 | (/usr/share/surfer/black.css) 99 | 100 | `Ctrl + Shift + h` — show history if enabled 101 | 102 | `F11` — toggle fullscreen 103 | 104 | 105 | 106 | 107 | **Edit `config.h` to change hotkeys and SURFER_DIR, SURFER_DOWNLOADS, and other settings** 108 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #define SURFER_META_MASK GDK_CONTROL_MASK 2 | #define SURFER_NEW_WINDOW_KEY GDK_KEY_n 3 | #define SURFER_OPEN_KEY GDK_KEY_o 4 | #define SURFER_CLOSE_KEY GDK_KEY_q 5 | #define SURFER_BACK_KEY GDK_KEY_b 6 | #define SURFER_FORWARD_KEY GDK_KEY_f 7 | #define SURFER_STOP_KEY GDK_KEY_Escape 8 | #define SURFER_RELOAD_KEY GDK_KEY_r 9 | #define SURFER_FIND_KEY GDK_KEY_slash 10 | #define SURFER_HOME_KEY GDK_KEY_h 11 | #define SURFER_BOOKMARK_KEY GDK_KEY_B 12 | #define SURFER_INSPECTOR_KEY GDK_KEY_I 13 | #define SURFER_ZOOM_IN_KEY GDK_KEY_equal 14 | #define SURFER_ZOOM_OUT_KEY GDK_KEY_minus 15 | #define SURFER_FULLSCREEN_KEY GDK_KEY_F11 16 | #define SURFER_HISTORY_KEY GDK_KEY_H 17 | #define SURFER_SCROLL_DOWN_KEY GDK_KEY_Down 18 | #define SURFER_SCROLL_UP_KEY GDK_KEY_Up 19 | #define SURFER_SCROLL_PAGE_DOWN_KEY GDK_KEY_s 20 | #define SURFER_SCROLL_PAGE_UP_KEY GDK_KEY_w 21 | #define SURFER_STYLE_KEY GDK_KEY_S 22 | 23 | #define SURFER_COOKIE_POLICY WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY 24 | 25 | //WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS -Accept all cookies unconditionally. 26 | //WEBKIT_COOKIE_POLICY_ACCEPT_NEVER -Reject all cookies unconditionally. 27 | //WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY -Accept only cookies set by the main document loaded 28 | 29 | #define SURFER_ACCELERATION_2DCANVAS FALSE 30 | 31 | 32 | #define SURFER_ACCELERATION_POLICY WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND 33 | /* 34 | WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND 35 | Hardware acceleration is enabled/disabled as request by web contents. 36 | 37 | WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS 38 | Hardware acceleration is always enabled, even for websites not requesting it. 39 | 40 | WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER 41 | Hardware acceleration is always disabled, even for websites requesting it. 42 | */ 43 | 44 | #define SURFER_SPATIAL_NAVIGATION FALSE//TRUE to enable 45 | #define SURFER_WINDOW_WIDTH 800 46 | #define SURFER_WINDOW_HEIGHT 600 47 | 48 | #define SURFER_THUMBNAIL_WIDTH 80 49 | #define SURFER_THUMBNAIL_HEIGHT 80 50 | #define SURFER_SMOOTH_SCROLLING FALSE 51 | #define SURFER_RESIZABLE_TEXT TRUE 52 | #define SURFER_ZOOM_LEVEL 1 53 | 54 | #define FONT_MIN_SIZE 12 55 | 56 | // tablecss.txt in SURFER_DIR for custom css per site 57 | #define USER_STYLESHEET_FILENAME "/usr/share/surfer/black.css" //change to your style file 58 | #define DEFAULT_STYLE_ENABLE 0 //change to 1 to enable default style 59 | #define ADBLOCK_JSON_FILE "adblock.json" 60 | 61 | #define WEB_EXTENSIONS_DIRECTORY "/usr/lib/surfer" 62 | 63 | //#define DONT_WAIT_FOR_SITE_FULLLOAD //just uncomment if you want so ! 64 | 65 | #define HISTORY_ENABLE 0 //change to 1 to enable history 66 | 67 | #define SURFER_DIR ".surfer" // upper directory(s) must exist 68 | #define SURFER_DOWNLOADS "downloads" 69 | #define SURFER_TMPDOWNLOADS "/tmp" 70 | #define SURFER_BIN "/usr/bin" // upper directory(s) must exist 71 | 72 | #define SURFER_PLAYER "/usr/bin/mpv" // best with youtube-dl on supported sites 73 | #define SURFER_SEARCH_SITE "https://translate.google.com/#auto/en/" 74 | 75 | //"https://www.google.com/search?q=" 76 | -------------------------------------------------------------------------------- /surfer.1: -------------------------------------------------------------------------------- 1 | .TH surfer 1 "2017-1-1" "surfer" "User Commands" 2 | .\" --------------------------------------------------------------------------- 3 | .SH NAME 4 | surfer \- simple keyboard based webkit browser 5 | .\" --------------------------------------------------------------------------- 6 | .SH DESCRIPTION 7 | \fBsurfer\fP is a simple web browser,keyboard based. 8 | 9 | For videos install gstreamer packages. 10 | 11 | config.h - customize keys, dirs and some other settings before compile. 12 | 13 | It can also launch mpv( with help of youtube-dl on supported sites) on links, 14 | but remember to pkill -9 mpv if it hogs your cpu, used on non supported sites. 15 | 16 | Beside it can toggle JS and History. Priv mode. You can also set css for sites in .surfer/tablecss.txt file. 17 | 18 | Search or translate for selected text, settable in config.h 19 | 20 | For adblock: 21 | Install https://github.com/jun7/wyebadblock 22 | Then sudo ln -s /usr/lib/wyebrowser/adblock.so /usr/lib/surfer 23 | 24 | Or block through /etc/hosts 25 | 26 | Or save to .surfer/adblock.json file (ie from https://easylist-downloads.adblockplus.org/easylist_min_content_blocker.json ) 27 | 28 | 29 | For JS scripts: 30 | 31 | Js scripts (i.e. from greasefork site) place in .local/share/surfer/ 32 | 33 | name them in following way: 34 | -i.e. for run scripts on www.youtube.com name script file identically. 35 | -if you want script to run on all sites, name it universal.js 36 | 37 | .\" --------------------------------------------------------------------------- 38 | 39 | .SH SHORTCUTS 40 | 41 | \fBCtrl + click\fP open link in new window 42 | 43 | \fBCtrl + n\fP new window 44 | 45 | \fBCtrl + b\fP go back 46 | 47 | \fBCtrl + f\fP go forward 48 | 49 | \fBCtrl + q\fP quit 50 | 51 | \fBEsc\fP stop loading 52 | 53 | \fBCtrl + h\fP home (bookmarks list) 54 | 55 | \fBCtrl + o\fP toggle url bar 56 | 57 | \fBCtrl + /\fP find word 58 | 59 | \fBCtrl + r\fP reload page 60 | 61 | \fBCtrl + =\fP zoom in 62 | 63 | \fBCtrl + -\fP zoom out 64 | 65 | \fBDown Arrow\fP scroll down 66 | 67 | \fBUp arrow\fP scroll up 68 | 69 | \fBCtrl + w\fP page up 70 | 71 | \fBCtrl + s\fP page down 72 | 73 | \fBF11\fP toggle fullscreen 74 | 75 | \fBCtrl + shift + b\fP bookmark site (to remove just edit file with links: fav in your SURFER_DIR dir) 76 | 77 | \fBCtrl + Shift + i\fP web inspector (page source) 78 | 79 | \fBCtrl + Shift + s\fP toggle user style black theme (/usr/share/surfer/black.css) 80 | 81 | \fBCtrl + Shift + h\fP show history if enabled 82 | 83 | Also refer to page of project http://github.com/nihilowy/surfer 84 | 85 | .\" -------------------------------------------------------------------- 86 | 87 | .SH FILES 88 | Files created in your home dir: 89 | .TP 90 | SURFER_DIR/fav - file with bookmarks ( added with ctrl + shift + b, edit if You like to remove any ) 91 | .TP 92 | SURFER_DIR/cookies - file for cookies 93 | .TP 94 | .cache - directory for cached content, localstorage and databases are in .local/share/webkitgtk 95 | .TP 96 | SURFER_DIR/hist - file for history if enabled in surfer.c 97 | .TP 98 | SURFER_DIR/tablecss.txt - file for setting css for site 99 | .TP 100 | SURFER_DOWNLOADS - dir for downloads with SURFER_DIR customizable in config.h 101 | .\" -------------------------------------------------------------------- 102 | .SH LICENSE 103 | \fBsurfer\fP is on GPL 3.0 license. 104 | -------------------------------------------------------------------------------- /black.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | * NIGHTSHIFT - eye care: 4 | 5 | * A darkening style for all websites. 6 | 7 | * by vetinari - 2009 8 | 9 | * contact: vetinari.userstyles@inode.at 10 | 11 | */ 12 | 13 | 14 | body,html { min-height: 100%!important; } 15 | 16 | 17 | html, body { background-color:#111!important } 18 | 19 | 20 | body>*:not(:empty){ background-color:#222!important } 21 | 22 | 23 | body>*>*:not(:empty){ background-color:#222!important } 24 | 25 | 26 | body>*>*>*:not(:empty){ background-color:#282828!important } 27 | 28 | 29 | body>*>*>*>*:not(:empty){ background-color:#282828!important } 30 | 31 | 32 | body>*>*>*>*>*:not(:empty){ background-color:#383838!important } 33 | 34 | 35 | body>*>*>*>*>* *{ background-color:#383838!important } 36 | 37 | 38 | body table[border="0"] td{ background-color:#111!important } 39 | 40 | 41 | body table table[border="0"] td{ background-color:#333!important } 42 | 43 | 44 | body table table table[border="0"] td{ background-color:#222!important } 45 | 46 | 47 | body table table table table[border="0"] td{ background-color:#444!important } 48 | 49 | 50 | body *:empty{ background-color: #252525!important } 51 | 52 | 53 | body p:not(:empty), body p *, body h1, body h1 *, body h2, body h2 *, body h3, 54 | 55 | body h3 *, body h4, body h4 *, body h5, body h5 *, body strong>*, body b>*, body 56 | 57 | em>*, body i>*, body span>*:not(img) { 58 | 59 | background:transparent none!important 60 | 61 | } 62 | 63 | 64 | body h1, body h1 *, body h2, body h2 *, p>strong:only-of-type, 65 | 66 | p>b:only-of-type { 67 | 68 | color: #a98!important 69 | 70 | } 71 | 72 | 73 | body h3, body h3 *, body h4, body h4 *{ color: #aaa!important } 74 | 75 | 76 | *:not([onclick]):not(input):not(a):not(img):not([class^="UI"]), body 77 | 78 | a:not(:empty), div:not([onclick]) { 79 | 80 | background-image:none!important; 81 | 82 | text-indent:0!important 83 | 84 | } 85 | 86 | 87 | *[onclick] { color:#79a!important } 88 | 89 | 90 | *[onclick]:hover { color:#99a8aa!important } 91 | 92 | 93 | body hr { 94 | 95 | background: #666 none!important; 96 | 97 | color: #666!important; 98 | 99 | border:1px solid #666!important; 100 | 101 | height: 1px!important; 102 | 103 | overflow:hidden!important; 104 | 105 | display: block!important 106 | 107 | } 108 | 109 | 110 | * { color: #c0c0c0!important; border-color:#666!important; } 111 | 112 | 113 | * body a, body a * { color: #B6AA7B!important; } 114 | 115 | 116 | body a:hover, body a:hover * { 117 | 118 | color: #D9C077!important; 119 | 120 | text-decoration: underline!important 121 | 122 | } 123 | 124 | 125 | body img,a[href] img, a[href] button, input[type="image"],*[onclick]:empty, body 126 | 127 | a:empty { 128 | 129 | opacity:.5!important 130 | 131 | } 132 | 133 | 134 | body img:hover,a[href]:hover img, a[href]:hover button, *[onclick]:empty:hover, 135 | 136 | body a:empty:hover { 137 | 138 | opacity:1!important 139 | 140 | } 141 | 142 | 143 | body input[type], body textarea[name], body input[name], body input[id], body 144 | 145 | select[name]{ 146 | 147 | -moz-appearance:none!important; 148 | 149 | color: #bbb!important; 150 | 151 | -moz-border-radius:4px !important; 152 | 153 | border-width: 1px!important; 154 | 155 | border-color: #778!important; 156 | 157 | border-style:solid!important; 158 | 159 | background:#555 none !important 160 | 161 | } 162 | 163 | 164 | body select[name] { 165 | 166 | -moz-appearance:none!important; 167 | 168 | color: #bbb!important; 169 | 170 | -moz-border-radius:4px !important; 171 | 172 | border-width: 1px!important; 173 | 174 | border-color: #778!important; 175 | 176 | border-style:solid!important; 177 | 178 | background-color:#555!important 179 | 180 | } 181 | 182 | 183 | body input>*, body textarea>* { 184 | 185 | background:transparent none !important; 186 | 187 | color: #bbb!important; 188 | 189 | border-style:solid!important; 190 | 191 | border-width: 0px!important; 192 | 193 | } 194 | 195 | 196 | body select * { 197 | 198 | background-color:transparent !important; 199 | 200 | color: #bbb!important; 201 | 202 | border-style:solid!important; 203 | 204 | border-width: 0px!important; 205 | 206 | } 207 | 208 | 209 | pre:not(:empty), code:not(:empty) , cite:not(:empty), pre:not(:empty) *, 210 | 211 | code:not(:empty) *, cite:not(:empty) 212 | 213 | * { 214 | 215 | background-image:url(data:image/gif;base64,R0lGODlhBAAEAIAAABERESIiIiH5BAAAAAAALAAAAAAEAAQAAAIGTACXaHkFADs=)!important; 216 | 217 | color: #bcc8dc!important;} 218 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /surfer.c: -------------------------------------------------------------------------------- 1 | 2 | /* Copyright © 2017 nihilowy@gmail.com 3 | * 4 | * This file is part of surfer 5 | * 6 | * Surfer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Surfer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Surfer. If not, see . 18 | * 19 | */ 20 | 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "config.h" 34 | 35 | 36 | typedef struct Client{ 37 | GtkWidget *main_window; 38 | GtkWidget *entry_find; 39 | GtkWidget *entry_open; 40 | GtkWidget *box_find; 41 | 42 | GtkWidget *button_goback; 43 | GtkWidget *button_goforward; 44 | GtkWidget *button_dm; 45 | GtkWidget *button_js; 46 | GtkWidget *button_bookmark; 47 | GtkWidget *button_history; 48 | GtkWidget *button_find_back; 49 | GtkWidget *button_find_close; 50 | 51 | 52 | GtkWidget *box_open; 53 | 54 | GtkWidget *vbox; 55 | 56 | WebKitWebView *webView; 57 | // WebKitPolicyDecision *decision1; 58 | WebKitFindController *fc; 59 | WebKitHitTestResult *mousepos; 60 | 61 | 62 | gboolean f; 63 | gboolean fs; 64 | gboolean s; 65 | gboolean o; 66 | 67 | gboolean enablejs; 68 | int progress; 69 | const gchar *title,*overtitle,*url,*targeturi; 70 | 71 | 72 | /* TLS information. */ 73 | GTlsCertificate *certificate; 74 | GTlsCertificateFlags tls_errors; 75 | 76 | gboolean bypass_safe_browsing; 77 | gboolean loading_error_page; 78 | char *tls_error_failing_uri; 79 | 80 | 81 | 82 | 83 | } Client; 84 | 85 | 86 | typedef struct { 87 | GMainLoop* mainLoop; //{ nullptr }; 88 | WebKitUserContentFilter* filter; // { nullptr }; 89 | GError* error; // { nullptr }; 90 | } FilterSaveData; 91 | 92 | static GMainContext* context; 93 | 94 | 95 | static GtkWidget *menuitem1; 96 | static GtkWidget *menu; 97 | 98 | GHashTable *tablecss; 99 | GList *permited; 100 | GList *denied; 101 | 102 | static gint clients = 0,downloads = 0; 103 | gchar *home; 104 | gchar *history; 105 | gchar *favpath; 106 | gchar *contentpath; 107 | gchar *histpath; 108 | gchar *permitedpath; 109 | gchar *deniedpath; 110 | gchar *downloads_dir; 111 | gchar *surfer_dir; 112 | gchar *surfer_img_dir; 113 | gchar *js_dir; 114 | gchar *bin_dir; 115 | 116 | 117 | static gboolean isrelated = TRUE; 118 | static gboolean recordhistory= TRUE; 119 | static gboolean wc_setup_done = FALSE; 120 | static gboolean istmpdownload =FALSE; 121 | 122 | static gboolean priv=FALSE; 123 | 124 | static gboolean enablehist=FALSE; 125 | 126 | static void destroy_window(GtkWidget* w,Client *rc); 127 | //static void tls_certs(WebKitWebContext *wc); 128 | static void allow_tls_cert (Client *c); 129 | static void display_webview( WebKitWebView *rc,Client *c); 130 | 131 | static gboolean close_request(WebKitWebView *view,Client *c); 132 | 133 | static Client *client_new(Client *rc); 134 | static WebKitWebView *clientview(Client *c, WebKitWebView *rv); 135 | 136 | static gboolean crashed(WebKitWebView *v, Client *c); 137 | static gboolean permission_request_cb (WebKitWebView *web_view,WebKitPermissionRequest *request,Client *c); 138 | 139 | static gboolean shownotification (WebKitWebView*web_view,WebKitNotification *notification,Client *c); 140 | 141 | static void loadurl(Client *rc, gchar *url); 142 | 143 | static WebKitWebView *create_request(WebKitWebView *rv,WebKitNavigationAction *navact, Client *c); 144 | 145 | static gboolean decide_policy(WebKitWebView *v,WebKitPolicyDecision *decision,WebKitPolicyDecisionType type, Client *c); 146 | static void decide_navaction(WebKitPolicyDecision *decision,Client *c); 147 | static void decide_newwindow(WebKitPolicyDecision *decision,Client *c); 148 | static void decide_response(WebKitPolicyDecision *decision,Client *c); 149 | 150 | static gboolean download_button_press( Client *c); 151 | static gboolean download_handle(WebKitDownload *, gchar *, gpointer); 152 | static void download_handle_start(WebKitWebView *, WebKitDownload *, gpointer); 153 | static void download_cancel( GtkWidget *,WebKitDownload *download); 154 | static void download_handle_finished(WebKitDownload *download, gpointer data); 155 | static void download_progress( WebKitDownload *download,GParamSpec *pspec, GtkWidget *tb); 156 | 157 | 158 | static void changed_title(WebKitWebView *view, GParamSpec *ps, Client *c); 159 | static void changed_url(WebKitWebView *rv,Client *c ); 160 | static void changed_webload(WebKitWebView *webview,WebKitLoadEvent event, Client *c); 161 | static void changed_estimated(WebKitWebView *webview, GParamSpec *pspec,Client *c); 162 | 163 | static void update_title(Client *c); 164 | 165 | static gboolean menucreate_cb (WebKitWebView *web_view,WebKitContextMenu *context_menu,GdkEvent *event, WebKitHitTestResult *h,Client *c); 166 | static void downloadtmphandler(Client *c); 167 | static void mpvhandler(Client *c); 168 | static void openhandler(Client *c); 169 | static void prvhandler(Client *c); 170 | static void mousetargetchanged(WebKitWebView *v, WebKitHitTestResult *h,guint modifiers, Client *c); 171 | static void searchhandler(Client *c); 172 | static void search_finished (GObject *source_object,GAsyncResult *res,gpointer user_data); 173 | 174 | 175 | 176 | static gboolean keyboard(GtkWidget *widget, GdkEvent *event, Client *c, gpointer ); 177 | static void openlink(GtkWidget *widget,Client *c); 178 | 179 | static void find(GtkWidget *widget,Client *c); 180 | static void find_close( Client *c); 181 | static void find_back(GtkWidget * widget,Client *c); 182 | 183 | static void togglejs_cb(GtkWidget * widget,Client *c); 184 | static void toggleab_cb(GtkWidget * widget,Client *c); 185 | static void togglehistory_cb(GtkWidget * widget,Client *c); 186 | static void togglefind_cb(Client *c); 187 | static void toggleopen_cb(GtkWidget *widget,Client *c); 188 | static void togglefullscreen_cb(Client *c); 189 | static void toggleuserstyle_cb(Client *c); 190 | static void goback(WebKitWebView *rv,Client *c); 191 | static void goforward(WebKitWebView *rv,Client *c); 192 | static void bookmark_cb(WebKitWebView *webview,Client *c); 193 | static void png_finished(GObject *object, GAsyncResult *result, gpointer user_data); 194 | 195 | static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResult *result, FilterSaveData *data); 196 | static void filterLoadedCallback(WebKitUserContentFilterStore *store, GAsyncResult *result, FilterSaveData *data); 197 | 198 | 199 | static gboolean setup(); 200 | static GHashTable *create_hash_table_from_file (gchar *tablepath); 201 | static GList *create_glist_from_file (gchar *listpath); 202 | static void remove_newline(char buffer[]); 203 | static void destroy_hash_table (GHashTable *table); 204 | 205 | 206 | 207 | static void 208 | destroy_window(GtkWidget* w,Client *c) { 209 | webkit_web_view_stop_loading(c->webView); 210 | free(c); 211 | clients--; 212 | 213 | 214 | gchar *cmd = "pkill -9 WebKitWebProces"; 215 | GError *err = NULL; 216 | 217 | if (clients == 0){ 218 | destroy_hash_table(tablecss); 219 | 220 | 221 | 222 | cmd = g_strdup_printf("%s", cmd); 223 | 224 | if (!g_spawn_command_line_async (cmd,&err)) 225 | { 226 | g_warning("Surfer cant't spawn '%s' %s",cmd,err->message); 227 | g_error_free (err); 228 | } 229 | 230 | gtk_main_quit(); 231 | } 232 | } 233 | 234 | gboolean 235 | close_request(WebKitWebView *view,Client *c) { 236 | 237 | 238 | gtk_widget_destroy(c->main_window); 239 | 240 | return TRUE; 241 | } 242 | 243 | 244 | gboolean crashed(WebKitWebView *v, Client *c){ 245 | 246 | 247 | webkit_web_view_reload(c->webView); 248 | 249 | return TRUE; 250 | 251 | } 252 | 253 | 254 | void 255 | display_webview(WebKitWebView *rc, Client *c) 256 | { 257 | // printf("new\n"); 258 | gtk_widget_show_all(c->main_window); 259 | gtk_widget_grab_focus(GTK_WIDGET(c->webView)); 260 | gtk_widget_hide(c->box_find); 261 | gtk_widget_hide(c->box_open); 262 | } 263 | 264 | WebKitWebView *create_request(WebKitWebView *rv,WebKitNavigationAction *navact, Client *c) 265 | { 266 | Client *rc; 267 | 268 | rc = client_new(c); 269 | // rc->webView = rv; 270 | return rc->webView; 271 | } 272 | 273 | 274 | 275 | 276 | Client *client_new(Client *rc) { 277 | 278 | Client *c; 279 | 280 | // c = malloc(sizeof(Client)); 281 | c = calloc(1, sizeof(Client)); 282 | 283 | 284 | 285 | c->o = FALSE; 286 | c->f = FALSE; 287 | c->s = FALSE; 288 | c->fs = FALSE; 289 | c->main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 290 | 291 | gtk_window_set_default_size(GTK_WINDOW(c->main_window), SURFER_WINDOW_WIDTH, SURFER_WINDOW_HEIGHT); 292 | 293 | // c->webView = clientview(c); 294 | if(priv){ 295 | c->webView = clientview(c,NULL); 296 | priv = FALSE; 297 | } 298 | else{ 299 | c->webView = clientview(c, rc ? rc->webView : NULL); 300 | } 301 | 302 | c->fc= webkit_web_view_get_find_controller(c->webView); 303 | 304 | 305 | 306 | c->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); 307 | 308 | c->box_find = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); 309 | c->box_open = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); 310 | 311 | c->button_goback = gtk_button_new_with_label("<"); 312 | c->button_goforward = gtk_button_new_with_label(">"); 313 | c->button_dm = gtk_button_new_with_label("[...]"); 314 | 315 | 316 | c->button_bookmark = gtk_button_new_with_label("B"); 317 | c->button_js = gtk_button_new_with_label("JS"); 318 | c->button_history = gtk_button_new_with_label("H"); 319 | 320 | gtk_widget_set_tooltip_text(c->button_dm,"Downloads"); 321 | gtk_widget_set_tooltip_text(c->button_js,"JS toogle"); 322 | gtk_widget_set_tooltip_text(c->button_bookmark,"Bookmark site"); 323 | gtk_widget_set_tooltip_text(c->button_history,"History toogle"); 324 | 325 | gtk_widget_show_all (menuitem1); 326 | gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem1); 327 | 328 | c->button_find_close = gtk_button_new_with_label ("Close"); 329 | c->button_find_back = gtk_button_new_with_label ("Find Back"); 330 | c->entry_find = gtk_entry_new(); 331 | c->entry_open= gtk_entry_new(); 332 | 333 | 334 | gtk_box_pack_start(GTK_BOX(c->box_find), c->entry_find, TRUE, TRUE, 0); 335 | gtk_box_pack_start(GTK_BOX(c->box_find), c->button_find_back, TRUE, TRUE, 0); 336 | gtk_box_pack_end(GTK_BOX(c->box_find), c->button_find_close,TRUE, TRUE, 0); 337 | 338 | gtk_box_pack_start(GTK_BOX(c->box_open), c->button_goback,FALSE, FALSE, 0); 339 | gtk_box_pack_start(GTK_BOX(c->box_open), c->button_goforward,FALSE, FALSE, 0); 340 | gtk_box_pack_start(GTK_BOX(c->box_open), c->button_dm,FALSE, FALSE, 0); 341 | gtk_box_pack_start(GTK_BOX(c->box_open),c->entry_open, TRUE, TRUE, 0); 342 | gtk_box_pack_end(GTK_BOX(c->box_open),c->button_bookmark, FALSE, FALSE, 0); 343 | gtk_box_pack_start(GTK_BOX(c->box_open),c->button_history, FALSE, FALSE, 0); 344 | gtk_box_pack_end(GTK_BOX(c->box_open),c->button_js, FALSE, FALSE, 0); 345 | 346 | 347 | gtk_box_pack_start(GTK_BOX (c->vbox), c->box_open, FALSE, FALSE, 0); 348 | gtk_box_pack_start(GTK_BOX(c->vbox),GTK_WIDGET(c->webView), TRUE, TRUE, 0); 349 | gtk_box_pack_start (GTK_BOX(c->vbox),c->box_find, FALSE, FALSE, 0); 350 | 351 | //gtk_container_add(GTK_CONTAINER(c->button_dm), GTK_WIDGET(menu)); 352 | 353 | gtk_container_add(GTK_CONTAINER(c->main_window), GTK_WIDGET(c->vbox)); 354 | 355 | 356 | 357 | g_signal_connect(G_OBJECT(c->box_open), "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); 358 | g_signal_connect(G_OBJECT(c->entry_open), "activate", G_CALLBACK(openlink), c); 359 | 360 | 361 | g_signal_connect(G_OBJECT(c->button_goback), "clicked", G_CALLBACK(goback), c); 362 | g_signal_connect(G_OBJECT(c->button_goforward), "clicked", G_CALLBACK(goforward), c); 363 | g_signal_connect(G_OBJECT(c->button_dm), "clicked", G_CALLBACK(download_button_press), c); 364 | g_signal_connect(G_OBJECT(c->button_bookmark), "clicked", G_CALLBACK(bookmark_cb), c); 365 | g_signal_connect(G_OBJECT(c->button_history), "clicked", G_CALLBACK(togglehistory_cb), c); 366 | g_signal_connect(G_OBJECT(c->button_js), "clicked", G_CALLBACK(togglejs_cb), c); 367 | g_signal_connect(G_OBJECT(c->entry_find), "activate", G_CALLBACK(find), c); 368 | g_signal_connect(G_OBJECT(c->button_find_back), "clicked", G_CALLBACK(find_back), c); 369 | g_signal_connect_swapped (G_OBJECT (c->button_find_close), "clicked",G_CALLBACK (find_close),c); 370 | 371 | g_signal_connect(G_OBJECT(c->main_window), "key-press-event", G_CALLBACK(keyboard),c); 372 | g_signal_connect(G_OBJECT(c->main_window), "destroy", G_CALLBACK(destroy_window), c); 373 | 374 | 375 | gtk_widget_show_all(c->main_window); 376 | // gtk_widget_grab_focus(GTK_WIDGET(c->webView)); 377 | 378 | display_webview(NULL, c); 379 | 380 | if (DEFAULT_STYLE_ENABLE == 1){ 381 | toggleuserstyle_cb(c); 382 | } 383 | 384 | 385 | if (HISTORY_ENABLE == 1) 386 | enablehist = TRUE; 387 | 388 | 389 | c->enablejs =TRUE; 390 | webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(c->webView), SURFER_ZOOM_LEVEL); 391 | 392 | clients++; 393 | return c; 394 | } 395 | 396 | 397 | 398 | WebKitWebView *clientview(Client *c,WebKitWebView *rv) 399 | { 400 | WebKitWebView *view; 401 | 402 | WebKitUserContentManager *contentmanager; 403 | WebKitWebsiteDataManager *mgr; 404 | WebKitCookieManager *cookiemgr; 405 | 406 | WebKitWebContext *wc; 407 | WebKitSettings *settings; 408 | 409 | int z; 410 | 411 | FILE *File; 412 | 413 | gchar *cookie_file = g_build_filename(surfer_dir, "cookie", NULL); 414 | 415 | gchar *datadir = g_build_filename(g_get_user_data_dir() , g_get_prgname(), NULL); 416 | gchar *cachedir = g_build_filename(g_get_user_cache_dir(), g_get_prgname(), NULL); 417 | 418 | 419 | if (rv) 420 | 421 | // if(isrelated) 422 | view = WEBKIT_WEB_VIEW(webkit_web_view_new_with_related_view(rv)); 423 | // printf("related\n"); 424 | // else{ 425 | // view = WEBKIT_WEB_VIEW(webkit_web_view_new()); //_with_context(webkit_web_view_get_context(rv))); 426 | // isrelated = TRUE; 427 | // } 428 | 429 | 430 | 431 | else { 432 | 433 | 434 | 435 | if(priv) 436 | mgr = webkit_website_data_manager_new_ephemeral(); 437 | else 438 | 439 | mgr = webkit_website_data_manager_new("base-data-directory" , datadir,"base-cache-directory", cachedir,NULL); 440 | 441 | 442 | 443 | 444 | wc = webkit_web_context_new_with_website_data_manager(mgr); 445 | 446 | settings = webkit_settings_new(); 447 | 448 | contentmanager = webkit_user_content_manager_new(); 449 | 450 | 451 | 452 | 453 | if (g_file_test(contentpath, G_FILE_TEST_EXISTS) && !priv){ 454 | GFile* contentFilterFile = g_file_new_for_path(contentpath); 455 | 456 | FilterSaveData saveData; 457 | gchar* filtersPath = g_build_filename(g_get_user_cache_dir(), g_get_prgname(), "filters", NULL); 458 | WebKitUserContentFilterStore* store = webkit_user_content_filter_store_new(filtersPath); 459 | g_free(filtersPath); 460 | 461 | 462 | webkit_user_content_filter_store_load(store, "BrowserFilter", NULL, (GAsyncReadyCallback)filterLoadedCallback, &saveData); 463 | saveData.mainLoop = g_main_loop_new(NULL, FALSE); 464 | g_main_loop_run(saveData.mainLoop); 465 | 466 | if (!saveData.filter){ 467 | webkit_user_content_filter_store_save_from_file(store, "BrowserFilter", contentFilterFile, NULL, (GAsyncReadyCallback)filterSavedCallback, &saveData); 468 | saveData.mainLoop = g_main_loop_new(NULL, FALSE); 469 | g_main_loop_run(saveData.mainLoop); 470 | } 471 | g_object_unref(store); 472 | 473 | if (saveData.filter) { 474 | webkit_user_content_manager_add_filter(contentmanager, saveData.filter); 475 | } else 476 | g_printerr("Cannot save filter '%s': %s\n", contentpath, saveData.error->message); 477 | 478 | // g_clear_pointer(&saveData.error, g_error_free); 479 | g_clear_pointer(&saveData.filter, webkit_user_content_filter_unref); 480 | g_main_loop_unref(saveData.mainLoop); 481 | g_object_unref(contentFilterFile); 482 | } 483 | 484 | 485 | //view= WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(wc)); 486 | //char *value = "Mozilla/5.0"; 487 | //g_object_set(settings, "user-agent", &value, NULL); 488 | 489 | if (!wc_setup_done) 490 | { 491 | 492 | g_signal_connect(G_OBJECT(wc), "download-started", G_CALLBACK(download_handle_start), NULL); 493 | wc_setup_done = TRUE; 494 | } 495 | 496 | g_object_set(G_OBJECT(settings), "minimum-font-size", FONT_MIN_SIZE, NULL); 497 | g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL); 498 | // g_object_set(G_OBJECT(settings), "enable-webgl", TRUE, NULL); 499 | 500 | g_object_set(G_OBJECT(settings), "enable-mediasource", TRUE, NULL); 501 | g_object_set(G_OBJECT(settings),"enable-javascript", TRUE, NULL); 502 | 503 | 504 | 505 | 506 | webkit_settings_set_enable_smooth_scrolling(settings,SURFER_SMOOTH_SCROLLING); 507 | webkit_settings_set_enable_resizable_text_areas (settings,SURFER_RESIZABLE_TEXT); 508 | webkit_settings_set_enable_spatial_navigation(settings,SURFER_SPATIAL_NAVIGATION); 509 | 510 | webkit_settings_set_hardware_acceleration_policy(settings, SURFER_ACCELERATION_POLICY); 511 | 512 | webkit_web_context_set_process_model(wc,WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES); 513 | 514 | webkit_web_context_set_web_extensions_directory(wc, WEB_EXTENSIONS_DIRECTORY); 515 | webkit_website_data_manager_set_itp_enabled(webkit_web_context_get_website_data_manager(wc), true); 516 | 517 | webkit_web_context_initialize_notification_permissions(wc,permited,denied); 518 | 519 | 520 | //webkit_web_context_set_sandbox_enabled(wc, FALSE); 521 | 522 | webkit_web_context_add_path_to_sandbox(wc, WEB_EXTENSIONS_DIRECTORY, TRUE); 523 | webkit_web_context_add_path_to_sandbox(wc, js_dir, TRUE); 524 | 525 | 526 | 527 | if (!g_file_test(cookie_file, G_FILE_TEST_EXISTS)) { 528 | File = fopen(cookie_file, "wb+"); 529 | 530 | fclose(File); 531 | } 532 | 533 | 534 | 535 | 536 | // cookiemgr = webkit_website_data_manager_get_cookie_manager(mgr); 537 | 538 | cookiemgr = webkit_web_context_get_cookie_manager(wc); 539 | 540 | webkit_cookie_manager_set_persistent_storage(cookiemgr, cookie_file,WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE); 541 | webkit_cookie_manager_set_accept_policy(cookiemgr,SURFER_COOKIE_POLICY); 542 | 543 | webkit_website_data_manager_set_tls_errors_policy(mgr, WEBKIT_TLS_ERRORS_POLICY_IGNORE); 544 | //webkit_web_context_set_tls_errors_policy(wc, WEBKIT_TLS_ERRORS_POLICY_IGNORE); 545 | 546 | 547 | view=g_object_new(WEBKIT_TYPE_WEB_VIEW,"settings",settings,"user-content-manager",contentmanager,"web-context",wc,NULL); 548 | 549 | //printf("new\n"); 550 | } 551 | 552 | g_object_connect( 553 | G_OBJECT(view),"signal::load-changed", G_CALLBACK(changed_webload),c, 554 | "signal::notify::title", G_CALLBACK(changed_title),c , 555 | // "signal::notify::url", G_CALLBACK(changed_url), c, 556 | #ifndef DONT_WAIT_FOR_SITE_FULLLOAD 557 | "signal::ready-to-show",G_CALLBACK(display_webview), c, 558 | #endif 559 | "signal::notify::estimated-load-progress",G_CALLBACK(changed_estimated),c, 560 | "signal::decide-policy", G_CALLBACK(decide_policy),c, 561 | "signal::close", G_CALLBACK(close_request), c, 562 | "signal::create",G_CALLBACK(create_request), c, 563 | "signal::context-menu",G_CALLBACK(menucreate_cb), c, 564 | "signal::mouse-target-changed",G_CALLBACK(mousetargetchanged), c, 565 | "signal::show-notification", G_CALLBACK (shownotification), c, 566 | // "signal::web-process-crashed",G_CALLBACK(crashed), c, 567 | "signal::permission-request",G_CALLBACK(permission_request_cb), c, 568 | // "signal::load-failed-with-tls-errors", G_CALLBACK(allow_tls_cert), c, 569 | NULL 570 | ); 571 | 572 | 573 | 574 | 575 | 576 | return view; 577 | } 578 | 579 | 580 | 581 | 582 | void 583 | loadurl(Client *c, gchar *url) 584 | { 585 | gchar *link; 586 | gchar *nospaces; 587 | 588 | nospaces = g_strchug(url); 589 | link = g_ascii_strdown(nospaces, -1); 590 | 591 | if (!g_str_has_prefix(link, "http:") && 592 | !g_str_has_prefix(link, "https:") && 593 | !g_str_has_prefix(link, "file:") && 594 | !g_str_has_prefix(link, "about:")) { 595 | g_free(link); 596 | link = g_strdup_printf("http://%s", url); 597 | } else 598 | 599 | link = g_strdup(url); 600 | 601 | 602 | 603 | // link = soup_uri_normalize(url,NULL); 604 | //printf("%s/n",link); 605 | webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->webView), link); 606 | 607 | g_free(link); 608 | 609 | 610 | 611 | } 612 | 613 | 614 | 615 | gboolean 616 | shownotification (WebKitWebView *web_view,WebKitNotification *notification,Client *c) 617 | { 618 | 619 | 620 | const char *notifytitle = webkit_notification_get_title (notification); 621 | const char *notify = webkit_notification_get_body (notification); 622 | 623 | 624 | NotifyNotification *not; 625 | notify_init("surfer"); 626 | not = notify_notification_new (notifytitle,notify, NULL); 627 | notify_notification_set_timeout (not, 3000); 628 | 629 | if (!notify_notification_show (not, NULL)) { 630 | g_warning("Failed to send notification.\n"); 631 | 632 | } 633 | notify_uninit(); 634 | g_object_unref(G_OBJECT(not)); 635 | 636 | return TRUE; 637 | } 638 | 639 | gboolean permission_request_cb (WebKitWebView *web_view,WebKitPermissionRequest *request,Client *c) 640 | { 641 | 642 | 643 | //WebKitSecurityOrigin *sorigin; 644 | char *msg =NULL; 645 | FILE *fp; 646 | const gchar *tmp; 647 | gchar *tmp2; 648 | 649 | if (WEBKIT_IS_GEOLOCATION_PERMISSION_REQUEST(request)) 650 | msg = "Allow access your location"; 651 | // if (WEBKIT_IS_NOTIFICATION_PERMISSION_REQUEST(request)) 652 | // msg = "Allow desktop notifications"; 653 | 654 | if (WEBKIT_IS_WEBSITE_DATA_ACCESS_PERMISSION_REQUEST(request)) { 655 | WebKitWebsiteDataAccessPermissionRequest *websiteDataAccessRequest = WEBKIT_WEBSITE_DATA_ACCESS_PERMISSION_REQUEST(request); 656 | const gchar *requesting = webkit_website_data_access_permission_request_get_requesting_domain(websiteDataAccessRequest); 657 | const gchar *current = webkit_website_data_access_permission_request_get_current_domain(websiteDataAccessRequest); 658 | msg = g_strdup_printf("Allow \"%s\" to use cookies while browsing \"%s\"?",requesting, current); 659 | } 660 | else if (WEBKIT_IS_USER_MEDIA_PERMISSION_REQUEST(request)) { 661 | if (webkit_user_media_permission_is_for_audio_device(WEBKIT_USER_MEDIA_PERMISSION_REQUEST(request))) { 662 | msg = "Allow access the microphone"; 663 | } 664 | else if (webkit_user_media_permission_is_for_video_device(WEBKIT_USER_MEDIA_PERMISSION_REQUEST(request))) { 665 | msg = "Alllow to access webcam"; 666 | } 667 | } 668 | else 669 | return FALSE; 670 | 671 | GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(c->main_window), 672 | GTK_DIALOG_MODAL, 673 | GTK_MESSAGE_QUESTION, 674 | GTK_BUTTONS_YES_NO, 675 | "%s", 676 | msg); 677 | gtk_widget_show (dialog); 678 | gint result = gtk_dialog_run (GTK_DIALOG (dialog)); 679 | 680 | 681 | 682 | switch (result) { 683 | case GTK_RESPONSE_YES: 684 | webkit_permission_request_allow (request); 685 | break; 686 | default: 687 | webkit_permission_request_deny (request); 688 | break; 689 | } 690 | gtk_widget_destroy (dialog); 691 | 692 | return TRUE; 693 | } 694 | 695 | 696 | 697 | gboolean 698 | download_button_press( Client *c ) 699 | { 700 | 701 | gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL); 702 | 703 | return FALSE; 704 | } 705 | 706 | 707 | void 708 | download_handle_start(WebKitWebView *web_view, WebKitDownload *download, 709 | gpointer data) 710 | { 711 | g_signal_connect(G_OBJECT(download), "decide-destination", 712 | G_CALLBACK(download_handle), data); 713 | } 714 | 715 | 716 | gboolean 717 | download_handle(WebKitDownload *download, gchar *suggested_filename, gpointer data) 718 | { 719 | gchar *sug, *path, *path2 = NULL, *basename; 720 | GtkWidget *tb; 721 | int suffix = 1; 722 | size_t i; 723 | gchar *uri = NULL; 724 | const gchar *download_uri; 725 | gchar *downloadsfilename; 726 | 727 | 728 | GtkWidget *dialog; 729 | GtkFileChooser *chooser; 730 | GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE; 731 | gint res; 732 | 733 | 734 | 735 | 736 | if (!suggested_filename || !*suggested_filename) { 737 | download_uri = webkit_uri_request_get_uri(webkit_download_get_request(download)); 738 | uri = soup_uri_decode(download_uri); 739 | basename = g_filename_display_basename(uri); 740 | g_free(uri); 741 | 742 | suggested_filename = basename; 743 | } 744 | 745 | sug = g_strdup(suggested_filename); 746 | 747 | 748 | dialog = gtk_file_chooser_dialog_new ("Save File", 749 | GTK_WINDOW_TOPLEVEL, 750 | action, 751 | ("Cancel"), 752 | GTK_RESPONSE_CANCEL, 753 | ("Save"), 754 | GTK_RESPONSE_ACCEPT, 755 | NULL); 756 | chooser = GTK_FILE_CHOOSER (dialog); 757 | 758 | gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE); 759 | webkit_download_set_allow_overwrite (download,TRUE); 760 | 761 | 762 | gtk_file_chooser_set_current_folder(chooser,downloads_dir); 763 | gtk_file_chooser_set_current_name (chooser,sug); 764 | 765 | res = gtk_dialog_run (GTK_DIALOG (dialog)); 766 | 767 | if (res == GTK_RESPONSE_ACCEPT) 768 | { 769 | char *filename; 770 | 771 | 772 | filename = gtk_file_chooser_get_filename (chooser); 773 | uri = g_filename_to_uri(filename, NULL, NULL); 774 | webkit_download_set_destination(download, uri); 775 | g_free(uri); 776 | downloads++; 777 | 778 | tb = gtk_menu_item_new_with_label(sug); 779 | gtk_menu_shell_append(GTK_MENU_SHELL(menu),tb); 780 | gtk_widget_show_all (GTK_WIDGET(menu)); 781 | g_free (filename); 782 | 783 | gtk_widget_destroy (dialog); 784 | 785 | g_signal_connect(G_OBJECT(download), "notify::estimated-progress",G_CALLBACK(download_progress), tb); 786 | 787 | g_signal_connect(G_OBJECT(download), "finished",G_CALLBACK(download_handle_finished), NULL); 788 | 789 | g_object_ref(download); 790 | g_signal_connect(G_OBJECT(tb), "activate",G_CALLBACK(download_cancel), download); 791 | 792 | } 793 | else if (res == GTK_RESPONSE_CANCEL) 794 | { 795 | gtk_widget_destroy (dialog); 796 | webkit_download_cancel(download); 797 | } 798 | 799 | // if downloadtmphandler was proceded, then reset downloads_dir onto SURFER_DOWNLOADS, default dir 800 | if (istmpdownload){ 801 | 802 | downloadsfilename = g_strdup_printf("%s", SURFER_DOWNLOADS); 803 | downloads_dir = g_build_filename(downloadsfilename, NULL); 804 | g_free(downloadsfilename); 805 | istmpdownload = FALSE; 806 | 807 | } 808 | 809 | 810 | 811 | g_free(sug); 812 | 813 | return FALSE; 814 | } 815 | 816 | void 817 | download_cancel( GtkWidget *tb,WebKitDownload *download) 818 | { 819 | 820 | webkit_download_cancel(download); 821 | g_object_unref(download); 822 | 823 | gtk_widget_destroy(GTK_WIDGET(tb)); 824 | 825 | } 826 | 827 | void 828 | download_handle_finished(WebKitDownload *download, gpointer data) 829 | { 830 | 831 | const char *notifytitle = g_strdup_printf("Surfer: download finished"); 832 | const char *notify = webkit_download_get_destination (download); 833 | 834 | NotifyNotification *not; 835 | notify_init("surfer"); 836 | not = notify_notification_new (notifytitle,notify, NULL); 837 | notify_notification_set_timeout (not, 3000); 838 | 839 | if (!notify_notification_show (not, NULL)) { 840 | g_warning("Failed to send notification.\n"); 841 | 842 | } 843 | notify_uninit(); 844 | g_object_unref(G_OBJECT(not)); 845 | 846 | downloads--; 847 | // g_object_unref(download); 848 | 849 | } 850 | 851 | 852 | void 853 | download_progress( WebKitDownload *download,GParamSpec *pspec, GtkWidget *tb) 854 | { 855 | WebKitURIResponse *resp; 856 | 857 | const gchar *uri; 858 | gchar *t, *filename, *base; 859 | gdouble p,size_mb; 860 | int b; 861 | p = webkit_download_get_estimated_progress(download); 862 | p = p > 1 ? 1 : p; 863 | p = p < 0 ? 0 : p; 864 | p *= 100; 865 | // b = (int) p; 866 | 867 | 868 | 869 | resp = webkit_download_get_response(download); 870 | size_mb = webkit_uri_response_get_content_length(resp) / 1e6; 871 | 872 | uri = webkit_download_get_destination(download); 873 | filename = g_filename_from_uri(uri, NULL, NULL); 874 | 875 | base = g_path_get_basename(filename); 876 | t = g_strdup_printf("%s (%.0f%% of %.1f MB)", base, p, size_mb); 877 | g_free(filename); 878 | g_free(base); 879 | 880 | gtk_menu_item_set_label(GTK_MENU_ITEM(tb), t); 881 | g_free(t); 882 | 883 | 884 | 885 | } 886 | 887 | void 888 | openhandler(Client *c) 889 | { 890 | char* t; 891 | g_autofree gchar *cmd = NULL; 892 | 893 | t = (char*)c->targeturi; 894 | GError *err = NULL; 895 | 896 | 897 | 898 | GtkWidget *dialog; 899 | GtkFileChooser *chooser; 900 | GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; 901 | gint res; 902 | 903 | 904 | dialog = gtk_file_chooser_dialog_new ("Open File", 905 | GTK_WINDOW_TOPLEVEL, 906 | action, 907 | ("_Cancel"), 908 | GTK_RESPONSE_CANCEL, 909 | ("_Open"), 910 | GTK_RESPONSE_ACCEPT, 911 | NULL); 912 | 913 | chooser = GTK_FILE_CHOOSER (dialog); 914 | gtk_file_chooser_set_current_folder(chooser,bin_dir); 915 | 916 | 917 | res = gtk_dialog_run (GTK_DIALOG (dialog)); 918 | 919 | if (res == GTK_RESPONSE_ACCEPT) 920 | { 921 | char *filename; 922 | filename = gtk_file_chooser_get_filename (chooser); 923 | 924 | cmd = g_strdup_printf("%s %s", filename, t); 925 | 926 | if (!g_spawn_command_line_async (cmd,&err)) 927 | { 928 | g_warning("Surfer cant't spawn '%s' %s",cmd,err->message); 929 | g_error_free (err); 930 | } 931 | g_free (filename); 932 | 933 | gtk_widget_destroy (dialog); 934 | } 935 | else if (res == GTK_RESPONSE_CANCEL) 936 | { 937 | gtk_widget_destroy (dialog); 938 | } 939 | 940 | 941 | 942 | } 943 | 944 | 945 | 946 | 947 | void 948 | mpvhandler(Client *c) 949 | { 950 | g_autofree gchar *cmd = NULL; 951 | char* t; 952 | 953 | t = (gchar*)c->targeturi; 954 | GError *err = NULL; 955 | 956 | 957 | cmd = g_strdup_printf("%s %s", SURFER_PLAYER, t); 958 | if (!g_spawn_command_line_async (cmd,&err)) 959 | { 960 | g_warning("Surfer cant't spawn '%s' %s",cmd,err->message); 961 | g_error_free (err); 962 | } 963 | 964 | } 965 | 966 | void 967 | downloadtmphandler(Client *c) 968 | { 969 | 970 | gchar *downloadsfilename; 971 | 972 | downloadsfilename = g_strdup_printf("%s", SURFER_TMPDOWNLOADS); 973 | downloads_dir = g_build_filename(downloadsfilename, NULL); 974 | 975 | istmpdownload = TRUE; 976 | g_free(downloadsfilename); 977 | 978 | webkit_web_context_download_uri(webkit_web_view_get_context(c->webView),c->targeturi); 979 | 980 | 981 | } 982 | void 983 | search_finished (GObject *source_object,GAsyncResult *res,gpointer user_data) 984 | { 985 | 986 | struct Client *c = (struct Client *)user_data; 987 | // char* t; 988 | Client *rc; 989 | g_autoptr (GError) error = NULL; 990 | WebKitJavascriptResult *js_result; 991 | JSCValue *value = NULL; 992 | 993 | js_result = webkit_web_view_run_javascript_finish (c->webView, res, &error); 994 | if (!js_result) { 995 | g_warning ("Error running javascript: %s", error->message); 996 | return; 997 | } 998 | 999 | value = webkit_javascript_result_get_js_value (js_result); 1000 | if (jsc_value_is_string (value)) { 1001 | JSCException *exception; 1002 | g_autofree gchar *str_value = NULL; 1003 | 1004 | str_value = jsc_value_to_string (value); 1005 | exception = jsc_context_get_exception (jsc_value_get_context (value)); 1006 | if (exception) 1007 | g_warning ("Error running javascript: %s", jsc_exception_get_message (exception)); 1008 | else if (strlen (str_value)){ 1009 | g_autofree gchar *t = NULL; 1010 | t = g_strdup_printf("%s %s", SURFER_SEARCH_SITE,str_value); 1011 | recordhistory=FALSE; 1012 | rc = client_new(c); 1013 | loadurl(rc,t); 1014 | } 1015 | } else { 1016 | g_warning ("Error running javascript: unexpected return value"); 1017 | } 1018 | webkit_javascript_result_unref (js_result); 1019 | 1020 | } 1021 | 1022 | 1023 | 1024 | void 1025 | searchhandler(Client *c) 1026 | { 1027 | 1028 | webkit_web_view_run_javascript(WEBKIT_WEB_VIEW(c->webView),"window.getSelection().toString();", NULL, search_finished , c); 1029 | 1030 | 1031 | } 1032 | 1033 | 1034 | void 1035 | prvhandler(Client *c) 1036 | { 1037 | char* t; 1038 | Client *rc; 1039 | 1040 | t = (char*)c->targeturi; 1041 | priv = TRUE; 1042 | recordhistory=FALSE; 1043 | rc = client_new(c); 1044 | loadurl(rc,t); 1045 | 1046 | 1047 | } 1048 | gboolean 1049 | menucreate_cb (WebKitWebView *web_view, WebKitContextMenu *context_menu,GdkEvent *event, WebKitHitTestResult *h,Client *c) 1050 | { 1051 | 1052 | 1053 | 1054 | WebKitContextMenuItem *menu_item; 1055 | GSimpleAction *action; 1056 | 1057 | if (webkit_hit_test_result_context_is_link(h)) { 1058 | menu_item = webkit_context_menu_item_new_separator(); 1059 | webkit_context_menu_append(context_menu, menu_item); 1060 | 1061 | action = g_simple_action_new("mpv-handler", NULL); 1062 | 1063 | g_signal_connect_swapped(G_OBJECT(action), "activate",G_CALLBACK(mpvhandler), c); 1064 | menu_item = webkit_context_menu_item_new_from_gaction(G_ACTION(action), 1065 | "Play in mpv (if supported)", NULL); 1066 | webkit_context_menu_append(context_menu, menu_item); 1067 | g_object_unref(action); 1068 | action = g_simple_action_new("open-handler", NULL); 1069 | 1070 | g_signal_connect_swapped(G_OBJECT(action), "activate",G_CALLBACK(openhandler), c); 1071 | menu_item = webkit_context_menu_item_new_from_gaction(G_ACTION(action), 1072 | "Open with", NULL); 1073 | webkit_context_menu_append(context_menu, menu_item); 1074 | g_object_unref(action); 1075 | 1076 | action = g_simple_action_new("ephemeral-handler", NULL); 1077 | 1078 | g_signal_connect_swapped(G_OBJECT(action), "activate",G_CALLBACK(prvhandler), c); 1079 | menu_item = webkit_context_menu_item_new_from_gaction(G_ACTION(action), 1080 | "Open in Priv mode", NULL); 1081 | webkit_context_menu_append(context_menu, menu_item); 1082 | g_object_unref(action); 1083 | 1084 | action = g_simple_action_new("downloadtmp-handler", NULL); 1085 | 1086 | g_signal_connect_swapped(G_OBJECT(action), "activate",G_CALLBACK(downloadtmphandler), c); 1087 | menu_item = webkit_context_menu_item_new_from_gaction(G_ACTION(action), 1088 | "Download to /tmp", NULL); 1089 | webkit_context_menu_append(context_menu, menu_item); 1090 | g_object_unref(action); 1091 | 1092 | 1093 | } 1094 | if (webkit_hit_test_result_context_is_selection(h)){ 1095 | 1096 | action = g_simple_action_new("search-handler", NULL); 1097 | 1098 | g_signal_connect_swapped(G_OBJECT(action), "activate",G_CALLBACK(searchhandler), c); 1099 | menu_item = webkit_context_menu_item_new_from_gaction(G_ACTION(action), 1100 | "Search with", NULL); 1101 | webkit_context_menu_append(context_menu, menu_item); 1102 | g_object_unref(action); 1103 | 1104 | } 1105 | 1106 | return FALSE; 1107 | } 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | void 1114 | update_title(Client *c){ 1115 | 1116 | // char *title; 1117 | const gchar *url; 1118 | g_autofree gchar *title = NULL; 1119 | 1120 | url = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->webView)); 1121 | 1122 | 1123 | if (c->progress != 100) 1124 | title = g_strdup_printf("[%i%%] %s",c->progress, c->title); 1125 | else 1126 | title = g_strdup_printf("%s", c->title); 1127 | 1128 | gtk_window_set_title(GTK_WINDOW(c->main_window), title); 1129 | 1130 | 1131 | gtk_entry_set_text(GTK_ENTRY(c->entry_open), url); 1132 | 1133 | 1134 | 1135 | } 1136 | 1137 | 1138 | 1139 | void 1140 | changed_estimated(WebKitWebView *webview, GParamSpec *pspec,Client *c) 1141 | { 1142 | gdouble prog; 1143 | 1144 | if (!c->fs){ 1145 | c->progress = webkit_web_view_get_estimated_load_progress(WEBKIT_WEB_VIEW(c->webView))*100; 1146 | 1147 | 1148 | } 1149 | else { 1150 | prog= webkit_web_view_get_estimated_load_progress(WEBKIT_WEB_VIEW(c->webView)); 1151 | if (prog==1) 1152 | prog=0; 1153 | 1154 | gtk_entry_set_progress_fraction(GTK_ENTRY(c->entry_open), prog); 1155 | } 1156 | update_title(c); 1157 | 1158 | } 1159 | 1160 | 1161 | 1162 | 1163 | void 1164 | changed_title(WebKitWebView *view, GParamSpec *ps, Client *c) { 1165 | 1166 | 1167 | c->title = webkit_web_view_get_title(WEBKIT_WEB_VIEW(c->webView)); 1168 | update_title(c); 1169 | 1170 | 1171 | 1172 | } 1173 | 1174 | void 1175 | changed_url(WebKitWebView *rv,Client *c) { 1176 | 1177 | 1178 | // update_title(c); 1179 | 1180 | } 1181 | 1182 | 1183 | static void changed_webload(WebKitWebView *webview, WebKitLoadEvent event,Client *c) 1184 | { 1185 | FILE *fp; 1186 | 1187 | const gchar *url; 1188 | gchar *tmp,*tmp2; 1189 | char *path; 1190 | char textdate[100]; 1191 | const gchar *csspath = NULL; 1192 | WebKitSecurityOrigin *sorigin; 1193 | 1194 | switch (event) { 1195 | case WEBKIT_LOAD_STARTED: 1196 | break; 1197 | case WEBKIT_LOAD_REDIRECTED: 1198 | break; 1199 | case WEBKIT_LOAD_COMMITTED: 1200 | 1201 | url = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->webView)); 1202 | if( recordhistory==TRUE && enablehist==TRUE ){ 1203 | 1204 | time_t now = time(NULL); 1205 | struct tm *t = localtime(&now); 1206 | strftime(textdate, sizeof(textdate)-1, "%d %m %Y %H:%M", t); 1207 | 1208 | 1209 | fp = fopen(histpath, "a"); 1210 | if (!fp) 1211 | { 1212 | g_warning("Surfer: can't open %s",histpath); 1213 | exit (1); 1214 | } 1215 | fprintf(fp, "\n%s %.100s\n
",textdate,url ); 1216 | fclose(fp); 1217 | 1218 | } 1219 | recordhistory= TRUE; 1220 | 1221 | tmp = g_strdup(url); 1222 | 1223 | if(tmp) { 1224 | sorigin =webkit_security_origin_new_for_uri (tmp); 1225 | tmp2 = webkit_security_origin_to_string (sorigin); 1226 | path = basename(tmp2); 1227 | // printf("%s\n",path); 1228 | 1229 | csspath = g_hash_table_lookup(tablecss,path); 1230 | gchar *contents; 1231 | 1232 | if(csspath){ 1233 | if(g_file_get_contents(csspath,&contents,NULL,NULL)){ 1234 | webkit_user_content_manager_remove_all_style_sheets(webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(c->webView))); 1235 | webkit_user_content_manager_add_style_sheet( 1236 | webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(c->webView)), 1237 | webkit_user_style_sheet_new(contents,WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,WEBKIT_USER_STYLE_LEVEL_USER,NULL, NULL)); 1238 | 1239 | g_free(contents); 1240 | 1241 | } 1242 | 1243 | 1244 | g_free(tmp2); 1245 | g_free(tmp); 1246 | } 1247 | 1248 | 1249 | /* else 1250 | { 1251 | if(!c->s) 1252 | webkit_user_content_manager_remove_all_style_sheets(webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(c->webView))); 1253 | else; 1254 | } 1255 | */ 1256 | } 1257 | break; 1258 | 1259 | case WEBKIT_LOAD_FINISHED: 1260 | 1261 | break; 1262 | default: 1263 | break; 1264 | } 1265 | } 1266 | 1267 | 1268 | 1269 | void 1270 | mousetargetchanged(WebKitWebView *v, WebKitHitTestResult *h, guint modifiers,Client *c) 1271 | { 1272 | WebKitHitTestResultContext hc = webkit_hit_test_result_get_context(h); 1273 | 1274 | gchar *t = NULL; 1275 | c->mousepos = h; 1276 | 1277 | if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK){ 1278 | c->targeturi = webkit_hit_test_result_get_link_uri(h); 1279 | t = (char*)c->targeturi; 1280 | gtk_window_set_title(GTK_WINDOW(c->main_window), t); 1281 | } 1282 | else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) 1283 | c->targeturi = webkit_hit_test_result_get_image_uri(h); 1284 | else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA) 1285 | c->targeturi = webkit_hit_test_result_get_media_uri(h); 1286 | else 1287 | c->targeturi = NULL; 1288 | 1289 | // update_title(c); 1290 | } 1291 | 1292 | 1293 | 1294 | 1295 | gboolean 1296 | decide_policy( WebKitWebView *v,WebKitPolicyDecision *decision, WebKitPolicyDecisionType type,Client *c) { 1297 | 1298 | 1299 | switch (type) { 1300 | case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: 1301 | decide_navaction(decision,c); 1302 | break; 1303 | 1304 | case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION: 1305 | decide_newwindow(decision,c); 1306 | break; 1307 | 1308 | case WEBKIT_POLICY_DECISION_TYPE_RESPONSE: 1309 | decide_response(decision,c); 1310 | break; 1311 | 1312 | default: 1313 | webkit_policy_decision_ignore(decision); 1314 | break; 1315 | } 1316 | return TRUE; 1317 | } 1318 | 1319 | void decide_navaction(WebKitPolicyDecision *decision,Client *c) { 1320 | 1321 | WebKitNavigationType navigation_type; 1322 | WebKitNavigationPolicyDecision *navigationDecision; 1323 | WebKitNavigationAction *navigation_action; 1324 | WebKitURIRequest *request; 1325 | guint button, mods; 1326 | gchar *link; 1327 | gchar *t; 1328 | Client *rc; 1329 | 1330 | 1331 | navigation_action = webkit_navigation_policy_decision_get_navigation_action(WEBKIT_NAVIGATION_POLICY_DECISION(decision)); 1332 | request = webkit_navigation_action_get_request(navigation_action); 1333 | navigation_type = webkit_navigation_action_get_navigation_type(navigation_action); 1334 | 1335 | t = ( gchar *) webkit_uri_request_get_uri(request); 1336 | mods = webkit_navigation_action_get_modifiers(navigation_action); 1337 | button = webkit_navigation_action_get_mouse_button(navigation_action); 1338 | 1339 | 1340 | 1341 | if (navigation_type == WEBKIT_NAVIGATION_TYPE_LINK_CLICKED && button == 1 && mods & SURFER_META_MASK) { 1342 | 1343 | webkit_policy_decision_ignore(decision); 1344 | // printf("new\n"); 1345 | // isrelated = FALSE; 1346 | 1347 | rc = client_new(c); 1348 | loadurl(rc,t); 1349 | // g_free(t); 1350 | } 1351 | else webkit_policy_decision_use(decision); 1352 | // printf("no\n"); 1353 | } 1354 | 1355 | void decide_newwindow(WebKitPolicyDecision *decision,Client *c) 1356 | { 1357 | 1358 | WebKitNavigationType navigation_type; 1359 | WebKitNavigationAction *navigation_action; 1360 | WebKitURIRequest *request; 1361 | gchar *t; 1362 | Client *rc; 1363 | 1364 | navigation_action = webkit_navigation_policy_decision_get_navigation_action(WEBKIT_NAVIGATION_POLICY_DECISION(decision)); 1365 | request = webkit_navigation_action_get_request(navigation_action); 1366 | navigation_type =webkit_navigation_action_get_navigation_type(navigation_action); 1367 | 1368 | switch (navigation_type) { 1369 | case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: 1370 | 1371 | t = (gchar *) webkit_uri_request_get_uri(request); 1372 | rc = client_new(c); 1373 | loadurl(rc,t); 1374 | case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: 1375 | case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: 1376 | case WEBKIT_NAVIGATION_TYPE_RELOAD: 1377 | case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED: 1378 | case WEBKIT_NAVIGATION_TYPE_OTHER: 1379 | default: 1380 | 1381 | break; 1382 | } 1383 | webkit_policy_decision_ignore(decision); 1384 | 1385 | } 1386 | 1387 | void decide_response(WebKitPolicyDecision *decision,Client *c){ 1388 | 1389 | guint status; 1390 | WebKitURIResponse *response; 1391 | 1392 | response = webkit_response_policy_decision_get_response(WEBKIT_RESPONSE_POLICY_DECISION(decision)); 1393 | status = webkit_uri_response_get_status_code(response); 1394 | 1395 | 1396 | if (webkit_response_policy_decision_is_mime_type_supported(WEBKIT_RESPONSE_POLICY_DECISION(decision))) 1397 | webkit_policy_decision_use(decision); 1398 | else if (SOUP_STATUS_IS_SUCCESSFUL(status) || status == SOUP_STATUS_NONE) 1399 | webkit_policy_decision_download(decision); 1400 | else 1401 | webkit_policy_decision_ignore(decision); 1402 | 1403 | } 1404 | 1405 | 1406 | 1407 | 1408 | gboolean 1409 | keyboard(GtkWidget *widget,GdkEvent *event, Client *c, gpointer data) { 1410 | 1411 | 1412 | WebKitWebInspector *inspector; 1413 | 1414 | Client *rc; 1415 | const gchar *url; 1416 | gdouble z; 1417 | guint meta_key_pressed; 1418 | int key_pressed; 1419 | // GdkEvent *event = c->eventt; 1420 | 1421 | 1422 | if (event->type == GDK_KEY_PRESS) { 1423 | key_pressed = ((GdkEventKey *) event)->keyval; 1424 | meta_key_pressed = ((GdkEventKey *) event)->state & SURFER_META_MASK; 1425 | 1426 | if (meta_key_pressed) { 1427 | switch (key_pressed) { 1428 | case SURFER_SCROLL_DOWN_KEY: 1429 | event->key.keyval = GDK_KEY_Down; 1430 | gdk_event_put(event); 1431 | return TRUE; 1432 | 1433 | case SURFER_SCROLL_UP_KEY: 1434 | event->key.keyval = GDK_KEY_Up; 1435 | gdk_event_put(event); 1436 | return TRUE; 1437 | 1438 | case SURFER_SCROLL_PAGE_UP_KEY: 1439 | event->key.keyval = GDK_KEY_Page_Up; 1440 | gdk_event_put(event); 1441 | return TRUE; 1442 | 1443 | case SURFER_SCROLL_PAGE_DOWN_KEY: 1444 | event->key.keyval = GDK_KEY_Page_Down; 1445 | gdk_event_put(event); 1446 | return TRUE; 1447 | 1448 | case SURFER_CLOSE_KEY: 1449 | //gtk_widget_destroy(c->main_window); 1450 | close_request(c->webView,c); 1451 | return TRUE; 1452 | 1453 | case SURFER_BACK_KEY: 1454 | goback(c->webView,c); 1455 | 1456 | return TRUE; 1457 | 1458 | case SURFER_FORWARD_KEY: 1459 | goforward(c->webView,c); 1460 | 1461 | return TRUE; 1462 | 1463 | case SURFER_INSPECTOR_KEY: 1464 | inspector = webkit_web_view_get_inspector(WEBKIT_WEB_VIEW(c->webView)); 1465 | webkit_web_inspector_show(inspector); 1466 | return TRUE; 1467 | 1468 | case SURFER_OPEN_KEY: 1469 | toggleopen_cb(c->box_open,c); 1470 | return TRUE; 1471 | 1472 | case SURFER_HISTORY_KEY: 1473 | recordhistory=FALSE; 1474 | loadurl(c,history); 1475 | return TRUE; 1476 | 1477 | case SURFER_NEW_WINDOW_KEY: 1478 | recordhistory=FALSE; 1479 | // isrelated = FALSE; 1480 | rc = client_new(c); 1481 | loadurl(rc,home); 1482 | return TRUE; 1483 | 1484 | case SURFER_HOME_KEY: 1485 | recordhistory=FALSE; 1486 | loadurl(c,home); 1487 | return TRUE; 1488 | 1489 | case SURFER_RELOAD_KEY: 1490 | recordhistory=FALSE; 1491 | webkit_web_view_reload_bypass_cache(c->webView); 1492 | return TRUE; 1493 | 1494 | case SURFER_FIND_KEY: 1495 | togglefind_cb(c); 1496 | return TRUE; 1497 | 1498 | case SURFER_BOOKMARK_KEY: 1499 | bookmark_cb(c->webView,c); 1500 | return TRUE; 1501 | 1502 | case SURFER_ZOOM_OUT_KEY: 1503 | z = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(c->webView)); 1504 | webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(c->webView), z - 0.1); 1505 | return TRUE; 1506 | 1507 | case SURFER_ZOOM_IN_KEY: 1508 | z = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(c->webView)); 1509 | webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(c->webView), z + 0.1); 1510 | return TRUE; 1511 | case SURFER_STYLE_KEY: 1512 | toggleuserstyle_cb(c); 1513 | return TRUE; 1514 | 1515 | default: 1516 | return FALSE; 1517 | } 1518 | } else { 1519 | switch (key_pressed) { 1520 | case SURFER_FULLSCREEN_KEY: 1521 | togglefullscreen_cb(c); 1522 | return TRUE; 1523 | 1524 | case SURFER_STOP_KEY: 1525 | webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(c->webView)); 1526 | return TRUE; 1527 | 1528 | 1529 | default: 1530 | return FALSE; 1531 | } 1532 | } 1533 | } 1534 | return FALSE; 1535 | } 1536 | 1537 | void 1538 | openlink(GtkWidget * widget,Client *c){ 1539 | 1540 | 1541 | gchar *link; 1542 | const gchar *p; 1543 | 1544 | p = gtk_entry_get_text(GTK_ENTRY(c->entry_open)); 1545 | link = g_strdup(p); 1546 | loadurl(c, link); 1547 | g_free(link); 1548 | gtk_widget_hide(c->box_open); 1549 | } 1550 | 1551 | 1552 | void 1553 | find(GtkWidget * widget,Client *c) { 1554 | 1555 | static gchar *search_text; 1556 | const gchar *p; 1557 | 1558 | 1559 | p = gtk_entry_get_text(GTK_ENTRY(c->entry_find)); 1560 | search_text = g_strdup(p); 1561 | 1562 | if(search_text != NULL){ 1563 | 1564 | webkit_find_controller_search(c->fc, search_text,WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE | WEBKIT_FIND_OPTIONS_WRAP_AROUND, G_MAXUINT); 1565 | webkit_find_controller_count_matches(c->fc, search_text,WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE | WEBKIT_FIND_OPTIONS_WRAP_AROUND, G_MAXUINT); 1566 | g_free(search_text); 1567 | 1568 | } 1569 | 1570 | } 1571 | 1572 | void 1573 | find_close(Client *c) { 1574 | 1575 | gtk_entry_set_text(GTK_ENTRY(c->entry_find), ""); 1576 | find(c->entry_find,c); 1577 | gtk_widget_hide(c->box_find); 1578 | gtk_widget_grab_focus(GTK_WIDGET(c->webView)); 1579 | 1580 | } 1581 | 1582 | 1583 | void 1584 | find_back(GtkWidget * widget,Client *c){ 1585 | 1586 | 1587 | webkit_find_controller_search_previous(c->fc); 1588 | 1589 | 1590 | } 1591 | 1592 | 1593 | void 1594 | png_finished(GObject *object, GAsyncResult *result, gpointer user_data) { 1595 | 1596 | const gchar *title,*url; 1597 | gchar *path,*tmp2,*tmp,*pngpath; 1598 | static char *png_file = NULL; 1599 | FILE *fp; 1600 | WebKitSecurityOrigin *sorigin; 1601 | 1602 | GdkPixbuf *snapshot, *scaled; 1603 | int orig_width, orig_height; 1604 | cairo_surface_t *surface; 1605 | 1606 | 1607 | WebKitWebView *web_view = WEBKIT_WEB_VIEW(object); 1608 | url = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(web_view)); 1609 | title = webkit_web_view_get_title(WEBKIT_WEB_VIEW(web_view)); 1610 | 1611 | tmp = g_strdup(url); 1612 | 1613 | 1614 | 1615 | if(tmp) { 1616 | sorigin =webkit_security_origin_new_for_uri (tmp); 1617 | tmp2 = webkit_security_origin_to_string (sorigin); 1618 | path = basename(tmp2); 1619 | 1620 | pngpath = (gchar *) g_strdup_printf("%s.png",path); 1621 | 1622 | png_file = g_build_filename(surfer_img_dir,pngpath, NULL); 1623 | 1624 | 1625 | } 1626 | 1627 | g_free(tmp); 1628 | g_free(tmp2); 1629 | 1630 | 1631 | GError *error = NULL; 1632 | surface = webkit_web_view_get_snapshot_finish(web_view, result, &error); 1633 | 1634 | if (surface == NULL) { 1635 | g_error( "error creating snapshot: %s",error->message ); 1636 | } 1637 | 1638 | 1639 | orig_width = cairo_image_surface_get_width (surface); 1640 | orig_height = cairo_image_surface_get_height (surface); 1641 | 1642 | 1643 | snapshot = gdk_pixbuf_get_from_surface (surface,0, 0,orig_width, orig_height); 1644 | scaled = gdk_pixbuf_scale_simple (snapshot,SURFER_THUMBNAIL_WIDTH,SURFER_THUMBNAIL_HEIGHT,GDK_INTERP_TILES); 1645 | 1646 | cairo_surface_destroy(surface); 1647 | // cairo_surface_write_to_png(scaled, png_file); 1648 | 1649 | gdk_pixbuf_save(scaled, png_file, "png", &error, NULL); 1650 | 1651 | g_object_unref (snapshot); 1652 | g_object_unref (scaled); 1653 | 1654 | 1655 | fp = fopen(favpath, "a"); 1656 | 1657 | if (!fp) 1658 | 1659 | { 1660 | g_warning("Surfer: can't open %s",favpath); 1661 | exit (1); 1662 | } 1663 | 1664 | 1665 | fprintf(fp, "  ", (char *) url, (char *) png_file, (char *) title); 1666 | fclose(fp); 1667 | 1668 | } 1669 | 1670 | 1671 | void 1672 | bookmark_cb(WebKitWebView *webview,Client *c){ 1673 | 1674 | 1675 | 1676 | webkit_web_view_get_snapshot(c->webView,WEBKIT_SNAPSHOT_REGION_VISIBLE,WEBKIT_SNAPSHOT_OPTIONS_NONE,NULL,png_finished,NULL); 1677 | 1678 | } 1679 | 1680 | 1681 | void 1682 | goback(WebKitWebView *rv,Client *c){ 1683 | 1684 | char *title; 1685 | if (webkit_web_view_can_go_back(c->webView)){ 1686 | webkit_web_view_go_back(WEBKIT_WEB_VIEW(c->webView)); 1687 | recordhistory= FALSE; 1688 | } 1689 | else { 1690 | title = g_strdup_printf(" %s", "Can't go back!"); 1691 | gtk_window_set_title(GTK_WINDOW(c->main_window), title); 1692 | 1693 | } 1694 | } 1695 | 1696 | 1697 | 1698 | void 1699 | goforward(WebKitWebView *rv,Client *c){ 1700 | 1701 | char *title; 1702 | if (webkit_web_view_can_go_forward(c->webView)){ 1703 | webkit_web_view_go_forward(WEBKIT_WEB_VIEW(c->webView)); 1704 | recordhistory= FALSE; 1705 | } 1706 | else { 1707 | title = g_strdup_printf(" %s", "Can't go forward!"); 1708 | gtk_window_set_title(GTK_WINDOW(c->main_window), title); 1709 | 1710 | } 1711 | 1712 | } 1713 | 1714 | 1715 | 1716 | void 1717 | toggleuserstyle_cb(Client *c){ 1718 | 1719 | gchar *contents; 1720 | 1721 | if (!c->s) { 1722 | g_file_get_contents(USER_STYLESHEET_FILENAME,&contents,NULL,NULL); 1723 | webkit_user_content_manager_add_style_sheet( 1724 | webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(c->webView)), 1725 | webkit_user_style_sheet_new(contents, 1726 | WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, 1727 | WEBKIT_USER_STYLE_LEVEL_USER, 1728 | NULL, NULL)); 1729 | 1730 | g_free(contents); 1731 | 1732 | c->s = TRUE; 1733 | } 1734 | else { 1735 | webkit_user_content_manager_remove_all_style_sheets( 1736 | webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(c->webView))); 1737 | c->s = FALSE; 1738 | } 1739 | 1740 | 1741 | } 1742 | 1743 | void 1744 | togglejs_cb(GtkWidget * widget,Client *c){ 1745 | 1746 | //GdkColor color; 1747 | 1748 | WebKitSettings *ssettings; 1749 | 1750 | ssettings=webkit_web_view_get_settings( WEBKIT_WEB_VIEW(c->webView)); 1751 | 1752 | if (c->enablejs){ 1753 | 1754 | g_object_set(G_OBJECT(ssettings),"enable-javascript", FALSE, NULL); 1755 | c->enablejs=FALSE; 1756 | 1757 | // gtk_button_set_label(GTK_BUTTON(c->button_js), "JS-"); 1758 | 1759 | } 1760 | else{ 1761 | //gtk_button_set_label(GTK_BUTTON(c->button_js), "JS+"); 1762 | 1763 | 1764 | g_object_set(G_OBJECT(ssettings),"enable-javascript", TRUE, NULL); 1765 | c->enablejs=TRUE; 1766 | } 1767 | } 1768 | void togglefind_cb(Client *c) 1769 | { 1770 | 1771 | if (!c->f) { 1772 | 1773 | gtk_widget_show_all(c->box_find); 1774 | gtk_widget_grab_focus(c->entry_find); 1775 | 1776 | c->f = TRUE; 1777 | } 1778 | else { 1779 | 1780 | gtk_widget_hide(c->box_find); 1781 | gtk_widget_grab_focus(GTK_WIDGET(c->webView)); 1782 | c->f = FALSE; 1783 | } 1784 | 1785 | 1786 | } 1787 | 1788 | void toggleopen_cb(GtkWidget *widget,Client *c) 1789 | { 1790 | const gchar *url; 1791 | if (!c->o) { 1792 | 1793 | gtk_widget_show_all(c->box_open); 1794 | gtk_widget_grab_focus(c->entry_open); 1795 | // url = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->webView)); 1796 | // gtk_entry_set_text(GTK_ENTRY(c->entry_open), url); 1797 | c->o = TRUE; 1798 | } 1799 | else { 1800 | 1801 | gtk_widget_hide(c->box_open); 1802 | gtk_widget_grab_focus(GTK_WIDGET(c->webView)); 1803 | c->o = FALSE; 1804 | } 1805 | 1806 | 1807 | } 1808 | 1809 | 1810 | void 1811 | togglehistory_cb(GtkWidget *widget,Client *c) 1812 | { 1813 | if (!enablehist){ 1814 | enablehist=TRUE; 1815 | // gtk_button_set_label(GTK_BUTTON(c->button_history), "HIST+"); 1816 | } 1817 | else 1818 | { 1819 | 1820 | enablehist=FALSE; 1821 | //gtk_button_set_label(GTK_BUTTON(c->button_history), "HIST-"); 1822 | } 1823 | 1824 | 1825 | } 1826 | 1827 | void togglefullscreen_cb(Client *c) 1828 | { 1829 | 1830 | if (!c->fs ) { 1831 | gtk_window_fullscreen(GTK_WINDOW(c->main_window)); 1832 | c->fs = TRUE; 1833 | } else { 1834 | gtk_window_unfullscreen(GTK_WINDOW(c->main_window)); 1835 | c->fs = FALSE; 1836 | } 1837 | 1838 | } 1839 | 1840 | void 1841 | allow_tls_cert(Client *c) 1842 | { 1843 | SoupURI *uri; 1844 | gchar *url; 1845 | gchar *tls_message; 1846 | 1847 | g_assert (G_IS_TLS_CERTIFICATE (c->certificate)); 1848 | g_assert (c->tls_error_failing_uri != NULL); 1849 | 1850 | uri = soup_uri_new (c->tls_error_failing_uri); 1851 | webkit_web_context_allow_tls_certificate_for_host (webkit_web_view_get_context(c->webView),c->certificate,uri->host); 1852 | 1853 | } 1854 | 1855 | void remove_newline(char buffer[]) { 1856 | size_t slen; 1857 | 1858 | slen = strlen(buffer); 1859 | 1860 | /* safe way to remove '\n' and check for bufferoverflow */ 1861 | if (slen > 0) { 1862 | if (buffer[slen-1] == '\n') { 1863 | buffer[slen-1] = '\0'; 1864 | } else { 1865 | printf("Buffer overflow detected.\n"); 1866 | exit(EXIT_FAILURE); 1867 | } 1868 | } 1869 | } 1870 | 1871 | 1872 | GHashTable 1873 | *create_hash_table_from_file (gchar *tablepath) 1874 | { 1875 | FILE *fp; 1876 | char buf[1024]; 1877 | GHashTable *table; 1878 | char *key; 1879 | char *value; 1880 | 1881 | table = g_hash_table_new (g_str_hash, g_str_equal); 1882 | 1883 | fp = fopen (tablepath, "r"); 1884 | 1885 | if (!fp) 1886 | 1887 | { 1888 | g_warning("Surfer: can't open %s",tablepath); 1889 | exit (1); 1890 | } 1891 | 1892 | while (fgets (buf, sizeof (buf), fp) !=NULL) 1893 | { 1894 | remove_newline(buf); 1895 | key = strtok (buf, "="); 1896 | if (!key) continue; 1897 | value = strtok (NULL, "="); 1898 | if (!value) continue; 1899 | g_hash_table_insert (table, g_strdup (key), g_strdup (value)); 1900 | } 1901 | fclose (fp); 1902 | return table; 1903 | } 1904 | 1905 | GList *create_glist_from_file (gchar *listpath) 1906 | { 1907 | FILE *fp; 1908 | char buf[1024]; 1909 | GList *list = NULL; 1910 | WebKitSecurityOrigin *sorigin; 1911 | 1912 | fp = fopen (listpath, "r"); 1913 | 1914 | if (!fp) 1915 | 1916 | { 1917 | g_warning("Surfer: can't open %s",listpath); 1918 | exit (1); 1919 | } 1920 | 1921 | while (fgets (buf, sizeof (buf), fp) !=NULL) 1922 | { 1923 | 1924 | sorigin = webkit_security_origin_new_for_uri(buf); 1925 | list = g_list_append(list,sorigin); 1926 | 1927 | } 1928 | fclose (fp); 1929 | return list; 1930 | 1931 | } 1932 | void 1933 | destroy_hash_table (GHashTable *table) 1934 | { 1935 | 1936 | g_hash_table_destroy (table); 1937 | 1938 | } 1939 | 1940 | void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResult *result, FilterSaveData *data) 1941 | { 1942 | data->filter = webkit_user_content_filter_store_save_finish(store, result, &data->error); 1943 | g_main_loop_quit(data->mainLoop); 1944 | } 1945 | 1946 | void filterLoadedCallback(WebKitUserContentFilterStore *store, GAsyncResult *result, FilterSaveData *data) 1947 | { 1948 | data->filter = webkit_user_content_filter_store_load_finish(store, result, &data->error); 1949 | g_main_loop_quit(data->mainLoop); 1950 | } 1951 | 1952 | 1953 | 1954 | 1955 | 1956 | 1957 | gboolean setup(){ 1958 | 1959 | 1960 | 1961 | gchar *binfilename,*downloadsfilename,*surferdirfilename,*jsdirfilename,*surferimgdirfilename; 1962 | gchar *tablecsspath; 1963 | FILE *File,*File1,*File2; 1964 | char buffer[256] = "Surfer

"; 1966 | 1967 | char buffercss[80]= "example.com=/usr/share/surfer/black.css\n"; 1968 | char bufferhome[256]= "

surfer


"; 1969 | 1970 | 1971 | binfilename = g_strdup_printf("%s", SURFER_BIN); 1972 | bin_dir = g_build_filename( binfilename, NULL); 1973 | g_free(binfilename); 1974 | 1975 | downloadsfilename = g_strdup_printf("%s", SURFER_DOWNLOADS); 1976 | downloads_dir = g_build_filename(getenv("HOME"), downloadsfilename, NULL); 1977 | g_free(downloadsfilename); 1978 | 1979 | 1980 | surferdirfilename = g_strdup_printf("%s", SURFER_DIR); 1981 | surferimgdirfilename = g_strdup_printf("%s", "img"); 1982 | surfer_dir = g_build_filename(getenv("HOME"), surferdirfilename, NULL); 1983 | surfer_img_dir = g_build_filename(getenv("HOME"), surferdirfilename,surferimgdirfilename, NULL); 1984 | 1985 | g_free(surferdirfilename); 1986 | g_free(surferimgdirfilename); 1987 | 1988 | 1989 | jsdirfilename = g_strdup_printf("%s", ".local/share/surfer"); 1990 | js_dir = g_build_filename(getenv("HOME"), jsdirfilename, NULL); 1991 | g_free(jsdirfilename); 1992 | 1993 | 1994 | 1995 | if (!g_file_test(downloads_dir, G_FILE_TEST_EXISTS)) { 1996 | mkdir(downloads_dir, 0700); 1997 | 1998 | } 1999 | 2000 | if (!g_file_test(surfer_dir, G_FILE_TEST_EXISTS)) { 2001 | mkdir(surfer_dir, 0700); 2002 | 2003 | } 2004 | 2005 | if (!g_file_test(surfer_img_dir, G_FILE_TEST_EXISTS)) { 2006 | 2007 | mkdir(surfer_img_dir, 0700); 2008 | } 2009 | 2010 | contentpath = g_build_filename(surfer_dir,ADBLOCK_JSON_FILE, NULL); 2011 | 2012 | favpath = g_build_filename(surfer_dir,"bookmarks", NULL); 2013 | 2014 | histpath = g_build_filename(surfer_dir, "hist", NULL); 2015 | 2016 | tablecsspath = g_build_filename(surfer_dir, "tablecss.txt", NULL); 2017 | 2018 | permitedpath = g_build_filename(surfer_dir,"permited", NULL); 2019 | 2020 | deniedpath = g_build_filename(surfer_dir,"denied", NULL); 2021 | 2022 | if (!g_file_test(favpath, G_FILE_TEST_EXISTS)) { 2023 | File = fopen(favpath, "wb+"); 2024 | fprintf(File, "%s", bufferhome); 2025 | fprintf(File, "%s", buffer); 2026 | fclose(File); 2027 | 2028 | } 2029 | 2030 | 2031 | //if (HISTORY_ENABLE == 1) 2032 | 2033 | if (!g_file_test(histpath, G_FILE_TEST_EXISTS)) { 2034 | File1 = fopen(histpath, "wb+"); 2035 | fprintf(File1, "%s", buffer); 2036 | fclose(File1); 2037 | 2038 | } 2039 | 2040 | if (!g_file_test(tablecsspath, G_FILE_TEST_EXISTS)) { 2041 | File2 = fopen(tablecsspath, "wb+"); 2042 | fprintf(File2, "%s", buffercss); 2043 | fclose(File2); 2044 | } 2045 | /* 2046 | if (!g_file_test(permitedpath, G_FILE_TEST_EXISTS)) { 2047 | File2 = fopen(permitedpath, "wb+"); 2048 | fclose(File2); 2049 | } 2050 | 2051 | if (!g_file_test(deniedpath, G_FILE_TEST_EXISTS)) { 2052 | File2 = fopen(deniedpath, "wb+"); 2053 | fclose(File2); 2054 | } 2055 | */ 2056 | history = (gchar *) g_strdup_printf("file://%s", histpath); 2057 | 2058 | home = (gchar *) g_strdup_printf("file://%s", favpath); 2059 | 2060 | tablecss = create_hash_table_from_file (tablecsspath); 2061 | 2062 | istmpdownload=FALSE; 2063 | 2064 | // permited = create_glist_from_file(permitedpath); 2065 | // denied = create_glist_from_file(deniedpath); 2066 | 2067 | return TRUE; 2068 | } 2069 | 2070 | 2071 | int main(int argc, char *argv[]) { 2072 | 2073 | Client *c; 2074 | int i; 2075 | FILE *File1; 2076 | gchar *link; 2077 | //char textdate[100]; 2078 | 2079 | gtk_init(&argc, &argv); 2080 | // context = g_main_context_new(); 2081 | // GOptionContext *context = g_option_context_new(NULL); 2082 | 2083 | menu =gtk_menu_new(); 2084 | menuitem1 = gtk_menu_item_new_with_label("Click to cancel"); 2085 | gtk_menu_shell_append(GTK_MENU_SHELL(menu),menuitem1); 2086 | //gtk_widget_show_all(menu); 2087 | 2088 | 2089 | setup(); 2090 | c = client_new(NULL); 2091 | 2092 | if (argc > 1){ 2093 | 2094 | for (i = 1; i < argc; i++) { 2095 | link = (gchar *) argv[i]; 2096 | loadurl(c,link); 2097 | } 2098 | } 2099 | 2100 | else 2101 | 2102 | loadurl(c,home); 2103 | 2104 | 2105 | 2106 | gtk_main(); 2107 | 2108 | return 0; 2109 | } 2110 | --------------------------------------------------------------------------------