def _download_requested(self, download_item) -> None: """ * If a download is requested call a save file dialog * :param download_item: file to be downloaded """ if bindings() == "PyQt5": from PyQt5.QtWidgets import QFileDialog else: from PySide2.QtWidgets import QFileDialog dialog = QFileDialog(self) path = dialog.getSaveFileName(dialog, "Save File", download_item.path()) if path[0]: download_item.setPath(path[0]) print(f"downloading file to:( {download_item.path()} )") download_item.accept() self.download_item = download_item download_item.finished.connect(self._download_finished) else: print("Download canceled")
#### Jade Application Kit # * https://codesardine.github.io/Jade-Application-Kit # * Vitor Lopes Copyright (c) 2016 - 2020 # * https://vitorlopes.me import sys import os from JAK.Utils import Instance, bindings, getScreenGeometry from JAK.KeyBindings import KeyPress if bindings() == "PyQt5": from PyQt5.QtCore import Qt, QSize, QUrl from PyQt5.QtGui import QIcon, QPixmap, QImage from PyQt5.QtWidgets import QMainWindow, QWidget, QMessageBox, QDesktopWidget, QSystemTrayIcon,\ QAction, QToolBar, QMenu, QMenuBar, QFileDialog, QLabel else: from PySide2.QtCore import Qt, QSize, QUrl from PySide2.QtGui import QIcon, QPixmap, QImage from PySide2.QtWidgets import QMainWindow, QWidget, QMessageBox, QDesktopWidget, QSystemTrayIcon,\ QAction, QToolBar, QMenu, QMenuBar, QFileDialog, QLabel class SystemTrayIcon(QSystemTrayIcon): def __init__(self, icon, app, config): self.config = config self.icon = icon super(SystemTrayIcon, self).__init__(icon, parent=app) self.setContextMenu(self.tray_menu()) self.show() def tray_menu(self): """
def __init__(self, config): self.config = config super(JWebView, self).__init__() self.setAttribute(Qt.WA_DeleteOnClose, True) self.profile = QWebEngineProfile.defaultProfile() self.webpage = JWebPage(self.profile, self, config) self.setPage(self.webpage) if config["inject_JavaScript"]["JavaScript"]: from JAK.Utils import JavaScript JavaScript.inject(self.page(), config["inject_JavaScript"]) self.interceptor = Interceptor(config) if config["user_agent"]: # Set user agent self.profile.setHttpUserAgent(config["user_agent"]) if config["debug"]: self.settings().setAttribute(QWebEngineSettings.XSSAuditingEnabled, True) else: self.setContextMenuPolicy(Qt.PreventContextMenu) if config["transparent"]: # Activates background transparency self.setAttribute(Qt.WA_TranslucentBackground) self.page().setBackgroundColor(Qt.transparent) self.setStyleSheet("background:transparent;") print( "Transparency detected, make sure you set [ body {background:transparent;} ]" ) # * Set Engine options if self.config["JavascriptCanPaste"]: self.settings().setAttribute(QWebEngineSettings.JavascriptCanPaste, True) else: self.settings().setAttribute(QWebEngineSettings.JavascriptCanPaste, False) if self.config["PlaybackRequiresUserGesture"]: self.settings().setAttribute( QWebEngineSettings.PlaybackRequiresUserGesture, True) else: self.settings().setAttribute( QWebEngineSettings.PlaybackRequiresUserGesture, False) if self.config["FullScreenSupportEnabled"]: self.settings().setAttribute( QWebEngineSettings.FullScreenSupportEnabled, True) else: self.settings().setAttribute( QWebEngineSettings.FullScreenSupportEnabled, False) if self.config["AllowWindowActivationFromJavaScript"]: self.settings().setAttribute( QWebEngineSettings.AllowWindowActivationFromJavaScript, True) else: self.settings().setAttribute( QWebEngineSettings.AllowWindowActivationFromJavaScript, False) if self.config["LocalContentCanAccessRemoteUrls"]: self.settings().setAttribute( QWebEngineSettings.LocalContentCanAccessRemoteUrls, True) else: self.settings().setAttribute( QWebEngineSettings.LocalContentCanAccessRemoteUrls, False) if self.config["JavascriptCanAccessClipboard"]: self.settings().setAttribute( QWebEngineSettings.JavascriptCanAccessClipboard, True) else: self.settings().setAttribute( QWebEngineSettings.JavascriptCanAccessClipboard, False) if self.config["SpatialNavigationEnabled"]: self.settings().setAttribute( QWebEngineSettings.SpatialNavigationEnabled, True) else: self.settings().setAttribute( QWebEngineSettings.SpatialNavigationEnabled, False) if self.config["TouchIconsEnabled"]: self.settings().setAttribute(QWebEngineSettings.TouchIconsEnabled, True) else: self.settings().setAttribute(QWebEngineSettings.TouchIconsEnabled, False) if self.config["FocusOnNavigationEnabled"]: self.settings().setAttribute( QWebEngineSettings.FocusOnNavigationEnabled, True) else: self.settings().setAttribute( QWebEngineSettings.FocusOnNavigationEnabled, False) if config["online"]: self.settings().setAttribute(QWebEngineSettings.DnsPrefetchEnabled, True) print("Engine online (IPC) Disabled") self.page().profile().downloadRequested.connect( self._download_requested) # Set persistent cookies self.profile.setPersistentCookiesPolicy( QWebEngineProfile.ForcePersistentCookies) # set cookies on user folder if config["cookies_path"]: # allow specific path per application. _cookies_path = f"{os.getenv('HOME')}/.jak/{config['cookies_path']}" else: # use separate cookies database per application title = config["title"].lower().replace(" ", "-") _cookies_path = f"{os.getenv('HOME')}/.jak/{title}" self.profile.setPersistentStoragePath(_cookies_path) print(f"Cookies PATH:{_cookies_path}") else: self.settings().setAttribute(QWebEngineSettings.ShowScrollBars, False) print("Engine interprocess communication (IPC) up and running:") self._ipc_scheme_handler = IpcSchemeHandler() self.profile.installUrlSchemeHandler('ipc'.encode(), self._ipc_scheme_handler) if config["webChannel"]["active"]: from JAK.Utils import JavaScript if bindings() == "PyQt5": from PyQt5.QtCore import QFile, QIODevice from PyQt5.QtWebChannel import QWebChannel webchannel_js = QFile(':/qtwebchannel/qwebchannel.js') webchannel_js.open(QIODevice.ReadOnly) webchannel_js = bytes(webchannel_js.readAll()).decode('utf-8') webchannel_js += """ var JAK; new QWebChannel(qt.webChannelTransport, function (channel) { JAK = channel.objects.Bridge; });""" JavaScript.inject(self.page(), { "JavaScript": webchannel_js, "name": "QWebChannel API" }) self.channel = QWebChannel(self.page()) if config["webChannel"]["shared_obj"]: self.bridge_obj = config["webChannel"]["shared_obj"] else: raise NotImplementedError("QWebChannel shared QObject") self.channel.registerObject("Bridge", self.bridge_obj) self.page().setWebChannel(self.channel) print("QWebChannel bridge active") self.profile.setRequestInterceptor(self.interceptor) print(self.profile.httpUserAgent()) validate_url(self, config["web_contents"])
def __init__(self, config): self.config = config super(JWebView, self).__init__() self.setAttribute(Qt.WA_DeleteOnClose, True) self.profile = QWebEngineProfile.defaultProfile() self.webpage = JWebPage(self.profile, self, config) self.setPage(self.webpage) if config['webview']["injectJavaScript"]["JavaScript"]: self._inject_script(config['webview']["injectJavaScript"]) self.interceptor = Interceptor(config) if config['webview']["userAgent"]: # Set user agent self.profile.setHttpUserAgent(config['webview']["userAgent"]) if config["debug"]: self.settings().setAttribute(QWebEngineSettings.XSSAuditingEnabled, True) else: self.setContextMenuPolicy(Qt.PreventContextMenu) if config['window']["transparent"]: # Activates background transparency self.setAttribute(Qt.WA_TranslucentBackground) self.page().setBackgroundColor(Qt.transparent) print("Transparency detected") # * Set Engine options self.settings().setAttribute( self.config['webview']['disabledSettings'], False) for setting in self.config['webview']['enabledSettings']: self.settings().setAttribute(setting, True) if config['webview']["online"]: self.settings().setAttribute(QWebEngineSettings.DnsPrefetchEnabled, True) print("Engine online IPC and Bridge Disabled") self.page().profile().downloadRequested.connect( self._download_requested) # Set persistent cookies self.profile.setPersistentCookiesPolicy( QWebEngineProfile.ForcePersistentCookies) # set cookies on user folder if config['webview']["cookiesPath"]: # allow specific path per application. _cookies_path = f"{os.getenv('HOME')}/.jak/{config['webview']['cookiesPath']}" else: # use separate cookies database per application title = config['window']["title"].lower().replace(" ", "-") _cookies_path = f"{os.getenv('HOME')}/.jak/{title}" self.profile.setPersistentStoragePath(_cookies_path) print(f"Cookies PATH:{_cookies_path}") else: self.settings().setAttribute(QWebEngineSettings.ShowScrollBars, False) application_script = "const JAK = {};" if config['webview']["IPC"]: print("IPC Active:") self._ipc_scheme_handler = IpcSchemeHandler() self.profile.installUrlSchemeHandler('ipc'.encode(), self._ipc_scheme_handler) application_script += """JAK.IPC = function(backendFunction) { window.location.href = "ipc:" + backendFunction; };""" if config['webview']["webChannel"]["active"]: if bindings() == "PyQt5": from PyQt5.QtCore import QFile, QIODevice from PyQt5.QtWebChannel import QWebChannel webchannel_js = QFile(':/qtwebchannel/qwebchannel.js') webchannel_js.open(QIODevice.ReadOnly) webchannel_js = bytes(webchannel_js.readAll()).decode('utf-8') webchannel_js += """new QWebChannel(qt.webChannelTransport, function (channel) { JAK.Bridge = channel.objects.Bridge; });""" application_script += webchannel_js self._inject_script({ "JavaScript": application_script, "name": "JAK" }) channel = QWebChannel(self.page()) if config['webview']["webChannel"]["sharedOBJ"]: bridge_obj = config['webview']["webChannel"]["sharedOBJ"] else: raise NotImplementedError("QWebChannel shared QObject") channel.registerObject("Bridge", bridge_obj) self.page().setWebChannel(channel) print("WebChannel Active:") else: self._inject_script({ "JavaScript": application_script, "name": "JAK" }) self.profile.setRequestInterceptor(self.interceptor) print(self.profile.httpUserAgent()) validate_url(self, config['webview']["webContents"])
def __init__(self, config=Settings.config(), **app_config): super(JWebApp, self).__init__(sys.argv) self.config = config self.setAAttribute(Qt.AA_UseHighDpiPixmaps) self.setAAttribute(Qt.AA_EnableHighDpiScaling) self.applicationStateChanged.connect(self._applicationStateChanged_cb) for key, value in app_config.items(): if isinstance(value, dict): for subkey, subvalue in app_config[key].items(): config[key][subkey] = subvalue else: config[key] = value for attr in config["setAAttribute"]: self.setAAttribute(attr) if config["remote-debug"] or "--remote-debug" in sys.argv: sys.argv.append("--remote-debugging-port=9000") if config["debug"] or "--dev" in sys.argv: print("Debugging On") if not config["debug"]: config["debug"] = True else: print("Production Mode On, use (--dev) for debugging") # Enable/Disable GPU acceleration if not config["disableGPU"]: # Virtual machine detection using SystemD detect_virtual_machine = subprocess.Popen(["systemd-detect-virt"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # FIXME find a more reliable way of detecting NVIDIA cards detect_nvidia_pci = subprocess.Popen( "lspci | grep -i --color 'vga\|3d\|2d'", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) virtual = detect_virtual_machine.communicate() nvidia_pci = detect_nvidia_pci.communicate() nvidia_pci = nvidia_pci[0].decode("utf-8").lower() if config["disableGPU"]: self.disable_opengl() print("Disabling GPU, Software Rendering explicitly activated") else: if virtual[-1]: # Detect virtual machine print(f"Virtual machine detected:{virtual}") self.disable_opengl() elif nvidia_pci: # Detect NVIDIA cards if "nvidia" in nvidia_pci: print( "NVIDIA detected:Known bug - kernel rejected pushbuf") print("Falling back to Software Rendering") self.disable_opengl() else: print(f"Virtual Machine:{virtual[-1]}") # Desktop file must match application name in lowercase with dashes instead of white space. self.setDesktopFileName( f"{self.config['window']['title'].lower().replace(' ', '-')}.desktop" ) self.setOrganizationDomain(self.config['webview']['webContents']) self.setApplicationVersion(__version__) if not self.config['webview']['online'] and self.config['webview'][ 'IPC']: if bindings() == "PyQt5": from PyQt5.QtWebEngineCore import QWebEngineUrlScheme else: from PySide2.QtWebEngineCore import QWebEngineUrlScheme QWebEngineUrlScheme.registerScheme( QWebEngineUrlScheme("ipc".encode()))
def __init__(self, config=config(), **app_config): self.config = config for key, value in app_config.items(): config[key] = value QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True) QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True) if config["debug"] or "--dev" in sys.argv: # Adding some command line arguments for testing purposes, # this MUST BE done before initializing QApplication sys.argv.append(f"--remote-debugging-port={config['debug_port']}") print("Debugging Mode On") if not config["debug"]: config["debug"] = True else: print("Production Mode On, use (--dev) for debugging") # Enable/Disable GPU acceleration if not config["disable_gpu"]: # Virtual machine detection using SystemD detect_virtual_machine = subprocess.Popen(["systemd-detect-virt"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # FIXME find a more reliable way of detecting NVIDIA cards detect_nvidia_pci = subprocess.Popen( "lspci | grep -i --color 'vga\|3d\|2d'", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) virtual = detect_virtual_machine.communicate() nvidia_pci = detect_nvidia_pci.communicate() nvidia_pci = nvidia_pci[0].decode("utf-8").lower() def disable_opengl(): # Disable GPU acceleration # https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/206307 QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL, True) if config["disable_gpu"]: disable_opengl() print("Disabling GPU, Software Rendering explicitly activated") else: if virtual[-1]: # Detect virtual machine print(f"Virtual machine detected:{virtual}") disable_opengl() elif nvidia_pci: # Detect NVIDIA cards if "nvidia" in nvidia_pci: print( "NVIDIA detected:Known bug - kernel rejected pushbuf") print("Falling back to Software Rendering") disable_opengl() else: print(f"Virtual Machine:{virtual[-1]}") super(JWebApp, self).__init__(sys.argv) # Desktop file must match application name in lowercase with dashes instead of white space. self.setDesktopFileName( f"{config['title'].lower().replace(' ', '-')}.desktop") self.setOrganizationDomain(config['web_contents']) self.setApplicationVersion(__version__) if not config['online']: if bindings() == "PyQt5": from PyQt5.QtWebEngineCore import QWebEngineUrlScheme else: from PySide2.QtWebEngineCore import QWebEngineUrlScheme QWebEngineUrlScheme.registerScheme( QWebEngineUrlScheme("ipc".encode()))