From 0abf3511646446ee64f21d551dd0d2214fd624b7 Mon Sep 17 00:00:00 2001 From: Matt Singleton Date: Wed, 19 Jan 2022 18:58:02 -0600 Subject: organizing the repo a bit --- browser/browser.py | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100755 browser/browser.py (limited to 'browser/browser.py') diff --git a/browser/browser.py b/browser/browser.py new file mode 100755 index 0000000..f5475ab --- /dev/null +++ b/browser/browser.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python + +import sys + +from PySide6 import QtCore, QtWidgets, QtGui, QtWebEngineWidgets, QtWebEngineCore + +import gemini + + +class GeminiPage(QtWebEngineCore.QWebEnginePage): + def acceptNavigationRequest(self, url, navtype, mainframe): + """ + Block non-gemini page navigation and + send the url to the os instead + """ + if url.scheme() == 'gemini': + return True + else: + QtGui.QDesktopServices().openUrl(url) + return False + + +class GeminiSchemeHandler(QtWebEngineCore.QWebEngineUrlSchemeHandler): + def requestStarted(self, request): + request_url = gemini.hack_url(request.requestUrl().toString()) + print(request_url) + gem = gemini.get(request_url) + print(gem['status'], gem['meta']) + buf = QtCore.QBuffer(parent=request) + buf.open(QtCore.QIODevice.WriteOnly) + buf.write(gemini.gem2html(gem).encode('utf8')) + buf.seek(0) + buf.close() + request.reply(b'text/html', buf) + + +class GUrlBar(QtWidgets.QLineEdit): + + def __init__(self): + QtWidgets.QLineEdit.__init__(self) + + def setUrl(self, url): + url = gemini.hack_url(url.toDisplayString()) + return self.setText(url) + + +class GBrowser(QtWidgets.QMainWindow): + + def __init__(self, initial_url=None, profile=None): + if initial_url is None: + initial_url = 'gemini://gemini.circumlunar.space/' + if profile is None: + profile = QtWebEngineCore.QWebEngineProfile.defaultProfile() + QtWidgets.QMainWindow.__init__(self) + + # Main Viewport + self._browser = QtWebEngineWidgets.QWebEngineView() + page = GeminiPage(profile, self._browser) + self._browser.setPage(page) + self.setCentralWidget(self._browser) + + # Navigation Toolbar + back = QtWidgets.QPushButton('←', self) + forward = QtWidgets.QPushButton('→', self) + self._address = GUrlBar() + toolbar = QtWidgets.QToolBar() + toolbar.setObjectName('navigationToolbar') + toolbar.addWidget(back) + toolbar.addWidget(forward) + toolbar.addWidget(self._address) + self.addToolBar(toolbar) + + # Status Bar + request_status = QtWidgets.QLabel() + self.statusBar().addWidget(request_status) + + # Connect signals + back.clicked.connect(self._browser.back) + forward.clicked.connect(self._browser.forward) + self._browser.urlChanged.connect(self._address.setUrl) + self._address.returnPressed.connect(self.loadAddress) + self._browser.page().linkHovered.connect(self.set_status_url) + + self._browser.load(QtCore.QUrl(initial_url)) + + settings = QtCore.QSettings("xcolour.net", "GeminiBrowser") + self.restoreGeometry(settings.value("geometry")) + self.restoreState(settings.value("windowState")) + self.setWindowTitle('Gemini Browser') + self.show() + + # Shortcuts + down_shortcut = QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_J), self) + down_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Down, QtCore.Qt.NoModifier) + down_shortcut.activated.connect(lambda: QtWidgets.QApplication.sendEvent(self._browser.focusProxy(), down_event)) + up_shortcut = QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_K), self) + up_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Up, QtCore.Qt.NoModifier) + up_shortcut.activated.connect(lambda: QtWidgets.QApplication.sendEvent(self._browser.focusProxy(), up_event)) + QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_H), self, self._browser.back) + QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_L), self, self._browser.forward) + QtGui.QShortcut(QtGui.QKeySequence("Shift+R"), self, self._browser.reload) + QtGui.QShortcut(QtGui.QKeySequence("Esc"), self._address, lambda: self.setFocus()) + QtGui.QShortcut(QtGui.QKeySequence("Shift+L"), self, lambda: self._address.setFocus()) + + def set_status_url(self, url): + if url: + self.statusBar().showMessage(url) + else: + self.statusBar().clearMessage() + + def closeEvent(self, event): + settings = QtCore.QSettings("xcolour.net", "GeminiBrowser") + settings.setValue("geometry", self.saveGeometry()) + settings.setValue("windowState", self.saveState()) + self._browser.page().deleteLater() + super().closeEvent(event) + + def loadAddress(self): + self._browser.load(self._address.text()) + self._browser.setFocus() + + +scheme = QtWebEngineCore.QWebEngineUrlScheme(b'gemini') +scheme.setDefaultPort(1965) +scheme.setFlags(QtWebEngineCore.QWebEngineUrlScheme.SecureScheme) +QtWebEngineCore.QWebEngineUrlScheme.registerScheme(scheme) +app = QtWidgets.QApplication(sys.argv) +gem_handler = GeminiSchemeHandler() +profile = QtWebEngineCore.QWebEngineProfile() +profile.removeAllUrlSchemeHandlers() +profile.installUrlSchemeHandler(b'gemini', gem_handler) +ex = GBrowser(sys.argv[1] if len(sys.argv) > 1 else None, profile) +sys.exit(app.exec()) -- cgit v1.2.3