2022-02-04 23:47:14 +00:00
|
|
|
|
(local lgi (require :lgi))
|
|
|
|
|
(local inspect (require :inspect))
|
|
|
|
|
|
|
|
|
|
(local Gtk lgi.Gtk)
|
2022-02-06 23:46:52 +00:00
|
|
|
|
(local Gdk lgi.Gdk)
|
2022-02-04 23:47:14 +00:00
|
|
|
|
(local WebKit2 lgi.WebKit2)
|
2022-02-06 23:46:52 +00:00
|
|
|
|
(local cairo lgi.cairo)
|
2022-02-04 23:47:14 +00:00
|
|
|
|
|
2022-02-06 15:05:00 +00:00
|
|
|
|
(local cache-dir (.. (os.getenv "HOME") "/.cache/just"))
|
2022-02-05 19:08:18 +00:00
|
|
|
|
|
|
|
|
|
(local content-filter-store
|
|
|
|
|
(WebKit2.UserContentFilterStore {:path cache-dir}))
|
|
|
|
|
|
2022-02-06 15:05:00 +00:00
|
|
|
|
(-> (WebKit2.WebContext:get_default)
|
|
|
|
|
(: :get_website_data_manager)
|
|
|
|
|
(: :get_cookie_manager)
|
|
|
|
|
(: :set_persistent_storage
|
|
|
|
|
(.. cache-dir "/cookies.db")
|
|
|
|
|
WebKit2.CookiePersistentStorage.SQLITE))
|
|
|
|
|
|
2022-02-06 14:05:05 +00:00
|
|
|
|
(fn event-bus []
|
|
|
|
|
(let [subscriptions {}
|
|
|
|
|
vivify (fn [n v]
|
2022-02-06 14:33:56 +00:00
|
|
|
|
(or (. n v) (tset n v {}))
|
|
|
|
|
(. n v))]
|
2022-02-06 14:05:05 +00:00
|
|
|
|
{
|
|
|
|
|
:subscriptions subscriptions
|
|
|
|
|
:subscribe (fn [self event-name handler]
|
|
|
|
|
(table.insert (vivify subscriptions event-name) handler))
|
|
|
|
|
:publish (fn [self event-name payload]
|
|
|
|
|
(each [_ handler (pairs (. subscriptions event-name))]
|
|
|
|
|
(handler payload)))
|
|
|
|
|
:unsubscribe (fn [self event-name handler]
|
|
|
|
|
(table.remove (. subscriptions event-name) handler))
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
|
2022-02-05 21:47:12 +00:00
|
|
|
|
(fn named-image [name size]
|
|
|
|
|
(Gtk.Image.new_from_icon_name
|
|
|
|
|
name
|
|
|
|
|
(or size Gtk.IconSize.LARGE_TOOLBAR)))
|
|
|
|
|
|
2022-02-05 19:08:18 +00:00
|
|
|
|
(fn load-easylist-json [store cb]
|
|
|
|
|
(print "loading easylist from json")
|
|
|
|
|
(with-open [f (io.open "easylist_min_content_blocker.json" "r")]
|
|
|
|
|
(let [blocks (f:read "*a")]
|
|
|
|
|
(store:save "easylist"
|
|
|
|
|
(lgi.GLib.Bytes blocks)
|
|
|
|
|
nil
|
|
|
|
|
(fn [self res]
|
|
|
|
|
(cb (store:save_finish res)))))))
|
|
|
|
|
|
|
|
|
|
(fn load-adblocks [content-manager store]
|
|
|
|
|
(store:fetch_identifiers
|
|
|
|
|
nil
|
|
|
|
|
(fn [self res]
|
|
|
|
|
(let [ids (store:fetch_identifiers_finish res)
|
|
|
|
|
found (icollect [_ id (pairs ids)] (= id "easylist"))]
|
|
|
|
|
(if (> (# found) 0)
|
|
|
|
|
(store:load "easylist" nil
|
|
|
|
|
(fn [self res]
|
|
|
|
|
(content-manager:add_filter
|
|
|
|
|
(store:load_finish res))))
|
|
|
|
|
(load-easylist-json
|
|
|
|
|
store
|
|
|
|
|
(fn [filter]
|
|
|
|
|
(content-manager:add_filter filter))))))))
|
|
|
|
|
|
2022-02-05 23:52:52 +00:00
|
|
|
|
(let [css "
|
|
|
|
|
progress, trough {
|
|
|
|
|
max-height: 6px;
|
|
|
|
|
color: #4444bb;
|
|
|
|
|
}
|
|
|
|
|
"
|
|
|
|
|
style_provider (Gtk.CssProvider)]
|
|
|
|
|
(style_provider:load_from_data css)
|
|
|
|
|
(Gtk.StyleContext.add_provider_for_screen
|
|
|
|
|
(lgi.Gdk.Screen.get_default)
|
|
|
|
|
style_provider
|
|
|
|
|
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
|
|
|
|
))
|
|
|
|
|
|
2022-02-05 19:08:18 +00:00
|
|
|
|
|
2022-02-06 14:08:42 +00:00
|
|
|
|
(fn handle-webview-properties [self pspec bus]
|
2022-02-06 14:15:59 +00:00
|
|
|
|
(match pspec.name
|
|
|
|
|
"uri"
|
|
|
|
|
(bus:publish :url-changed self.uri)
|
2022-02-06 14:08:42 +00:00
|
|
|
|
|
2022-02-06 14:15:59 +00:00
|
|
|
|
"title"
|
|
|
|
|
(if (> (self.title:len) 0)
|
|
|
|
|
(bus:publish :title-changed self.title))
|
2022-02-06 14:08:42 +00:00
|
|
|
|
|
2022-02-06 14:15:59 +00:00
|
|
|
|
"estimated-load-progress"
|
|
|
|
|
(bus:publish :loading-progress self.estimated_load_progress)
|
2022-02-06 14:08:42 +00:00
|
|
|
|
|
2022-02-06 14:15:59 +00:00
|
|
|
|
"is-loading"
|
2022-02-06 14:26:58 +00:00
|
|
|
|
(bus:publish (if self.is_loading :start-loading :stop-loading))
|
2022-02-06 14:15:59 +00:00
|
|
|
|
))
|
2022-02-06 14:08:42 +00:00
|
|
|
|
|
2022-02-06 17:47:52 +00:00
|
|
|
|
(fn new-webview [bus]
|
|
|
|
|
(let [webview (WebKit2.WebView {
|
|
|
|
|
:on_notify
|
|
|
|
|
#(handle-webview-properties $1 $2 bus)
|
2022-02-06 17:52:15 +00:00
|
|
|
|
|
2022-02-06 19:41:14 +00:00
|
|
|
|
})]
|
2022-02-06 17:47:52 +00:00
|
|
|
|
(load-adblocks webview.user_content_manager content-filter-store)
|
|
|
|
|
webview))
|
|
|
|
|
|
2022-02-06 23:46:52 +00:00
|
|
|
|
(fn scale-surface [source]
|
|
|
|
|
(let [image-width 300
|
|
|
|
|
image-height 200
|
|
|
|
|
scaled (cairo.ImageSurface.create
|
|
|
|
|
cairo.Format.ARGB32
|
|
|
|
|
image-width image-height)
|
|
|
|
|
ctx (cairo.Context.create scaled)
|
|
|
|
|
source-width (cairo.ImageSurface.get_width source)
|
|
|
|
|
source-height (cairo.ImageSurface.get_height source)
|
|
|
|
|
scale (/ image-width source-width)]
|
|
|
|
|
;; XXX do we need to destroy this context? the example
|
|
|
|
|
;; in C called cairo_destroy(cr), but I haven't found a
|
|
|
|
|
;; gi equivalent
|
|
|
|
|
(doto ctx
|
|
|
|
|
(: :scale scale scale)
|
|
|
|
|
(: :set_source_surface source 0 0)
|
|
|
|
|
(: :paint))
|
|
|
|
|
scaled))
|
|
|
|
|
|
|
|
|
|
(fn load-webview-thumbnail [button webview]
|
|
|
|
|
(webview:get_snapshot
|
|
|
|
|
WebKit2.SnapshotRegion.VISIBLE
|
|
|
|
|
WebKit2.SnapshotOptions.NONE
|
|
|
|
|
nil
|
|
|
|
|
(fn [self res]
|
|
|
|
|
(let [surface (webview:get_snapshot_finish res)
|
|
|
|
|
scaled (scale-surface surface)
|
|
|
|
|
img (doto (Gtk.Image) (: :set_from_surface scaled))]
|
|
|
|
|
(button:set_image img)))))
|
|
|
|
|
|
|
|
|
|
|
2022-02-06 22:16:03 +00:00
|
|
|
|
(fn update-tab-overview [bus tabs scrolledwindow]
|
|
|
|
|
(let [box (Gtk.Box {
|
|
|
|
|
:orientation Gtk.Orientation.VERTICAL
|
|
|
|
|
})]
|
|
|
|
|
|
|
|
|
|
(each [_ w (ipairs (scrolledwindow:get_children))]
|
|
|
|
|
(scrolledwindow:remove w))
|
|
|
|
|
|
|
|
|
|
(each [i w (pairs tabs)]
|
|
|
|
|
(when (> i 0)
|
2022-02-06 23:46:52 +00:00
|
|
|
|
(box:pack_start
|
|
|
|
|
(doto (Gtk.Button {
|
|
|
|
|
:label w.title
|
|
|
|
|
:image-position Gtk.PositionType.TOP
|
|
|
|
|
:relief Gtk.ReliefStyle.NONE
|
|
|
|
|
:on_clicked
|
|
|
|
|
#(bus:publish :switch-tab i)
|
|
|
|
|
})
|
|
|
|
|
(load-webview-thumbnail w))
|
|
|
|
|
false false 5)))
|
2022-02-06 22:16:03 +00:00
|
|
|
|
(scrolledwindow:add box)
|
|
|
|
|
(scrolledwindow:show_all)
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
|
2022-02-06 19:41:14 +00:00
|
|
|
|
(fn pane-cave [bus]
|
2022-02-06 22:16:03 +00:00
|
|
|
|
(let [tabs {}
|
|
|
|
|
widget (Gtk.Notebook {
|
|
|
|
|
:show_tabs false
|
|
|
|
|
:on_switch_page
|
|
|
|
|
(fn [self page num]
|
|
|
|
|
(when (= num 0)
|
|
|
|
|
(update-tab-overview bus tabs page)))
|
|
|
|
|
})
|
|
|
|
|
new-tab (fn [self child]
|
|
|
|
|
(let [v (or child (new-webview bus))
|
2022-02-06 19:41:14 +00:00
|
|
|
|
i (widget:append_page v)]
|
|
|
|
|
(tset tabs i v)
|
|
|
|
|
(v:show)
|
2022-02-06 22:16:03 +00:00
|
|
|
|
(set widget.page i)
|
2022-02-06 19:41:14 +00:00
|
|
|
|
v))
|
|
|
|
|
current #(. tabs widget.page)]
|
|
|
|
|
(bus:subscribe :fetch #(match (current) c (c:load_uri $1)))
|
|
|
|
|
(bus:subscribe :stop-loading
|
|
|
|
|
#(match (current) c (c:stop_loading)))
|
|
|
|
|
(bus:subscribe :reload
|
|
|
|
|
#(match (current) c (c:reload)))
|
|
|
|
|
(bus:subscribe :go-back
|
|
|
|
|
#(match (current) c (and (c:can_go_back) (c:go_back))))
|
|
|
|
|
(bus:subscribe :new-tab new-tab)
|
2022-02-06 22:16:03 +00:00
|
|
|
|
(bus:subscribe :switch-tab (fn [i] (widget:set_current_page i)))
|
|
|
|
|
|
|
|
|
|
(new-tab nil (Gtk.ScrolledWindow))
|
2022-02-06 19:41:14 +00:00
|
|
|
|
{
|
|
|
|
|
:new-tab new-tab
|
|
|
|
|
:current-tab current
|
|
|
|
|
:widget widget
|
2022-02-06 22:16:03 +00:00
|
|
|
|
:show-tab-overview #(widget:set_current_page 0)
|
2022-02-06 19:41:14 +00:00
|
|
|
|
}))
|
|
|
|
|
|
2022-02-06 15:05:00 +00:00
|
|
|
|
(let [current-url "https://terse.telent.net"
|
2022-02-06 14:05:05 +00:00
|
|
|
|
bus (event-bus)
|
2022-02-04 23:47:14 +00:00
|
|
|
|
window (Gtk.Window {
|
|
|
|
|
:title "Just browsing"
|
2022-02-06 22:16:03 +00:00
|
|
|
|
:default_width 360
|
|
|
|
|
:default_height 720
|
2022-02-04 23:47:14 +00:00
|
|
|
|
:on_destroy Gtk.main_quit
|
|
|
|
|
})
|
|
|
|
|
container (Gtk.Box {
|
|
|
|
|
:orientation Gtk.Orientation.VERTICAL
|
|
|
|
|
})
|
|
|
|
|
nav-bar (Gtk.Box {
|
|
|
|
|
:orientation Gtk.Orientation.HORIZONTAL
|
|
|
|
|
})
|
2022-02-05 23:52:52 +00:00
|
|
|
|
progress-bar (Gtk.ProgressBar {
|
|
|
|
|
:orientation Gtk.Orientation.HORIZONTAL
|
|
|
|
|
:fraction 1.0
|
|
|
|
|
:margin 0
|
|
|
|
|
})
|
2022-02-06 15:05:00 +00:00
|
|
|
|
url (Gtk.Entry {
|
|
|
|
|
:on_activate
|
|
|
|
|
(fn [self] (bus:publish :fetch self.text))
|
|
|
|
|
})
|
2022-02-06 14:26:58 +00:00
|
|
|
|
stop (doto (Gtk.Button {
|
|
|
|
|
:on_clicked #(bus:publish :stop-loading)
|
|
|
|
|
})
|
|
|
|
|
(: :set_image (named-image "process-stop")))
|
2022-02-06 19:41:14 +00:00
|
|
|
|
new-tab (Gtk.Button {
|
|
|
|
|
:on_clicked #(bus:publish :new-tab)
|
|
|
|
|
:label "➕"
|
|
|
|
|
})
|
2022-02-06 14:26:58 +00:00
|
|
|
|
refresh (doto (Gtk.Button {
|
|
|
|
|
:on_clicked #(bus:publish :reload)
|
|
|
|
|
})
|
|
|
|
|
(: :set_image (named-image "view-refresh")))
|
2022-02-06 19:41:14 +00:00
|
|
|
|
views (pane-cave bus)
|
2022-02-06 22:16:03 +00:00
|
|
|
|
show-tabs (Gtk.Button {
|
|
|
|
|
:label "><"
|
|
|
|
|
:on_clicked #(views:show-tab-overview)
|
2022-02-06 19:41:14 +00:00
|
|
|
|
})
|
|
|
|
|
|
2022-02-05 12:45:50 +00:00
|
|
|
|
back (doto
|
|
|
|
|
(Gtk.Button {
|
2022-02-06 17:52:15 +00:00
|
|
|
|
:on_clicked #(bus:publish :go-back)
|
2022-02-05 12:45:50 +00:00
|
|
|
|
})
|
2022-02-05 21:47:12 +00:00
|
|
|
|
(: :set_image (named-image "go-previous")))]
|
2022-02-06 14:05:05 +00:00
|
|
|
|
|
|
|
|
|
(bus:subscribe :url-changed #(url:set_text $1))
|
|
|
|
|
|
|
|
|
|
(bus:subscribe :title-changed #(window:set_title
|
|
|
|
|
(.. $1 " - Just browsing")))
|
|
|
|
|
|
|
|
|
|
(bus:subscribe :loading-progress #(tset progress-bar :fraction $1))
|
2022-02-06 14:26:58 +00:00
|
|
|
|
(bus:subscribe :start-loading
|
|
|
|
|
(fn [] (stop:show) (refresh:hide)))
|
|
|
|
|
(bus:subscribe :stop-loading
|
|
|
|
|
(fn [] (stop:hide) (refresh:show)))
|
2022-02-06 14:05:05 +00:00
|
|
|
|
|
2022-02-06 19:41:14 +00:00
|
|
|
|
(views:new-tab)
|
|
|
|
|
|
2022-02-05 12:45:50 +00:00
|
|
|
|
(nav-bar:pack_start back false false 2)
|
2022-02-06 17:04:48 +00:00
|
|
|
|
(nav-bar:pack_start refresh false false 2)
|
|
|
|
|
(nav-bar:pack_start stop false false 2)
|
2022-02-05 12:45:50 +00:00
|
|
|
|
(nav-bar:pack_start url true true 2)
|
2022-02-06 22:16:03 +00:00
|
|
|
|
(nav-bar:pack_end show-tabs false false 2)
|
2022-02-06 19:41:14 +00:00
|
|
|
|
(nav-bar:pack_end new-tab false false 2)
|
2022-02-04 23:47:14 +00:00
|
|
|
|
|
|
|
|
|
(container:pack_start nav-bar false false 5)
|
2022-02-05 23:52:52 +00:00
|
|
|
|
(container:pack_start progress-bar false false 0)
|
2022-02-06 19:41:14 +00:00
|
|
|
|
(container:pack_start views.widget true true 5)
|
2022-02-04 23:47:14 +00:00
|
|
|
|
|
|
|
|
|
(window:add container)
|
|
|
|
|
|
2022-02-06 19:41:14 +00:00
|
|
|
|
(window:show_all)
|
|
|
|
|
(bus:publish :fetch current-url))
|
2022-02-06 15:05:00 +00:00
|
|
|
|
|
|
|
|
|
|
2022-02-04 23:47:14 +00:00
|
|
|
|
(Gtk.main)
|