def __init__(self, *args, **kwargs): super(Window, self).__init__(*args, **kwargs) self.resize(800, 600) # 首先获取默认的url协议 h1 = QWebEngineUrlScheme.schemeByName(b'http') h2 = QWebEngineUrlScheme.schemeByName(b'https') # 这里需要修改增加本地文件和跨域支持 CorsEnabled = 0x80 # 5.14才增加 h1.setFlags(h1.flags() | QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed | CorsEnabled) h2.setFlags(h2.flags() | QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed | CorsEnabled) # 安装url拦截器和自定义url协议处理 de = QWebEngineProfile.defaultProfile() # @UndefinedVariable de.setRequestInterceptor(RequestInterceptor(self)) de.installUrlSchemeHandler(b'myurl', UrlSchemeHandler(self))
def __init__(self, *args, **kwargs): super(Window, self).__init__(*args, **kwargs) self.resize(800, 600) profile = QWebEngineProfile.defaultProfile() # 首先获取默认的url协议 o_http = QWebEngineUrlScheme.schemeByName(QByteArray(b'http')) o_https = QWebEngineUrlScheme.schemeByName(QByteArray(b'https')) print('scheme:', o_http, o_https) # 这里需要修改增加本地文件和跨域支持 CorsEnabled = 0x80 # 5.14才增加 o_http.setFlags(o_http.flags() | QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed | CorsEnabled) o_https.setFlags(o_https.flags() | QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed | CorsEnabled) # 安装url拦截器和自定义url协议处理 de = QWebEngineProfile.defaultProfile() # @UndefinedVariable de.setRequestInterceptor(RequestInterceptor(self)) self.urlSchemeHandler = UrlSchemeHandler(self) de.installUrlSchemeHandler(QByteArray(b'myurl'), self.urlSchemeHandler) # for http de.installUrlSchemeHandler(QByteArray(b'myurls'), self.urlSchemeHandler) # for https
def init(self): """Initialize browser""" logger.debug("Initializing Browser Window") if web_greeter_config["config"]["greeter"]["debug_mode"]: os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = '12345' url_scheme = "web-greeter" self.url_scheme = QWebEngineUrlScheme(url_scheme.encode()) self.url_scheme.setDefaultPort(QWebEngineUrlScheme.PortUnspecified) self.url_scheme.setFlags(QWebEngineUrlScheme.SecureScheme or QWebEngineUrlScheme.LocalScheme or QWebEngineUrlScheme.LocalAccessAllowed) QWebEngineUrlScheme.registerScheme(self.url_scheme) self.profile = QWebEngineProfile.defaultProfile() self.interceptor = QtUrlRequestInterceptor(url_scheme) self.url_scheme_handler = QtUrlSchemeHandler() self.view = QWebEngineView(parent=self.window) self.page = WebPage() self.view.setPage(self.page) self.page.setObjectName("WebG Page") self.view.setObjectName("WebG View") self.channel = QWebChannel(self.page) self.bridge_initialized = False self.profile.installUrlSchemeHandler(url_scheme.encode(), self.url_scheme_handler) self._initialize_page() if web_greeter_config["config"]["greeter"]["debug_mode"]: self._initialize_devtools() else: self.view.setContextMenuPolicy(Qt.PreventContextMenu) self._init_actions() if web_greeter_config["app"]["frame"]: self._init_menu_bar() else: self.window.setWindowFlags(self.window.windowFlags() | Qt.FramelessWindowHint) if web_greeter_config["config"]["greeter"]["secure_mode"]: if hasattr(QWebEngineProfile, "setUrlRequestInterceptor"): self.profile.setUrlRequestInterceptor(self.interceptor) else: # Older Qt5 versions self.profile.setRequestInterceptor(self.interceptor) self.page.setBackgroundColor(QColor(0, 0, 0)) self.window.setStyleSheet("""QMainWindow, QWebEngineView { background: #000000; }""") self.window.setCentralWidget(self.view) logger.debug("Browser Window created")
def init(): """Register the qute:// scheme. Note this needs to be called early, before constructing any QtWebEngine classes. """ if QWebEngineUrlScheme is not None: scheme = QWebEngineUrlScheme(b'qute') scheme.setFlags(QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed) QWebEngineUrlScheme.registerScheme(scheme)
def declareUrlScheme(name, flags=defaultSchemeFlags, syntax=QWebEngineUrlScheme.Syntax.Host, defaultPort=QWebEngineUrlScheme.PortUnspecified, schemeSection='core'): global urlSchemes scheme = QWebEngineUrlScheme(name.encode()) scheme.setFlags(flags) scheme.setSyntax(syntax) scheme.setDefaultPort(defaultPort) QWebEngineUrlScheme.registerScheme(scheme) urlSchemes.setdefault(schemeSection, {}) urlSchemes[schemeSection][name] = scheme return scheme
def initializeSchemes(): name = QWebEngineUrlScheme.schemeByName(SCHEME_DWEB.encode()).name() if name: log.debug('initializeSchemes() already called') return declareUrlScheme( SCHEME_DWEB, syntax=QWebEngineUrlScheme.Syntax.Path, ) declareUrlScheme( SCHEME_DWEBGW, syntax=QWebEngineUrlScheme.Syntax.Path, ) declareUrlScheme( SCHEME_FS, syntax=QWebEngineUrlScheme.Syntax.Path, ) declareUrlScheme(SCHEME_IPFS, syntax=QWebEngineUrlScheme.Syntax.Host) declareUrlScheme(SCHEME_IPNS, syntax=QWebEngineUrlScheme.Syntax.Host) declareUrlScheme(SCHEME_ENS, syntax=QWebEngineUrlScheme.Syntax.Host) declareUrlScheme(SCHEME_ENSR, syntax=QWebEngineUrlScheme.Syntax.Host) dappsRegisterSchemes() registerMiscSchemes()
def __init__(self, argv, name=None): if name is None: name = "luminos" super().__init__(argv, name) if QWebEngineUrlScheme is not None: if not QWebEngineUrlScheme.schemeByName(b"luminos").name(): scheme = QWebEngineUrlScheme(b"luminos") scheme.setFlags( QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed | QWebEngineUrlScheme.ContentSecurityPolicyIgnored | QWebEngineUrlScheme.SecureScheme ) QWebEngineUrlScheme.registerScheme(scheme) self._initProfile() # self.interceptor = UrlRequestInterceptor() # self.profile.setRequestInterceptor(self.interceptor) log.init.debug("Initializing web setings...") config.instance.changed.connect(self._updateSettings) self.settings = WebEngineSettings(_SettingsWrapper(self.profile)) self.settings.initSettings() self._setupSchemeHandler() self.pluginManager = PluginManager() self.controller = Controller(self) self.controller.mainWindowChanged.connect(self._mainWindowChanged)
def main(args=sys.argv): # Ensure viewer can continue to function if GUI is closed os.environ.pop('CALIBRE_WORKER_TEMP_DIR', None) reset_base_dir() scheme = QWebEngineUrlScheme(FAKE_PROTOCOL.encode('ascii')) scheme.setSyntax(QWebEngineUrlScheme.Syntax.Host) scheme.setFlags(QWebEngineUrlScheme.Flag.SecureScheme) QWebEngineUrlScheme.registerScheme(scheme) override = 'calibre-ebook-viewer' if islinux else None processed_args = [] internal_book_data = internal_book_data_path = None for arg in args: if arg.startswith('--internal-book-data='): internal_book_data_path = arg.split('=', 1)[1] continue processed_args.append(arg) if internal_book_data_path: try: with lopen(internal_book_data_path, 'rb') as f: internal_book_data = json.load(f) finally: try: os.remove(internal_book_data_path) except EnvironmentError: pass args = processed_args app = Application(args, override_program_name=override, windows_app_uid=VIEWER_APP_UID) parser = option_parser() opts, args = parser.parse_args(args) oat = opts.open_at if oat and not ( oat.startswith('toc:') or oat.startswith('toc-href:') or oat.startswith('toc-href-contains:') or oat.startswith('epubcfi(/') or is_float(oat) or oat.startswith('ref:')): raise SystemExit('Not a valid --open-at value: {}'.format(opts.open_at)) if get_session_pref('singleinstance', False): from calibre.utils.lock import SingleInstance from calibre.gui2.listener import Listener with SingleInstance(singleinstance_name) as si: if si: try: listener = Listener(address=viewer_socket_address(), parent=app) listener.start_listening() except Exception as err: error_dialog(None, _('Failed to start listener'), _( 'Could not start the listener used for single instance viewers. Try rebooting your computer.'), det_msg=str(err), show=True) else: with closing(listener): run_gui(app, opts, args, internal_book_data, listener=listener) else: send_message_to_viewer_instance(args, opts.open_at) else: run_gui(app, opts, args, internal_book_data)
def install(self, profile, schemes): self.schemes = schemes """Install the handler for luminos:// URLs on the given profile.""" if QWebEngineUrlScheme is not None: assert QWebEngineUrlScheme.schemeByName(b"luminos").name() profile.installUrlSchemeHandler(b"luminos", self) for scheme in schemes.keys(): if QWebEngineUrlScheme.schemeByName(scheme.encode("ascii")).name(): profile.installUrlSchemeHandler(scheme.encode("ascii"), self) if qtutils.version_check("5.11", compiled=False) and not qtutils.version_check( "5.12", compiled=False): # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-63378 profile.installUrlSchemeHandler(b"chrome-error", self) profile.installUrlSchemeHandler(b"chrome-extension", self)
def main(args=sys.argv): # Ensure viewer can continue to function if GUI is closed os.environ.pop('CALIBRE_WORKER_TEMP_DIR', None) reset_base_dir() scheme = QWebEngineUrlScheme(FAKE_PROTOCOL.encode('ascii')) scheme.setSyntax(QWebEngineUrlScheme.Syntax.Host) scheme.setFlags(QWebEngineUrlScheme.SecureScheme) QWebEngineUrlScheme.registerScheme(scheme) override = 'calibre-ebook-viewer' if islinux else None app = Application(args, override_program_name=override, windows_app_uid=VIEWER_APP_UID) parser = option_parser() opts, args = parser.parse_args(args) oat = opts.open_at if oat and not ( oat.startswith('toc:') or oat.startswith('toc-href:') or oat.startswith('toc-href-contains:') or oat.startswith('epubcfi(/') or is_float(oat)): raise SystemExit('Not a valid --open-at value: {}'.format(opts.open_at)) listener = None if get_session_pref('singleinstance', False): try: listener = ensure_single_instance(args, opts.open_at) except Exception as e: import traceback error_dialog(None, _('Failed to start viewer'), as_unicode(e), det_msg=traceback.format_exc(), show=True) raise SystemExit(1) acc = EventAccumulator(app) app.file_event_hook = acc app.load_builtin_fonts() app.setWindowIcon(QIcon(I('viewer.png'))) migrate_previous_viewer_prefs() main = EbookViewer(open_at=opts.open_at, continue_reading=opts.continue_reading, force_reload=opts.force_reload) main.set_exception_handler() if len(args) > 1: acc.events.append(os.path.abspath(args[-1])) acc.got_file.connect(main.handle_commandline_arg) main.show() main.msg_from_anotherinstance.connect(main.another_instance_wants_to_talk, type=Qt.QueuedConnection) if listener is not None: t = Thread(name='ConnListener', target=listen, args=(listener, main.msg_from_anotherinstance)) t.daemon = True t.start() QTimer.singleShot(0, acc.flush) if opts.raise_window: main.raise_() if opts.full_screen: main.set_full_screen(True) app.exec_() if listener is not None: listener.close()
def install(self, profile): """Install the handler for qute:// URLs on the given profile.""" if QWebEngineUrlScheme is not None: assert QWebEngineUrlScheme.schemeByName(b'qute') is not None profile.installUrlSchemeHandler(b'qute', self) if (qtutils.version_check('5.11', compiled=False) and not qtutils.version_check('5.12', compiled=False)): # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-63378 profile.installUrlSchemeHandler(b'chrome-error', self) profile.installUrlSchemeHandler(b'chrome-extension', self)
def registerUriScheme(cls, name: str, base_path: str): if not name in cls.schemes.keys(): cls.schemes[name] = base_path if not QWebEngineUrlScheme.schemeByName(name.encode()).name(): scheme = QWebEngineUrlScheme(name.encode()) scheme.setFlags( QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed | QWebEngineUrlScheme.ContentSecurityPolicyIgnored | QWebEngineUrlScheme.SecureScheme ) QWebEngineUrlScheme.registerScheme(scheme)
def init(): """Register the qute:// scheme. Note this needs to be called early, before constructing any QtWebEngine classes. """ if QWebEngineUrlScheme is not None: assert not QWebEngineUrlScheme.schemeByName(b'qute').name() scheme = QWebEngineUrlScheme(b'qute') scheme.setFlags(QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed) QWebEngineUrlScheme.registerScheme(scheme)
def _run(args, notify=None): # Ensure we can continue to function if GUI is closed os.environ.pop('CALIBRE_WORKER_TEMP_DIR', None) reset_base_dir() scheme = QWebEngineUrlScheme(FAKE_PROTOCOL.encode('ascii')) scheme.setSyntax(QWebEngineUrlScheme.Syntax.Host) scheme.setFlags(QWebEngineUrlScheme.SecureScheme) QWebEngineUrlScheme.registerScheme(scheme) # The following two lines are needed to prevent circular imports causing # errors during initialization of plugins that use the polish container # infrastructure. importlib.import_module('calibre.customize.ui') from calibre.gui2.tweak_book import tprefs from calibre.gui2.tweak_book.ui import Main parser = option_parser() opts, args = parser.parse_args(args) decouple('edit-book-'), set_gui_prefs(tprefs) override = 'calibre-edit-book' if islinux else None app = Application(args, override_program_name=override, color_prefs=tprefs, windows_app_uid=EDITOR_APP_UID) app.file_event_hook = EventAccumulator() app.load_builtin_fonts() app.setWindowIcon(QIcon(I('tweak.png'))) main = Main(opts, notify=notify) main.set_exception_handler() main.show() app.shutdown_signal_received.connect(main.boss.quit) if len(args) > 1: main.boss.open_book(args[1], edit_file=args[2:], clear_notify_data=False) else: for path in reversed(app.file_event_hook.events): main.boss.open_book(path) break app.file_event_hook = main.boss.open_book app.exec_() # Ensure that the parse worker has quit so that temp files can be deleted # on windows st = time.time() from calibre.gui2.tweak_book.preview import parse_worker while parse_worker.is_alive() and time.time() - st < 120: time.sleep(0.1)
def initializeSchemes(): name = QWebEngineUrlScheme.schemeByName(SCHEME_DWEB.encode()).name() if name: log.debug('initializeSchemes() already called') return declareUrlScheme(SCHEME_DWEB, syntax=QWebEngineUrlScheme.Syntax.Path, flags=serviceWorkersFlags) declareUrlScheme(SCHEME_DWEBGW, syntax=QWebEngineUrlScheme.Syntax.Path, flags=serviceWorkersFlags) declareUrlScheme(SCHEME_FS, syntax=QWebEngineUrlScheme.Syntax.Path, flags=serviceWorkersFlags) declareUrlScheme(SCHEME_IPFS, syntax=QWebEngineUrlScheme.Syntax.Host, flags=serviceWorkersFlags) declareUrlScheme(SCHEME_IPNS, syntax=QWebEngineUrlScheme.Syntax.Host, flags=serviceWorkersFlags) declareUrlScheme(SCHEME_IPID, syntax=QWebEngineUrlScheme.Syntax.Host, flags=defaultSchemeFlags | QWebEngineUrlScheme.ContentSecurityPolicyIgnored) declareUrlScheme(SCHEME_I, syntax=QWebEngineUrlScheme.Syntax.Path, flags=defaultSchemeFlags) declareUrlScheme(SCHEME_ENS, syntax=QWebEngineUrlScheme.Syntax.Host, flags=serviceWorkersFlags) declareUrlScheme(SCHEME_ENSR, syntax=QWebEngineUrlScheme.Syntax.Host) declareUrlScheme(SCHEME_GEMINI, syntax=QWebEngineUrlScheme.Syntax.Host, flags=defaultSchemeFlags) dappsRegisterSchemes() registerMiscSchemes()
def specialize_options(self, log, opts, input_fmt): # Ensure Qt is setup to be used with WebEngine # specialize_options is called early enough in the pipeline # that hopefully no Qt application has been constructed as yet from PyQt5.QtWebEngineCore import QWebEngineUrlScheme from PyQt5.QtWebEngineWidgets import QWebEnginePage # noqa from ebook_converter.gui2 import must_use_qt from ebook_converter.constants_old import FAKE_PROTOCOL scheme = QWebEngineUrlScheme(FAKE_PROTOCOL.encode('ascii')) scheme.setSyntax(QWebEngineUrlScheme.Syntax.Host) scheme.setFlags(QWebEngineUrlScheme.SecureScheme) QWebEngineUrlScheme.registerScheme(scheme) must_use_qt() self.input_fmt = input_fmt if opts.pdf_use_document_margins: # Prevent the conversion pipeline from overwriting document margins opts.margin_left = opts.margin_right = opts.margin_top = opts.margin_bottom = -1
def registerSchemes(cls): if QWebEngineUrlScheme: appSchema = QWebEngineUrlScheme(b'app') appSchema.setFlags( QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.ContentSecurityPolicyIgnored) appSchema.setSyntax(QWebEngineUrlScheme.Syntax.Path) QWebEngineUrlScheme.registerScheme(appSchema) extensionScheme = QWebEngineUrlScheme(b'extension') extensionScheme.setFlags( QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.ContentSecurityPolicyIgnored) extensionScheme.setSyntax(QWebEngineUrlScheme.Syntax.Path) QWebEngineUrlScheme.registerScheme(extensionScheme)
def install(self, profile): """Install the handler for qute:// URLs on the given profile.""" if QWebEngineUrlScheme is not None: assert QWebEngineUrlScheme.schemeByName(b'qute') is not None profile.installUrlSchemeHandler(b'qute', self)
def registerVoceUrlScheme(cls): voceUrlScheme = QWebEngineUrlScheme(cls.schemeName) voceUrlScheme.setFlags(QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed) QWebEngineUrlScheme.registerScheme(voceUrlScheme)
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()))
def __init__(self): super(MainWindow, self).__init__() self._okToClose = False # systray = QSystemTrayIcon(self) # systray.setIcon(QIcon(":/icons/icon.png")) # systray.show() # def systray_activated(reason): # self.setVisible(self.isVisible() ^ True) # systray.activated.connect(systray_activated) # results self._incr_results = None self._fts_results = None self._found_items = None # status self._selection_pending = False self._loading_pending = False self._auto_fts_phrase = None # Lazy-loaded objects self._lazy = {} # Local URL scheme for name in _LOCAL_SCHEMES: scheme = QWebEngineUrlScheme(name.encode("ascii")) scheme.setFlags( QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed | QWebEngineUrlScheme.CorsEnabled ) QWebEngineUrlScheme.registerScheme(scheme) self._scheme_handler = MyUrlSchemeHandler(self) profile = QWebEngineProfile.defaultProfile() for name in _LOCAL_SCHEMES: profile.installUrlSchemeHandler(name.encode("ascii"), self._scheme_handler) # Url request interceptor profile.setUrlRequestInterceptor(UrlRequestInterceptor(self)) # Setup self._setup_ui() self._restore_from_config() # Timers def _makeSingleShotTimer(slot): timer = QTimer(self) timer.setSingleShot(True) timer.timeout.connect(slot) return timer self._timerUpdateIndex = _makeSingleShotTimer(self._updateIndex) self._timerAutoFTS = _makeSingleShotTimer(self._onTimerAutoFullSearchTimeout) self._timerAutoPron = _makeSingleShotTimer(self._onTimerAutoPronTimeout) self._timerSpellCorrection = _makeSingleShotTimer(self._onTimerSpellCorrection) self._timerSearchingLabel = _makeSingleShotTimer(self._onTimerSearchingLabel) # Clipboard clipboard = QApplication.clipboard() clipboard.dataChanged.connect( partial(self._onClipboardChanged, mode=QClipboard.Clipboard) ) clipboard.selectionChanged.connect( partial(self._onClipboardChanged, mode=QClipboard.Selection) ) # Stylesheet for the item list pane try: self._ui.listWidgetIndex.setStyleSheet( _load_static_data("styles/list.css").decode("utf-8", "ignore") ) except EnvironmentError: pass # Check index QTimer.singleShot(0, self._check_index) # Show self.show() # Click the dock icon (macOS) if objc: def applicationShouldHandleReopen_hasVisibleWindows_(s, a, f): self.show() objc.classAddMethods( Cocoa.NSApplication.sharedApplication().delegate().class__(), [applicationShouldHandleReopen_hasVisibleWindows_], )
def main(): """ Main entry point into the application. """ global app from PyQt5.QtGui import QGuiApplication QGuiApplication.setDesktopFileName("eric6_browser.desktop") options = [ ("--config=configDir", "use the given directory as the one containing the config files"), ("--private", "start the browser in private browsing mode"), ("--qthelp", "start the browser with support for QtHelp"), ("--quiet", "don't show any startup error messages"), ("--search=word", "search for the given word"), ("--settings=settingsDir", "use the given directory to store the settings files"), ("--single", "start the browser as a single application"), ] appinfo = AppInfo.makeAppInfo(sys.argv, "eric6 Web Browser", "file", "web browser", options) # set the library paths for plugins Startup.setLibraryPaths() if qVersionTuple() >= (5, 12, 0): from PyQt5.QtWebEngineCore import QWebEngineUrlScheme scheme = QWebEngineUrlScheme(b"eric") scheme.setSyntax(QWebEngineUrlScheme.Syntax.Path) scheme.setFlags(QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.ContentSecurityPolicyIgnored) QWebEngineUrlScheme.registerScheme(scheme) if "--qthelp" in sys.argv and qVersionTuple() >= (5, 12, 0): from PyQt5.QtWebEngineCore import QWebEngineUrlScheme scheme = QWebEngineUrlScheme(b"qthelp") scheme.setSyntax(QWebEngineUrlScheme.Syntax.Path) scheme.setFlags(QWebEngineUrlScheme.SecureScheme) QWebEngineUrlScheme.registerScheme(scheme) app = E5Application(sys.argv) if "--private" not in sys.argv: client = WebBrowserSingleApplicationClient() res = client.connect() if res > 0: if len(sys.argv) > 1: client.processArgs(sys.argv[1:]) sys.exit(0) elif res < 0: print("eric6_browser: {0}".format(client.errstr())) # __IGNORE_WARNING_M801__ sys.exit(res) res = Startup.simpleAppStartup(sys.argv, appinfo, createMainWidget, installErrorHandler=True, app=app) sys.exit(res)
def enableSchemeFlag(name: str, flag): scheme = QWebEngineUrlScheme.schemeByName(name.encode()) if scheme: scheme.setFlags(scheme.flags() | flag)
def add_provider(self, bundle_info, name, **kw): self.schemes.add(name) def is_true(value): return value and value.casefold() in ('true', '1', 'on') from PyQt5.QtWebEngineCore import QWebEngineUrlScheme scheme = QWebEngineUrlScheme(name.encode('utf-8')) port = kw.get('defaultPort', None) if port is not None: scheme.setDefaultPort(int(port)) syntax = kw.get('syntax', None) if syntax == "Path": scheme.setSyntax(QWebEngineUrlScheme.Syntax.Path) elif syntax == "Host": scheme.setSyntax(QWebEngineUrlScheme.Syntax.Host) elif syntax == "HostAndPort": scheme.setSyntax(QWebEngineUrlScheme.Syntax.HostAndPort) elif syntax == "HostPortAndUserInformation": scheme.setSyntax( QWebEngineUrlScheme.Syntax.HostPortAndUserInformation) flags = 0 if is_true(kw.get("SecureScheme", None)): flags |= QWebEngineUrlScheme.SecureScheme if is_true(kw.get("LocalScheme", None)): flags |= QWebEngineUrlScheme.LocalScheme if is_true(kw.get("LocalAccessAllowed", None)): flags |= QWebEngineUrlScheme.LocalAccessAllowed if is_true(kw.get("NoAccessAllowed", None)): flags |= QWebEngineUrlScheme.NoAccessAllowed if is_true(kw.get("ServiceWorkersAllowed", None)): flags |= QWebEngineUrlScheme.ServiceWorkersAllowed if is_true(kw.get("ViewSourceAllowed", None)): flags |= QWebEngineUrlScheme.ViewSourceAllowed if is_true(kw.get("ContentSecurityPolicyIgnored", None)): flags |= QWebEngineUrlScheme.ContentSecurityPolicyIgnored if flags: scheme.setFlags(flags) QWebEngineUrlScheme.registerScheme(scheme)
class Browser(Application): # pylint: disable=too-many-instance-attributes """The main browser""" url_scheme: QWebEngineUrlScheme bridge_initialized: bool dev_view: QWebEngineView dev_page: WebPage qdock: QDockWidget def __init__(self): super().__init__() self.init() # self.load() def init(self): """Initialize browser""" logger.debug("Initializing Browser Window") if web_greeter_config["config"]["greeter"]["debug_mode"]: os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = '12345' url_scheme = "web-greeter" self.url_scheme = QWebEngineUrlScheme(url_scheme.encode()) self.url_scheme.setDefaultPort(QWebEngineUrlScheme.PortUnspecified) self.url_scheme.setFlags(QWebEngineUrlScheme.SecureScheme or QWebEngineUrlScheme.LocalScheme or QWebEngineUrlScheme.LocalAccessAllowed) QWebEngineUrlScheme.registerScheme(self.url_scheme) self.profile = QWebEngineProfile.defaultProfile() self.interceptor = QtUrlRequestInterceptor(url_scheme) self.url_scheme_handler = QtUrlSchemeHandler() self.view = QWebEngineView(parent=self.window) self.page = WebPage() self.view.setPage(self.page) self.page.setObjectName("WebG Page") self.view.setObjectName("WebG View") self.channel = QWebChannel(self.page) self.bridge_initialized = False self.profile.installUrlSchemeHandler(url_scheme.encode(), self.url_scheme_handler) self._initialize_page() if web_greeter_config["config"]["greeter"]["debug_mode"]: self._initialize_devtools() else: self.view.setContextMenuPolicy(Qt.PreventContextMenu) self._init_actions() if web_greeter_config["app"]["frame"]: self._init_menu_bar() else: self.window.setWindowFlags(self.window.windowFlags() | Qt.FramelessWindowHint) if web_greeter_config["config"]["greeter"]["secure_mode"]: if hasattr(QWebEngineProfile, "setUrlRequestInterceptor"): self.profile.setUrlRequestInterceptor(self.interceptor) else: # Older Qt5 versions self.profile.setRequestInterceptor(self.interceptor) self.page.setBackgroundColor(QColor(0, 0, 0)) self.window.setStyleSheet("""QMainWindow, QWebEngineView { background: #000000; }""") self.window.setCentralWidget(self.view) logger.debug("Browser Window created") def load(self): """Load theme and initialize bridge""" self.load_theme() self.bridge_objects = (self.greeter, self.greeter_config, self.theme_utils) self.initialize_bridge_objects() self.load_script(':/_greeter/js/bundle.js', 'Web Greeter Bundle') def _initialize_devtools(self): self.dev_view = QWebEngineView(parent=self.window) self.dev_page = WebPage() self.dev_view.setPage(self.dev_page) self.page.setDevToolsPage(self.dev_page) self.dev_view.setObjectName("Devtools view") self.dev_page.setObjectName("Devtools page") self.dev_page.windowCloseRequested.connect( lambda: self.toggle_devtools_value(False)) inspect_element_action = self.page.action(self.page.InspectElement) inspect_element_action.triggered.connect( lambda: self.toggle_devtools_value(True)) self.qdock = QDockWidget() self.qdock.setWidget(self.dev_view) self.qdock.setFeatures(QDockWidget.DockWidgetMovable or QDockWidget.DockWidgetClosable) self.window.addDockWidget(Qt.RightDockWidgetArea, self.qdock) self.qdock.hide() logger.debug("DevTools initialized") def toggle_devtools(self): """Toggle devtools""" if not web_greeter_config["config"]["greeter"]["debug_mode"]: return self.toggle_devtools_value(not self.qdock.isVisible()) def toggle_devtools_value(self, value: bool): """Toggle devtools by value""" if not web_greeter_config["config"]["greeter"]["debug_mode"]: return if value: self.qdock.show() self.dev_view.setFocus() else: self.qdock.hide() self.view.setFocus() def _init_actions(self): """Init browser actions""" self.exit_action = QAction(QIcon("exit.png"), "&Quit", self.window) self.exit_action.setShortcut("Ctrl+Q") self.exit_action.setStatusTip("Exit application") self.exit_action.triggered.connect(qApp.quit) self.toggle_dev_action = QAction("Toggle Developer Tools", self.window) self.toggle_dev_action.setShortcut("Ctrl+Shift+I") self.toggle_dev_action.triggered.connect(self.toggle_devtools) self.fullscreen_action = QAction("Toggle Fullscreen", self.window) self.fullscreen_action.setShortcut("F11") self.fullscreen_action.triggered.connect( lambda: self.toggle_fullscreen(not self.window.isFullScreen())) self.inc_zoom_action = QAction("Zoom In", self.window) self.inc_zoom_action.setShortcut("Ctrl++") self.inc_zoom_action.triggered.connect(self._inc_zoom) self.dec_zoom_action = QAction("Zoom Out", self.window) self.dec_zoom_action.setShortcut("Ctrl+-") self.dec_zoom_action.triggered.connect(self._dec_zoom) self.reset_zoom_action = QAction("Actual Size", self.window) self.reset_zoom_action.setShortcut("Ctrl+0") self.reset_zoom_action.triggered.connect(self._reset_zoom) self.window.addAction(self.exit_action) self.window.addAction(self.toggle_dev_action) self.window.addAction(self.fullscreen_action) self.window.addAction(self.inc_zoom_action) self.window.addAction(self.dec_zoom_action) self.window.addAction(self.reset_zoom_action) def _inc_zoom(self): if self.view.hasFocus(): self.page.increaseZoom() else: self.dev_page.increaseZoom() def _dec_zoom(self): if self.view.hasFocus(): self.page.decreaseZoom() else: self.dev_page.decreaseZoom() def _reset_zoom(self): if self.view.hasFocus(): self.page.setZoomFactor(1) else: self.dev_page.setZoomFactor(1) def _init_menu_bar(self): minimize_action = QAction("Minimize", self.window) minimize_action.setShortcut("Ctrl+M") minimize_action.triggered.connect(self.window.showMinimized) close_action = QAction("Close", self.window) close_action.setShortcut("Ctrl+W") close_action.triggered.connect(self.window.close) self.page.action( self.page.ReloadAndBypassCache).setText("Force Reload") self.page.fullScreenRequested.connect(self.accept_fullscreen) self.menu_bar = QMenuBar() file_menu = self.menu_bar.addMenu("&File") file_menu.addAction(self.exit_action) edit_menu = self.menu_bar.addMenu("&Edit") edit_menu.addAction(self.page.action(self.page.Undo)) edit_menu.addAction(self.page.action(self.page.Redo)) edit_menu.addSeparator() edit_menu.addAction(self.page.action(self.page.Cut)) edit_menu.addAction(self.page.action(self.page.Copy)) edit_menu.addAction(self.page.action(self.page.Paste)) edit_menu.addSeparator() edit_menu.addAction(self.page.action(self.page.SelectAll)) view_menu = self.menu_bar.addMenu("&View") view_menu.addAction(self.page.action(self.page.Reload)) view_menu.addAction(self.page.action(self.page.ReloadAndBypassCache)) view_menu.addAction(self.toggle_dev_action) view_menu.addSeparator() view_menu.addAction(self.reset_zoom_action) view_menu.addAction(self.inc_zoom_action) view_menu.addAction(self.dec_zoom_action) view_menu.addSeparator() view_menu.addAction(self.fullscreen_action) window_menu = self.menu_bar.addMenu("&Window") window_menu.addAction(minimize_action) window_menu.addAction(close_action) # help_menu = menu_bar.addMenu("&Help") self.window.setMenuBar(self.menu_bar) def accept_fullscreen(self, request): """Accepts fullscreen requests""" if web_greeter_config["config"]["greeter"]["debug_mode"]: request.reject() return if request.toggleOn(): self.toggle_fullscreen(True) else: self.toggle_fullscreen(False) request.accept() def toggle_fullscreen(self, value: bool): """Toggle fullscreen""" if not web_greeter_config["config"]["greeter"]["debug_mode"]: return if value: state = self.states["FULLSCREEN"] self.window.setWindowFlags(self.window.windowFlags() or Qt.FramelessWindowHint) self.menu_bar.setParent(None) self.window.setMenuBar(None) else: state = self.states["NORMAL"] self.window.setWindowFlags(self.window.windowFlags() or not Qt.FramelessWindowHint) self.window.setMenuBar(self.menu_bar) try: self.window.windowHandle().setWindowState(state) except (AttributeError, TypeError): self.window.setWindowState(state) def _initialize_page(self): page_settings = self.page.settings().globalSettings() if not web_greeter_config["config"]["greeter"]["secure_mode"]: ENABLED_SETTINGS.append('LocalContentCanAccessRemoteUrls') else: DISABLED_SETTINGS.append('LocalContentCanAccessRemoteUrls') for setting in DISABLED_SETTINGS: try: page_settings.setAttribute( getattr(QWebEngineSettings, setting), False) except AttributeError: pass for setting in ENABLED_SETTINGS: try: page_settings.setAttribute( getattr(QWebEngineSettings, setting), True) except AttributeError: pass self.page.setView(self.view) def load_theme(self): """Load theme""" theme = web_greeter_config["config"]["greeter"]["theme"] dir_t = "/usr/share/web-greeter/themes/" path_to_theme = os.path.join(dir_t, theme, "index.html") def_theme = "gruvbox" if theme.startswith("/"): path_to_theme = theme elif theme.__contains__(".") or theme.__contains__("/"): path_to_theme = os.path.join(os.getcwd(), theme) path_to_theme = os.path.realpath(path_to_theme) if not path_to_theme.endswith(".html"): path_to_theme = os.path.join(path_to_theme, "index.html") if not os.path.exists(path_to_theme): print("Path does not exists", path_to_theme) path_to_theme = os.path.join(dir_t, def_theme, "index.html") web_greeter_config["config"]["greeter"]["theme"] = path_to_theme url = QUrl(f"web-greeter://app/{path_to_theme}") self.page.load(url) logger.debug("Theme loaded") @staticmethod def _create_webengine_script(path: Url, name: str) -> QWebEngineScript: script = QWebEngineScript() script_file = QFile(path) # print(script_file, path) if script_file.open(QFile.ReadOnly): script_string = str(script_file.readAll(), 'utf-8') script.setInjectionPoint(QWebEngineScript.DocumentCreation) script.setName(name) script.setWorldId(QWebEngineScript.MainWorld) script.setSourceCode(script_string) # print(script_string) return script def _get_channel_api_script(self) -> QWebEngineScript: return self._create_webengine_script(':/qtwebchannel/qwebchannel.js', 'QWebChannel API') def _init_bridge_channel(self) -> None: self.page.setWebChannel(self.channel) self.bridge_initialized = True def initialize_bridge_objects(self) -> None: """Initialize bridge objects :D""" if not self.bridge_initialized: self._init_bridge_channel() registered_objects = self.channel.registeredObjects() for obj in self.bridge_objects: if obj not in registered_objects: # pylint: disable=protected-access self.channel.registerObject(obj._name, obj) # print("Registered", obj._name) def load_script(self, path: Url, name: str): """Loads a script in page""" qt_api = self._get_channel_api_script() qt_api_source = qt_api.sourceCode() script = self._create_webengine_script(path, name) script.setSourceCode(qt_api_source + "\n" + script.sourceCode()) self.page.scripts().insert(script)
def __init__(self, qthelp_file, parent = None): """ Constructor of HelpDialog :param qthelp_file: full path to qthelp helpfile """ super(HelpDialog,self).__init__(parent) # instantiate help engine helpEngine = QHelpEngine(qthelp_file) helpEngine.setupData() self._helpEngine = helpEngine # base dialog widget self.ui = QDialog(None, QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowMinMaxButtonsHint | QtCore.Qt.WindowCloseButtonHint ) self.ui.setWindowTitle("HelpViewer") self.ui.setWindowIcon(QIcon(":/images/prog_icons/help/help.ico")) # Create webview for help information # and assign a custom URL scheme handler for scheme "qthelp) self._wv = QWebEngineView(self.ui) if QWebEngineUrlScheme is not None: scheme = QWebEngineUrlScheme(b'qthelp') scheme.setFlags(QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed) QWebEngineUrlScheme.registerScheme(scheme) self._urlschemehandler = HelpSchemeHandler(self._helpEngine, self._wv.page().profile()) self._wv.page().profile().installUrlSchemeHandler(b'qthelp', self._urlschemehandler) # get help content overview widget self._helpContent = self._helpEngine.contentWidget() self._helpIndex = self._helpEngine.indexWidget() self._helpSearchQuery = self._helpEngine.searchEngine().queryWidget() self._helpSearchResult = self._helpEngine.searchEngine().resultWidget() self._se = self._helpEngine.searchEngine() self._se.reindexDocumentation() self._helpSearchQuery.search.connect(self.search) # create QSplitter self._splitterMain = QSplitter(QtCore.Qt.Vertical) self._splitterMain.setOpaqueResize(False) self._splitterSearch = QSplitter(QtCore.Qt.Horizontal) self._splitterSearch.setOpaqueResize(False) self._splitterUpper = QSplitter(QtCore.Qt.Horizontal) self._splitterUpper.setOpaqueResize(False) self._splitterLower = QSplitter(QtCore.Qt.Horizontal) self._splitterLower.setOpaqueResize(False) # create horzLayout self._horzLayoutSearch = QHBoxLayout() self._horzLayoutUpper = QHBoxLayout() self._horzLayoutLower = QHBoxLayout() # create vertLayout self._vertLayout = QVBoxLayout() # main widgets self._upperWidget = QWidget() self._lowerWidget = QWidget() self._btnReset = QPushButton() self._btnReset.setMaximumHeight(23) self._btnReset.setMaximumWidth(100) # build search structure self._splitterSearch.insertWidget(0, self._helpSearchQuery) self._splitterSearch.insertWidget(1, self._btnReset) # build upper inner structure self._splitterUpper.insertWidget(0, self._helpContent) self._splitterUpper.insertWidget(1, self._wv) self._horzLayoutUpper.addWidget(self._splitterUpper) self._upperWidget.setLayout(self._horzLayoutUpper) # build lower inner structure self._splitterLower.insertWidget(0, self._helpIndex) self._splitterLower.insertWidget(1, self._helpSearchResult) self._horzLayoutLower.addWidget(self._splitterLower) self._lowerWidget.setLayout(self._horzLayoutLower) # build outer structure self._splitterMain.insertWidget(0, self._splitterSearch) self._splitterMain.insertWidget(1, self._upperWidget) self._splitterMain.insertWidget(2, self._lowerWidget) self._helpSearchResult.hide() self._btnReset.hide() self._vertLayout.addWidget(self._splitterMain) self.ui.setLayout(self._vertLayout) # set splitter width w = self._splitterUpper.geometry().width() self._splitterUpper.setSizes([w*(1/4), w*(3/4)]) w = self._splitterLower.geometry().width() self._splitterLower.setSizes([w*(1/5), w*(4/5)]) h = self._splitterMain.geometry().height() self._splitterMain.setSizes([h*(1/9), h*(7/9), h*(1/9)]) self._helpContent.linkActivated.connect(self._wv.setUrl) self._helpIndex.linkActivated.connect(self._wv.setUrl) self._helpSearchResult.requestShowLink.connect(self._wv.setUrl) self._se.searchingFinished.connect(self.showResults) self._btnReset.clicked.connect(self.resetResult) self.retranslateMsg()
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()))