176 lines
6.1 KiB
Python
176 lines
6.1 KiB
Python
|
#!/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
|
||
|
|
||
|
Below "# Script start" you can find a setting for software mode, which you should use if you're experiencing trouble with the viewport not showing up or freezing.
|
||
|
"""
|
||
|
|
||
|
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
|
||
|
|
||
|
# Uncomment the following line for software-mode
|
||
|
os.environ["LIBGL_ALWAYS_SOFTWARE"] = "1"
|
||
|
|
||
|
#os.environ["WEBKIT_USE_SINGLE_WEB_PROCESS"] = "1" # Deprecated, not required with this code
|
||
|
import gi
|
||
|
gi.require_version("Gtk","3.0")
|
||
|
gi.require_version("WebKit2","4.0")
|
||
|
from gi.repository import Gtk, WebKit2
|
||
|
|
||
|
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_process_model(WebKit2.ProcessModel.SHARED_SECONDARY_PROCESS) # Deprecated, not required with this code
|
||
|
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)
|
||
|
birdyWebSettings.set_hardware_acceleration_policy(WebkKit2.HardwareAccelerationPolicy.ALWAYS) # WebKit's software acceleration is broken, use LIBGL_ALWAYS_SOFTWARE=1 instead.
|
||
|
#birdyWebSettings.set_enable_plugins(False) # Probably best to not uncomment this, I think it causes a memory leak
|
||
|
defaultUserAgent = birdyWebSettings.get_user_agent()
|
||
|
|
||
|
def birdyWebViewConstructor(webView):
|
||
|
if webView:
|
||
|
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.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)
|
||
|
|
||
|
homepage = "about:blank"
|
||
|
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)
|
||
|
self.cWebView = birdyWebViewConstructor(webView)
|
||
|
self.cWebView.connect("load-changed",self.cWebViewLoadChanged)
|
||
|
self.cMainBox.add(self.cWebView)
|
||
|
self.cWebView.load_uri(homepage)
|
||
|
self.cResizeElements()
|
||
|
self.set_focus(self.cUrlEntry)
|
||
|
self.cUrlEntry.select_region(0,2)
|
||
|
self.show_all()
|
||
|
|
||
|
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 cWebViewLoadChanged(self,widget,event):
|
||
|
url = widget.get_uri()
|
||
|
if self.cUrlEntry.get_text() != url: self.cUrlEntry.set_text(url)
|
||
|
|
||
|
#if event == WebKit2.LoadEvent.FINISHED:
|
||
|
# birdyWebContext.clear_cache() # This might cause a memory leak?
|
||
|
|
||
|
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)
|
||
|
self.cWebView.load_uri(url)
|
||
|
|
||
|
browserWindows.append(birdyBrowserWindow(False))
|
||
|
Gtk.main()
|