webkit-disappointment/webkit-inabox-gtk.py

217 lines
7.1 KiB
Python
Raw Permalink Normal View History

2021-12-19 03:59:42 +00:00
#!/usr/bin/env python3
"""
This uses the currently supported WebKit GTK, which is more up to date but also fatter.
WebKit is a huge mess and leaks all over the place. I'm not even sure about anything that's going on. Resources are taken up but only loosely released. You can start with as low as a 50MB memory load, but you will never go back to that. There's no apparent way to run JavaScript garbage collection, and I doubt it would help. -- Par of the course for JavaScript supporting browsers.
Good: This is a little less fat than Chrome, probably.. maybe.. at least at first
Bad: It still sucks
Prerequisites (Debian and cousins):
sudo apt install python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-webkit2-4.0
2021-12-20 05:41:56 +00:00
Below "# Script start" you can find a setting for software mode, which you should comment out if you use a modern PC. I don't use the software rendering that comes included with WebKit, as it's unstable in my experience.
2021-12-19 03:59:42 +00:00
"""
import sys
oldexcepthook = sys.excepthook
def newexcepthook(type,value,traceback):
oldexcepthook(type,value,traceback)
#input("Press ENTER to quit.")
sys.excepthook = newexcepthook
import os
p = os.path.join
pUp = os.path.dirname
s = False
if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
s = os.path.realpath(sys.executable)
else:
s = os.path.realpath(__file__)
sp = pUp(s)
# Script start
os.environ["LIBGL_ALWAYS_SOFTWARE"] = "1"
2021-12-19 03:59:42 +00:00
import gi
gi.require_version("Gtk","3.0")
gi.require_version("WebKit2","4.0")
from gi.repository import Gtk, WebKit2
import time
2021-12-19 03:59:42 +00:00
defaultProtocol = "https"
browserWindows = []
class emptyClass(): pass;
measure = emptyClass()
measure.toolbar = 22
def parseUrl(url):
if url.startswith("data:"): return "data",[],"",""
if url.startswith("blob:"): return "blob",[],"",""
urlSplit = url.split(":",1)
protocol = urlSplit[0]
urlSplit = urlSplit[1].lstrip("/").split("/",1)
if len(urlSplit) < 2: urlSplit.append("")
domain = urlSplit[0].split(".")
urlSplit = urlSplit[1].split("?",1)
if len(urlSplit) < 2: urlSplit.append("")
path = urlSplit[0]
arguments = urlSplit[1]
return protocol,domain,path,arguments
birdyWebContext = WebKit2.WebContext()
birdyWebContext.set_cache_model(WebKit2.CacheModel.DOCUMENT_VIEWER) # Does this even do anything at all?
birdyWebContext.set_spell_checking_enabled(False)
birdyWebContext.set_use_system_appearance_for_scrollbars(True)
birdyWebSettings = WebKit2.Settings.new()
#birdyWebSettings.set_auto_load_images(False)
birdyWebSettings.set_enable_developer_extras(False)
birdyWebSettings.set_enable_page_cache(False)
2022-06-08 19:12:02 +00:00
birdyWebSettings.set_hardware_acceleration_policy(WebKit2.HardwareAccelerationPolicy.NEVER)
2021-12-19 03:59:42 +00:00
defaultUserAgent = birdyWebSettings.get_user_agent()
2022-06-08 19:14:37 +00:00
singleProcessMode = False
remakeViewOnNavigation = False # Always entirely remake view on navigation, could break some websites - use for super low memory situations
2021-12-19 03:59:42 +00:00
def birdyWebViewConstructor(webView):
2022-06-08 19:14:37 +00:00
if webView and singleProcessMode:
2021-12-19 03:59:42 +00:00
return WebKit2.WebView.new_with_related_view(webView)
self = WebKit2.WebView.new_with_context(birdyWebContext)
self.set_settings(birdyWebSettings)
return self
class birdyBrowserWindow(Gtk.Window):
def __init__(self,webView,*args,**kwargs):
super().__init__(*args,**kwargs)
self.cTitle = "webkit-inabox-gtk"
self.set_title(self.cTitle)
2021-12-19 03:59:42 +00:00
self.cWidth = 640
self.cHeight = 480
self.resize(self.cWidth,self.cHeight)
self.connect("destroy",self.cCloseEvent)
self.connect("configure-event",self.cConfigureEvent)
self.cCreateElements(webView)
def cCreateElements(self,webView):
self.cMainBoxWrapper = Gtk.ScrolledWindow()
self.add(self.cMainBoxWrapper)
self.cMainBox = Gtk.Fixed()
self.cMainBoxWrapper.add(self.cMainBox)
self.cMenuBar = Gtk.MenuBar()
self.cMainBox.add(self.cMenuBar)
# Menu - File
self.cFileMenuButton = Gtk.MenuItem.new_with_label("File")
self.cFileMenu = Gtk.Menu()
self.cFileMenuNewWindow = Gtk.MenuItem.new_with_label("New window")
self.cFileMenuNewWindow.connect("activate",self.cOpenWindow)
self.cFileMenu.add(self.cFileMenuNewWindow)
self.cFileMenuButton.set_submenu(self.cFileMenu)
self.cMenuBar.add(self.cFileMenuButton)
# Menu - Loading indication
self.cMenuLoadingIndication = Gtk.MenuItem.new_with_label("Loading...")
self.cMenuBar.add(self.cMenuLoadingIndication)
2021-12-19 03:59:42 +00:00
homepage = "about:blank"
2022-06-08 19:14:37 +00:00
self.cLastUrl = "about:blank"
2021-12-19 03:59:42 +00:00
self.cUrlEntry = Gtk.Entry()
self.cUrlEntry.set_text(homepage)
#self.cUrlEntry.props.enable_emoji_completion = True # lol
self.cUrlEntry.connect("activate",self.cUrlEntryNavigate)
self.cMainBox.add(self.cUrlEntry)
2022-06-08 19:14:37 +00:00
self.cCreateWebView(webView)
2021-12-19 03:59:42 +00:00
self.cWebView.load_uri(homepage)
self.cResizeElements()
self.set_focus(self.cUrlEntry)
self.cUrlEntry.select_region(0,2)
self.show_all()
self.cMenuLoadingIndication.hide()
2021-12-19 03:59:42 +00:00
2022-06-08 19:14:37 +00:00
def cCreateWebView(self,webView):
self.cWebView = birdyWebViewConstructor(webView)
self.cWebView.connect("load-changed",self.cWebViewLoadChanged)
self.cWebView.connect("notify::uri",self.cUrlChanged)
self.cWebView.connect("notify::title",self.cTitleChanged)
self.cMainBox.add(self.cWebView)
2021-12-19 03:59:42 +00:00
def cResizeElements(self):
# cMenuBar
self.cMainBox.move(self.cMenuBar,0,0)
self.cMenuBar.set_size_request(self.cWidth,measure.toolbar)
# cUrlEntry
self.cMainBox.move(self.cUrlEntry,0,measure.toolbar)
self.cUrlEntry.set_size_request(self.cWidth,measure.toolbar)
# cWebView
self.cMainBox.move(self.cWebView,0,measure.toolbar * 2)
self.cWebView.set_size_request(self.cWidth,self.cHeight - (measure.toolbar * 2))
def cConfigureEvent(self,widget,event):
if event.width == self.cWidth and event.height == self.cHeight: return
self.cWidth = event.width
self.cHeight = event.height
self.cResizeElements()
def cCloseEvent(self,*args,**kwargs):
browserWindows.remove(self)
self.cWebView.destroy()
self.destroy()
if len(browserWindows) > 0: return
Gtk.main_quit()
def cUrlChanged(self,widget,prop):
2021-12-19 03:59:42 +00:00
url = widget.get_uri()
2022-06-08 19:14:37 +00:00
if url != "" and url != self.cLastUrl and remakeViewOnNavigation and not singleProcessMode:
time.sleep(1)
self.cLastUrl = url
2022-06-08 19:14:37 +00:00
self.cWebView.destroy()
self.cCreateWebView(False)
self.cResizeElements()
self.show_all()
self.cWebView.load_uri(url)
self.cLastUrl = url
if url == "about:blank": return
2022-06-09 14:30:37 +00:00
if url == "": return
2021-12-19 03:59:42 +00:00
if self.cUrlEntry.get_text() != url: self.cUrlEntry.set_text(url)
def cTitleChanged(self,widget,prop):
2022-06-09 14:30:37 +00:00
title = widget.get_title()
if title == "":
title = self.cWebView.get_uri()
if title == "": title = self.cLastUrl
self.set_title(title + " - " +self.cTitle)
def cWebViewLoadChanged(self,widget,event):
if event == WebKit2.LoadEvent.STARTED:
self.cMenuLoadingIndication.show()
2021-12-19 03:59:42 +00:00
if event == WebKit2.LoadEvent.FINISHED:
self.cMenuLoadingIndication.hide()
2021-12-19 03:59:42 +00:00
def cOpenWindow(self,*args,**kwargs):
browserWindows.append(birdyBrowserWindow(self.cWebView))
def cUrlEntryNavigate(self,*args,**kwargs):
url = self.cUrlEntry.get_text()
if len(url.split(":",1)) < 2:
url = defaultProtocol + "://" + url
self.set_focus(self.cWebView)
2022-06-08 19:14:37 +00:00
if not singleProcessMode:
self.cWebView.destroy()
self.cCreateWebView(False)
self.cResizeElements()
self.show_all()
2021-12-19 03:59:42 +00:00
self.cWebView.load_uri(url)
browserWindows.append(birdyBrowserWindow(False))
Gtk.main()