def get_tab(win_id, target): """Get a tab widget for the given usertypes.ClickTarget. Args: win_id: The window ID to open new tabs in target: A usertypes.ClickTarget """ if target == usertypes.ClickTarget.tab: win_id = win_id bg_tab = False elif target == usertypes.ClickTarget.tab_bg: win_id = win_id bg_tab = True elif target == usertypes.ClickTarget.window: tabbed_browser = objreg.get('tabbed-browser', scope='window', window=win_id) window = mainwindow.MainWindow(private=tabbed_browser.private) window.show() win_id = window.win_id bg_tab = False else: raise ValueError("Invalid ClickTarget {}".format(target)) tabbed_browser = objreg.get('tabbed-browser', scope='window', window=win_id) return tabbed_browser.tabopen(url=None, background=bg_tab)
def _init_key_config(parent): """Initialize the key config. Args: parent: The parent to use for the KeyConfigParser. """ args = objreg.get('args') try: key_config = keyconf.KeyConfigParser(standarddir.config(), 'keys.conf', args.relaxed_config, parent=parent) except (keyconf.KeyConfigError, UnicodeDecodeError) as e: log.init.exception(e) errstr = "Error while reading key config:\n" if e.lineno is not None: errstr += "In line {}: ".format(e.lineno) error.handle_fatal_exc(e, args, "Error while reading key config!", pre_text=errstr) # We didn't really initialize much so far, so we just quit hard. sys.exit(usertypes.Exit.err_key_config) else: objreg.register('key-config', key_config) if standarddir.config() is not None: save_manager = objreg.get('save-manager') filename = os.path.join(standarddir.config(), 'keys.conf') save_manager.add_saveable( 'key-config', key_config.save, key_config.config_dirty, config_opt=('general', 'auto-save-config'), filename=filename, dirty=key_config.is_dirty)
def __init__(self, parent=None): super().__init__(parent) self.setAcceptRichText(False) self.setReadOnly(True) objreg.get("config").changed.connect(self.update_font) self.update_font() self.setFocusPolicy(Qt.ClickFocus)
def __init__(self, *, win_id, tab_id, tab, private, parent=None): super().__init__(parent) if sys.platform == 'darwin' and qtutils.version_check('5.4'): # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-42948 # See https://github.com/qutebrowser/qutebrowser/issues/462 self.setStyle(QStyleFactory.create('Fusion')) # FIXME:qtwebengine this is only used to set the zoom factor from # the QWebPage - we should get rid of it somehow (signals?) self.tab = tab self._tabdata = tab.data self.win_id = win_id self.scroll_pos = (-1, -1) self._old_scroll_pos = (-1, -1) self._set_bg_color() self._tab_id = tab_id page = webpage.BrowserPage(win_id=self.win_id, tab_id=self._tab_id, tabdata=tab.data, private=private, parent=self) try: page.setVisibilityState( QWebPage.VisibilityStateVisible if self.isVisible() else QWebPage.VisibilityStateHidden) except AttributeError: pass self.setPage(page) mode_manager = objreg.get('mode-manager', scope='window', window=win_id) mode_manager.entered.connect(self.on_mode_entered) mode_manager.left.connect(self.on_mode_left) objreg.get('config').changed.connect(self._set_bg_color)
def __init__(self, section, option, parent=None): super().__init__(parent) self._section = section self._option = option objreg.get('config').changed.connect(self.update_current_value) cur_cat = self.new_category("Current/Default", sort=0) value = config.get(section, option, raw=True) if not value: value = '""' self.cur_item, _descitem, _miscitem = self.new_item(cur_cat, value, "Current value") self.new_item(cur_cat, configdata.DATA[section][option].default(), "Default value") if hasattr(configdata.DATA[section], 'valtype'): # Same type for all values (ValueList) vals = configdata.DATA[section].valtype.complete() else: if option is None: raise ValueError("option may only be None for ValueList " "sections, but {} is not!".format(section)) # Different type for each value (KeyValue) vals = configdata.DATA[section][option].typ.complete() if vals is not None: cat = self.new_category("Allowed", sort=1) for (val, desc) in vals: self.new_item(cat, val, desc)
def _process_args(args): """Open startpage etc. and process commandline args.""" config_obj = objreg.get('config') for sect, opt, val in args.temp_settings: try: config_obj.set('temp', sect, opt, val) except (configexc.Error, configparser.Error) as e: message.error("set: {} - {}".format(e.__class__.__name__, e)) if not args.override_restore: _load_session(args.session) session_manager = objreg.get('session-manager') if not session_manager.did_load: log.init.debug("Initializing main window...") window = mainwindow.MainWindow() if not args.nowindow: window.show() qApp.setActiveWindow(window) process_pos_args(args.command) _open_startpage() _open_quickstart(args) delta = datetime.datetime.now() - earlyinit.START_TIME log.init.debug("Init finished after {}s".format(delta.total_seconds()))
def _load_session(name): """Load the default session. Args: name: The name of the session to load, or None to read state file. """ state_config = objreg.get('state-config') if name is None: try: name = state_config['general']['session'] except KeyError: # No session given as argument and none in the session file -> # start without loading a session return session_manager = objreg.get('session-manager') try: session_manager.load(name) except sessions.SessionNotFoundError: message.error("Session {} not found!".format(name)) except sessions.SessionError as e: message.error("Failed to load session {}: {}".format(name, e)) try: del state_config['general']['session'] except KeyError: pass # If this was a _restart session, delete it. if name == '_restart': session_manager.delete('_restart')
def run(self, text, count=None): """Parse a command from a line of text and run it. Args: text: The text to parse. count: The count to pass to the command. """ record_last_command = True record_macro = True mode_manager = objreg.get('mode-manager', scope='window', window=self._win_id) cur_mode = mode_manager.mode for result in self._parser.parse_all(text): if result.cmd.no_replace_variables: args = result.args else: args = replace_variables(self._win_id, result.args) result.cmd.run(self._win_id, args, count=count) if result.cmdline[0] == 'repeat-command': record_last_command = False if result.cmdline[0] in ['record-macro', 'run-macro', 'set-cmd-text']: record_macro = False if record_last_command: last_command[cur_mode] = (text, count) if record_macro and cur_mode == usertypes.KeyMode.normal: macro_recorder = objreg.get('macro-recorder') macro_recorder.record_command(text, count)
def _ask(self, text, mode, owner=None): """Ask a blocking question in the statusbar. Args: text: The text to display to the user. mode: A PromptMode. owner: An object which will abort the question if destroyed, or None. Return: The answer the user gave or None if the prompt was cancelled. """ q = usertypes.Question() q.text = text q.mode = mode self.shutting_down.connect(q.abort) if owner is not None: owner.destroyed.connect(q.abort) # This might be a generic network manager, e.g. one belonging to a # DownloadManager. In this case, just skip the webview thing. if self._tab_id is not None: tab = objreg.get('tab', scope='tab', window=self._win_id, tab=self._tab_id) tab.load_started.connect(q.abort) bridge = objreg.get('message-bridge', scope='window', window=self._win_id) bridge.ask(q, blocking=True) q.deleteLater() return q.answer
def __init__(self, win_id, parent=None): super().__init__(parent) self._win_id = win_id objreg.register('completion', self, scope='window', window=win_id) cmd = objreg.get('status-command', scope='window', window=win_id) completer_obj = completer.Completer(cmd, win_id, self) completer_obj.next_prev_item.connect(self.on_next_prev_item) objreg.register('completer', completer_obj, scope='window', window=win_id) self.enabled = config.get('completion', 'show') objreg.get('config').changed.connect(self.set_enabled) # FIXME handle new aliases. # objreg.get('config').changed.connect(self.init_command_completion) self._column_widths = base.BaseCompletionModel.COLUMN_WIDTHS self._delegate = completiondelegate.CompletionItemDelegate(self) self.setItemDelegate(self._delegate) style.set_register_stylesheet(self) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Minimum) self.setHeaderHidden(True) self.setAlternatingRowColors(True) self.setIndentation(0) self.setItemsExpandable(False) self.setExpandsOnDoubleClick(False) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # WORKAROUND # This is a workaround for weird race conditions with invalid # item indexes leading to segfaults in Qt. # # Some background: http://bugs.quassel-irc.org/issues/663 # The proposed fix there was later reverted because it didn't help. self.setUniformRowHeights(True) self.hide()
def _ask(self, text, mode, owner=None): """Ask a blocking question in the statusbar. Args: text: The text to display to the user. mode: A PromptMode. owner: An object which will abort the question if destroyed, or None. Return: The answer the user gave or None if the prompt was cancelled. """ q = usertypes.Question() q.text = text q.mode = mode self.shutting_down.connect(q.abort) if owner is not None: owner.destroyed.connect(q.abort) webview = objreg.get('webview', scope='tab', window=self._win_id, tab=self._tab_id) webview.loadStarted.connect(q.abort) bridge = objreg.get('message-bridge', scope='window', window=self._win_id) bridge.ask(q, blocking=True) q.deleteLater() return q.answer
def _start_cb(self, elems): """Initialize the elements and labels based on the context set.""" filterfunc = webelem.FILTERS.get(self._context.group, lambda e: True) elems = [e for e in elems if filterfunc(e)] if not elems: message.error(self._win_id, "No elements found.", immediately=True) return strings = self._hint_strings(elems) log.hints.debug("hints: {}".format(', '.join(strings))) for elem, string in zip(elems, strings): label = HintLabel(elem, self._context) label.update_text('', string) self._context.all_labels.append(label) self._context.labels[string] = label keyparsers = objreg.get('keyparsers', scope='window', window=self._win_id) keyparser = keyparsers[usertypes.KeyMode.hint] keyparser.update_bindings(strings) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) message_bridge.set_text(self._get_text()) modeman.enter(self._win_id, usertypes.KeyMode.hint, 'HintManager.start') # to make auto-follow == 'always' work self._handle_auto_follow()
def __init__(self, parent=None): super().__init__(parent) self.columns_to_filter = [self.URL_COLUMN, self.TEXT_COLUMN] self._quickmark_cat = self.new_category("Quickmarks") self._bookmark_cat = self.new_category("Bookmarks") self._history_cat = self.new_category("History") quickmark_manager = objreg.get('quickmark-manager') quickmarks = quickmark_manager.marks.items() for qm_name, qm_url in quickmarks: self.new_item(self._quickmark_cat, qm_url, qm_name) quickmark_manager.added.connect( lambda name, url: self.new_item(self._quickmark_cat, url, name)) quickmark_manager.removed.connect(self.on_quickmark_removed) bookmark_manager = objreg.get('bookmark-manager') bookmarks = bookmark_manager.marks.items() for bm_url, bm_title in bookmarks: self.new_item(self._bookmark_cat, bm_url, bm_title) bookmark_manager.added.connect( lambda name, url: self.new_item(self._bookmark_cat, url, name)) bookmark_manager.removed.connect(self.on_bookmark_removed) self._history = objreg.get('web-history') self._max_history = config.get('completion', 'web-history-max-items') history = utils.newest_slice(self._history, self._max_history) for entry in history: self._add_history_entry(entry) self._history.add_completion_item.connect(self.on_history_item_added) self._history.cleared.connect(self.on_history_cleared) objreg.get('config').changed.connect(self.reformat_timestamps)
def _prevnext_cb(elems): elem = _find_prevnext(prev, elems) word = 'prev' if prev else 'forward' if elem is None: message.error(win_id, "No {} links found!".format(word)) return url = elem.resolve_url(baseurl) if url is None: message.error(win_id, "No {} links found!".format(word)) return qtutils.ensure_valid(url) if window: from qutebrowser.mainwindow import mainwindow new_window = mainwindow.MainWindow() new_window.show() tabbed_browser = objreg.get('tabbed-browser', scope='window', window=new_window.win_id) tabbed_browser.tabopen(url, background=False) elif tab: tabbed_browser = objreg.get('tabbed-browser', scope='window', window=win_id) tabbed_browser.tabopen(url, background=background) else: browsertab.openurl(url)
def __init__(self, win_id, parent=None): super().__init__(parent) self._widget = None self._win_id = win_id self._default_zoom_changed = False self._init_neighborlist() objreg.get('config').changed.connect(self._on_config_changed)
def _start_cb(self, elems): """Initialize the elements and labels based on the context set.""" filterfunc = webelem.FILTERS.get(self._context.group, lambda e: True) elems = [e for e in elems if filterfunc(e)] if not elems: raise cmdexc.CommandError("No elements found.") strings = self._hint_strings(elems) log.hints.debug("hints: {}".format(', '.join(strings))) for e, string in zip(elems, strings): label = self._draw_label(e, string) elem = ElemTuple(e, label) self._context.all_elems.append(elem) self._context.elems[string] = elem keyparsers = objreg.get('keyparsers', scope='window', window=self._win_id) keyparser = keyparsers[usertypes.KeyMode.hint] keyparser.update_bindings(strings) self._context.tab.contents_size_changed.connect( self.on_contents_size_changed) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) message_bridge.set_text(self._get_text()) modeman.enter(self._win_id, usertypes.KeyMode.hint, 'HintManager.start')
def __init__(self, parent=None): super().__init__(parent) assert cmdutils.cmd_dict cmdlist = [] for obj in set(cmdutils.cmd_dict.values()): if (obj.hide or (obj.debug and not objreg.get('args').debug) or obj.deprecated): pass else: cmdlist.append((obj.name, obj.desc)) for name, cmd in config.section('aliases').items(): cmdlist.append((name, "Alias for '{}'".format(cmd))) cat = self.new_category("Commands") # map each command to its bound keys and show these in the misc column keyconf = objreg.get('key-config') cmd_to_keys = defaultdict(list) for key, cmd in keyconf.get_bindings_for('normal').items(): # put special bindings last if utils.is_special_key(key): cmd_to_keys[cmd].append(key) else: cmd_to_keys[cmd].insert(0, key) for (name, desc) in sorted(cmdlist): self.new_item(cat, name, desc, ', '.join(cmd_to_keys[name]))
def _prevnext_cb(elems): if elems is None: message.error("There was an error while getting hint elements") return elem = _find_prevnext(prev, elems) word = 'prev' if prev else 'forward' if elem is None: message.error("No {} links found!".format(word)) return url = elem.resolve_url(baseurl) if url is None: message.error("No {} links found!".format(word)) return qtutils.ensure_valid(url) cur_tabbed_browser = objreg.get('tabbed-browser', scope='window', window=win_id) if window: new_window = mainwindow.MainWindow( private=cur_tabbed_browser.private) new_window.show() tabbed_browser = objreg.get('tabbed-browser', scope='window', window=new_window.win_id) tabbed_browser.tabopen(url, background=False) elif tab: cur_tabbed_browser.tabopen(url, background=background) else: browsertab.openurl(url)
def init(): """Initialize the global QWebSettings.""" cache_path = standarddir.cache() data_path = standarddir.data() if config.get('general', 'private-browsing') or cache_path is None: QWebSettings.setIconDatabasePath('') else: QWebSettings.setIconDatabasePath(cache_path) if cache_path is not None: QWebSettings.setOfflineWebApplicationCachePath( os.path.join(cache_path, 'application-cache')) if data_path is not None: QWebSettings.globalSettings().setLocalStoragePath( os.path.join(data_path, 'local-storage')) QWebSettings.setOfflineStoragePath( os.path.join(data_path, 'offline-storage')) for sectname, section in MAPPINGS.items(): for optname, mapping in section.items(): default = mapping.save_default() log.config.vdebug("Saved default for {} -> {}: {!r}".format( sectname, optname, default)) value = config.get(sectname, optname) log.config.vdebug("Setting {} -> {} to {!r}".format( sectname, optname, value)) mapping.set(value) objreg.get('config').changed.connect(update_settings)
def _start_cb(self, elems): """Initialize the elements and labels based on the context set.""" if self._context is None: log.hints.debug("In _start_cb without context!") return if elems is None: message.error("There was an error while getting hint elements") return if not elems: message.error("No elements found.") return strings = self._hint_strings(elems) log.hints.debug("hints: {}".format(', '.join(strings))) for elem, string in zip(elems, strings): label = HintLabel(elem, self._context) label.update_text('', string) self._context.all_labels.append(label) self._context.labels[string] = label keyparsers = objreg.get('keyparsers', scope='window', window=self._win_id) keyparser = keyparsers[usertypes.KeyMode.hint] keyparser.update_bindings(strings) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) message_bridge.set_text(self._get_text()) modeman.enter(self._win_id, usertypes.KeyMode.hint, 'HintManager.start') # to make auto_follow == 'always' work self._handle_auto_follow()
def _check_prerequisites(self, win_id): """Check if the command is permitted to run currently. Args: win_id: The window ID the command is run in. """ mode_manager = objreg.get('mode-manager', scope='window', window=win_id) curmode = mode_manager.mode if self._modes is not None and curmode not in self._modes: mode_names = '/'.join(mode.name for mode in self._modes) raise cmdexc.PrerequisitesError( "{}: This command is only allowed in {} mode.".format( self.name, mode_names)) elif self._not_modes is not None and curmode in self._not_modes: mode_names = '/'.join(mode.name for mode in self._not_modes) raise cmdexc.PrerequisitesError( "{}: This command is not allowed in {} mode.".format( self.name, mode_names)) if self._needs_js and not QWebSettings.globalSettings().testAttribute( QWebSettings.JavascriptEnabled): raise cmdexc.PrerequisitesError( "{}: This command needs javascript enabled.".format(self.name)) used_backend = usertypes.arg2backend[objreg.get('args').backend] if self.backend is not None and used_backend != self.backend: raise cmdexc.PrerequisitesError( "{}: Only available with {} " "backend.".format(self.name, self.backend.name)) if self.deprecated: message.warning(win_id, '{} is deprecated - {}'.format( self.name, self.deprecated))
def _init_misc(): """Initialize misc. config-related files.""" save_manager = objreg.get('save-manager') state_config = ini.ReadWriteConfigParser(standarddir.data(), 'state') for sect in ['general', 'geometry']: try: state_config.add_section(sect) except configparser.DuplicateSectionError: pass # See commit a98060e020a4ba83b663813a4b9404edb47f28ad. state_config['general'].pop('fooled', None) objreg.register('state-config', state_config) save_manager.add_saveable('state-config', state_config.save) # We need to import this here because lineparser needs config. from qutebrowser.misc import lineparser command_history = lineparser.LimitLineParser( standarddir.data(), 'cmd-history', limit=('completion', 'cmd-history-max-items'), parent=objreg.get('config')) objreg.register('command-history', command_history) save_manager.add_saveable('command-history', command_history.save, command_history.changed) # Set the QSettings path to something like # ~/.config/qutebrowser/qsettings/qutebrowser/qutebrowser.conf so it # doesn't overwrite our config. # # This fixes one of the corruption issues here: # https://github.com/qutebrowser/qutebrowser/issues/515 path = os.path.join(standarddir.config(), 'qsettings') for fmt in [QSettings.NativeFormat, QSettings.IniFormat]: QSettings.setPath(fmt, QSettings.UserScope, path)
def info(message, immediately=True): """Convienience function to display an info message in the statusbar. Args: See MessageBridge.info. """ objreg.get('message-bridge').info(message, immediately)
def __init__(self, win_id, parent=None): log.init.debug("Initializing NetworkManager") with log.disable_qt_msghandler(): # WORKAROUND for a hang when a message is printed - See: # http://www.riverbankcomputing.com/pipermail/pyqt/2014-November/035045.html super().__init__(parent) log.init.debug("NetworkManager init done") self._win_id = win_id self._requests = [] self._scheme_handlers = { 'qute': qutescheme.QuteSchemeHandler(win_id), } # We have a shared cookie jar and cache - we restore their parents so # we don't take ownership of them. app = QCoreApplication.instance() cookie_jar = objreg.get('cookie-jar') self.setCookieJar(cookie_jar) cookie_jar.setParent(app) cache = objreg.get('cache') self.setCache(cache) cache.setParent(app) if SSL_AVAILABLE: self.sslErrors.connect(self.on_ssl_errors) self.authenticationRequired.connect(self.on_authentication_required) self.proxyAuthenticationRequired.connect( self.on_proxy_authentication_required)
def error(message, immediately=False): """Convienience function to display an error message in the statusbar. Args: See MessageBridge.error. """ objreg.get('message-bridge').error(message, immediately)
def _save_all(self, *, only_window=None, with_private=False): """Get a dict with data for all windows/tabs.""" data = {'windows': []} if only_window is not None: winlist = [only_window] else: winlist = objreg.window_registry for win_id in sorted(winlist): tabbed_browser = objreg.get('tabbed-browser', scope='window', window=win_id) main_window = objreg.get('main-window', scope='window', window=win_id) # We could be in the middle of destroying a window here if sip.isdeleted(main_window): continue if tabbed_browser.private and not with_private: continue win_data = {} active_window = QApplication.instance().activeWindow() if getattr(active_window, 'win_id', None) == win_id: win_data['active'] = True win_data['geometry'] = bytes(main_window.saveGeometry()) win_data['tabs'] = [] if tabbed_browser.private: win_data['private'] = True for i, tab in enumerate(tabbed_browser.widgets()): active = i == tabbed_browser.currentIndex() win_data['tabs'].append(self._save_tab(tab, active)) data['windows'].append(win_data) return data
def __init__(self): self.blocked_hosts = set() self._in_progress = [] self._done_count = 0 data_dir = standarddir.get(QStandardPaths.DataLocation) self._hosts_file = os.path.join(data_dir, 'blocked-hosts') objreg.get('config').changed.connect(self.on_config_changed)
def alert(message): """Display an alert which needs to be confirmed.""" q = usertypes.Question() q.text = message q.mode = usertypes.PromptMode.alert objreg.get('message-bridge').ask(q, blocking=True) q.deleteLater()
def init(): """Initialize QtWebEngine-specific modules.""" # For some reason we need to keep a reference, otherwise the scheme handler # won't work... # https://www.riverbankcomputing.com/pipermail/pyqt/2016-September/038075.html global _qute_scheme_handler app = QApplication.instance() log.init.debug("Initializing qute://* handler...") _qute_scheme_handler = webenginequtescheme.QuteSchemeHandler(parent=app) _qute_scheme_handler.install(webenginesettings.default_profile) _qute_scheme_handler.install(webenginesettings.private_profile) log.init.debug("Initializing request interceptor...") host_blocker = objreg.get('host-blocker') req_interceptor = interceptor.RequestInterceptor( host_blocker, parent=app) req_interceptor.install(webenginesettings.default_profile) req_interceptor.install(webenginesettings.private_profile) log.init.debug("Initializing QtWebEngine downloads...") download_manager = webenginedownloads.DownloadManager(parent=app) download_manager.install(webenginesettings.default_profile) download_manager.install(webenginesettings.private_profile) objreg.register('webengine-download-manager', download_manager) greasemonkey = objreg.get('greasemonkey') greasemonkey.scripts_reloaded.connect(webenginesettings.inject_userscripts) webenginesettings.inject_userscripts()
def __init__(self, parent=None): super().__init__(parent) self._lineparser = lineparser.AppendLineParser( standarddir.data(), 'history', parent=self) self._history_dict = collections.OrderedDict() with self._lineparser.open(): for line in self._lineparser: data = line.rstrip().split(maxsplit=1) if not data: # empty line continue elif len(data) != 2: # other malformed line log.init.warning("Invalid history entry {!r}!".format( line)) continue atime, url = data # This de-duplicates history entries; only the latest # entry for each URL is kept. If you want to keep # information about previous hits change the items in # old_urls to be lists or change HistoryEntry to have a # list of atimes. self._history_dict[url] = HistoryEntry(atime, url) self._history_dict.move_to_end(url) self._new_history = [] self._saved_count = 0 objreg.get('save-manager').add_saveable( 'history', self.save, self.item_added)
def delete(data): """Delete a bookmark from the completion menu.""" urlstr = data[0] log.completion.debug('Deleting bookmark {}'.format(urlstr)) bookmark_manager = objreg.get('bookmark-manager') bookmark_manager.delete(urlstr)
def createRequest(self, op, req, outgoing_data): """Return a new QNetworkReply object. Args: op: Operation op req: const QNetworkRequest & req outgoing_data: QIODevice * outgoingData Return: A QNetworkReply. """ if proxymod.application_factory is not None: proxy_error = proxymod.application_factory.get_error() if proxy_error is not None: return networkreply.ErrorNetworkReply( req, proxy_error, QNetworkReply.UnknownProxyError, self) for header, value in shared.custom_headers(url=req.url()): req.setRawHeader(header, value) # There are some scenarios where we can't figure out current_url: # - There's a generic NetworkManager, e.g. for downloads # - The download was in a tab which is now closed. current_url = QUrl() if self._tab_id is not None: assert self._win_id is not None try: tab = objreg.get('tab', scope='tab', window=self._win_id, tab=self._tab_id) current_url = tab.url() except (KeyError, RuntimeError): # https://github.com/qutebrowser/qutebrowser/issues/889 # Catching RuntimeError because we could be in the middle of # the webpage shutdown here. current_url = QUrl() request = interceptors.Request(first_party_url=current_url, request_url=req.url()) interceptors.run(request) if request.is_blocked: return networkreply.ErrorNetworkReply( req, HOSTBLOCK_ERROR_STRING, QNetworkReply.ContentAccessDenied, self) if 'log-requests' in objects.debug_flags: operation = debug.qenum_key(QNetworkAccessManager, op) operation = operation.replace('Operation', '').upper() log.webview.debug("{} {}, first-party {}".format( operation, req.url().toDisplayString(), current_url.toDisplayString())) scheme = req.url().scheme() if scheme in self._scheme_handlers: result = self._scheme_handlers[scheme](req, op, current_url) if result is not None: result.setParent(self) return result self.set_referer(req, current_url) return super().createRequest(op, req, outgoing_data)
def toggle_selection(self): self.selection_enabled = not self.selection_enabled mainwindow = objreg.get('main-window', scope='window', window=self._win_id) mainwindow.status.set_mode_active(usertypes.KeyMode.caret, True)
def _fire(self, keystr: str) -> None: """Fire a completed hint. Args: keystr: The keychain string to follow. """ assert self._context is not None # Handlers which take a QWebElement elem_handlers = { Target.normal: self._actions.click, Target.current: self._actions.click, Target.tab: self._actions.click, Target.tab_fg: self._actions.click, Target.tab_bg: self._actions.click, Target.window: self._actions.click, Target.hover: self._actions.click, Target.right_click: self._actions.click, # _download needs a QWebElement to get the frame. Target.download: self._actions.download, Target.userscript: self._actions.call_userscript, Target.delete: self._actions.delete, } # Handlers which take a QUrl url_handlers = { Target.yank: self._actions.yank, Target.yank_primary: self._actions.yank, Target.run: self._actions.run_cmd, Target.fill: self._actions.preset_cmd_text, Target.spawn: self._actions.spawn, } elem = self._context.labels[keystr].elem if not elem.has_frame(): message.error("This element has no webframe.") return if self._context.target in elem_handlers: handler = functools.partial(elem_handlers[self._context.target], elem, self._context) elif self._context.target in url_handlers: url = elem.resolve_url(self._context.baseurl) if url is None: message.error("No suitable link found for this element.") return handler = functools.partial(url_handlers[self._context.target], url, self._context) if self._context.add_history: objreg.get('web-history').add_url(url, "") else: raise ValueError("No suitable handler found!") if not self._context.rapid: modeman.leave(self._win_id, usertypes.KeyMode.hint, 'followed', maybe=True) else: # Reset filtering self.filter_hints(None) # Undo keystring highlighting for string, label in self._context.labels.items(): label.update_text('', string) try: handler() except HintingError as e: message.error(str(e)) if self._context is not None: self._context.first_run = False
def start( self, # pylint: disable=keyword-arg-before-vararg group: str = 'all', target: Target = Target.normal, *args: str, mode: str = None, add_history: bool = False, rapid: bool = False, first: bool = False) -> None: """Start hinting. Args: rapid: Whether to do rapid hinting. With rapid hinting, the hint mode isn't left after a hint is followed, so you can easily open multiple links. This is only possible with targets `tab` (with `tabs.background=true`), `tab-bg`, `window`, `run`, `hover`, `userscript` and `spawn`. add_history: Whether to add the spawned or yanked link to the browsing history. first: Click the first hinted element without prompting. group: The element types to hint. - `all`: All clickable elements. - `links`: Only links. - `images`: Only images. - `inputs`: Only input fields. Custom groups can be added via the `hints.selectors` setting and also used here. target: What to do with the selected element. - `normal`: Open the link. - `current`: Open the link in the current tab. - `tab`: Open the link in a new tab (honoring the `tabs.background` setting). - `tab-fg`: Open the link in a new foreground tab. - `tab-bg`: Open the link in a new background tab. - `window`: Open the link in a new window. - `hover` : Hover over the link. - `right-click`: Right-click the element. - `yank`: Yank the link to the clipboard. - `yank-primary`: Yank the link to the primary selection. - `run`: Run the argument as command. - `fill`: Fill the commandline with the command given as argument. - `download`: Download the link. - `userscript`: Call a userscript with `$QUTE_URL` set to the link. - `spawn`: Spawn a command. - `delete`: Delete the selected element. mode: The hinting mode to use. - `number`: Use numeric hints. - `letter`: Use the chars in the hints.chars setting. - `word`: Use hint words based on the html elements and the extra words. *args: Arguments for spawn/userscript/run/fill. - With `spawn`: The executable and arguments to spawn. `{hint-url}` will get replaced by the selected URL. - With `userscript`: The userscript to execute. Either store the userscript in `~/.local/share/qutebrowser/userscripts` (or `$XDG_DATA_HOME`), or use an absolute path. - With `fill`: The command to fill the statusbar with. `{hint-url}` will get replaced by the selected URL. - With `run`: Same as `fill`. """ tabbed_browser = objreg.get('tabbed-browser', scope='window', window=self._win_id) tab = tabbed_browser.widget.currentWidget() if tab is None: raise cmdutils.CommandError("No WebView available yet!") mode_manager = objreg.get('mode-manager', scope='window', window=self._win_id) if mode_manager.mode == usertypes.KeyMode.hint: modeman.leave(self._win_id, usertypes.KeyMode.hint, 're-hinting') if rapid: if target in [ Target.tab_bg, Target.window, Target.run, Target.hover, Target.userscript, Target.spawn, Target.download, Target.normal, Target.current, Target.yank, Target.yank_primary ]: pass elif target == Target.tab and config.val.tabs.background: pass else: name = target.name.replace('_', '-') raise cmdutils.CommandError("Rapid hinting makes no sense " "with target {}!".format(name)) self._check_args(target, *args) self._context = HintContext() self._context.tab = tab self._context.target = target self._context.rapid = rapid self._context.hint_mode = self._get_hint_mode(mode) self._context.add_history = add_history self._context.first = first try: self._context.baseurl = tabbed_browser.current_url() except qtutils.QtValueError: raise cmdutils.CommandError("No URL set for this page yet!") self._context.args = list(args) self._context.group = group try: selector = webelem.css_selector(self._context.group, self._context.baseurl) except webelem.Error as e: raise cmdutils.CommandError(str(e)) self._context.tab.elements.find_css( selector, callback=self._start_cb, error_cb=lambda err: message.error(str(err)), only_visible=True)
def debug_cache_stats(): """Print LRU cache stats.""" config_info = objreg.get('config').get.cache_info() style_info = style.get_stylesheet.cache_info() log.misc.debug('config: {}'.format(config_info)) log.misc.debug('style: {}'.format(style_info))
def __init__(self, debug, parent=None): """Constructor for CrashDialog. Args: debug: Whether --debug was given. """ super().__init__(parent) # We don't set WA_DeleteOnClose here as on an exception, we'll get # closed anyways, and it only could have unintended side-effects. self._crash_info = [] self._btn_box = None self._btn_report = None self._btn_cancel = None self._lbl = None self._paste_text = None self.setWindowTitle("Whoops!") self.resize(QSize(640, 600)) self._vbox = QVBoxLayout(self) http_client = httpclient.HTTPClient() self._paste_client = pastebin.PastebinClient(http_client, self) self._pypi_client = autoupdate.PyPIVersionClient(self) self._init_text() contact = QLabel( "I'd like to be able to follow up with you, to keep " "you posted on the status of this crash and get more " "information if I need it - how can I contact you?", wordWrap=True) self._vbox.addWidget(contact) self._contact = QTextEdit(tabChangesFocus=True, acceptRichText=False) try: state = objreg.get('state-config') try: self._contact.setPlainText(state['general']['contact-info']) except KeyError: self._contact.setPlaceholderText("Mail or IRC nickname") except Exception: log.misc.exception("Failed to get contact information!") self._contact.setPlaceholderText("Mail or IRC nickname") self._vbox.addWidget(self._contact, 2) info = QLabel("What were you doing when this crash/bug happened?") self._vbox.addWidget(info) self._info = QTextEdit(tabChangesFocus=True, acceptRichText=False) self._info.setPlaceholderText("- Opened http://www.example.com/\n" "- Switched tabs\n" "- etc...") self._vbox.addWidget(self._info, 5) self._vbox.addSpacing(15) self._debug_log = QTextEdit(tabChangesFocus=True, acceptRichText=False, lineWrapMode=QTextEdit.NoWrap) self._debug_log.hide() info = QLabel( "<i>You can edit the log below to remove sensitive " "information.</i>", wordWrap=True) info.hide() self._fold = miscwidgets.DetailFold("Show log", self) self._fold.toggled.connect(self._debug_log.setVisible) self._fold.toggled.connect(info.setVisible) if debug: self._fold.toggle() self._vbox.addWidget(self._fold) self._vbox.addWidget(info) self._vbox.addWidget(self._debug_log, 10) self._vbox.addSpacing(15) self._init_checkboxes() self._init_info_text() self._init_buttons()
def tabopen(self, url=None, background=None, related=True, idx=None, *, ignore_tabs_are_windows=False): """Open a new tab with a given URL. Inner logic for open-tab and open-tab-bg. Also connect all the signals we need to _filter_signals. Args: url: The URL to open as QUrl or None for an empty tab. background: Whether to open the tab in the background. if None, the `tabs.background` setting decides. related: Whether the tab was opened from another existing tab. If this is set, the new position might be different. With the default settings we handle it like Chromium does: - Tabs from clicked links etc. are to the right of the current (related=True). - Explicitly opened tabs are at the very right (related=False) idx: The index where the new tab should be opened. ignore_tabs_are_windows: If given, never open a new window, even with tabs.tabs_are_windows set. Return: The opened WebView instance. """ if url is not None: qtutils.ensure_valid(url) log.webview.debug("Creating new tab with URL {}, background {}, " "related {}, idx {}".format(url, background, related, idx)) prev_focus = QApplication.focusWidget() if (config.val.tabs.tabs_are_windows and self.widget.count() > 0 and not ignore_tabs_are_windows): window = mainwindow.MainWindow(private=self.is_private) window.show() tabbed_browser = objreg.get('tabbed-browser', scope='window', window=window.win_id) return tabbed_browser.tabopen(url=url, background=background, related=related) tab = browsertab.create(win_id=self._win_id, private=self.is_private, parent=self.widget) self._connect_tab_signals(tab) if idx is None: idx = self._get_new_tab_idx(related) self.widget.insertTab(idx, tab, "") if url is not None: tab.load_url(url) if background is None: background = config.val.tabs.background if background: # Make sure the background tab has the correct initial size. # With a foreground tab, it's going to be resized correctly by the # layout anyways. tab.resize(self.widget.currentWidget().size()) self.widget.tab_index_changed.emit(self.widget.currentIndex(), self.widget.count()) # Refocus webview in case we lost it by spawning a bg tab self.widget.currentWidget().setFocus() else: self.widget.setCurrentWidget(tab) # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-68076 # Still seems to be needed with Qt 5.11.1 tab.setFocus() mode = modeman.instance(self._win_id).mode if mode in [ usertypes.KeyMode.command, usertypes.KeyMode.prompt, usertypes.KeyMode.yesno ]: # If we were in a command prompt, restore old focus # The above commands need to be run to switch tabs if prev_focus is not None: prev_focus.setFocus() tab.show() self.new_tab.emit(tab, idx) return tab
def tabopen(self, url=None, background=None, related=True, idx=None, *, ignore_tabs_are_windows=False): """Open a new tab with a given URL. Inner logic for open-tab and open-tab-bg. Also connect all the signals we need to _filter_signals. Args: url: The URL to open as QUrl or None for an empty tab. background: Whether to open the tab in the background. if None, the `tabs.background_tabs`` setting decides. related: Whether the tab was opened from another existing tab. If this is set, the new position might be different. With the default settings we handle it like Chromium does: - Tabs from clicked links etc. are to the right of the current (related=True). - Explicitly opened tabs are at the very right (related=False) idx: The index where the new tab should be opened. ignore_tabs_are_windows: If given, never open a new window, even with tabs.tabs_are_windows set. Return: The opened WebView instance. """ if url is not None: qtutils.ensure_valid(url) log.webview.debug("Creating new tab with URL {}, background {}, " "related {}, idx {}".format(url, background, related, idx)) if (config.val.tabs.tabs_are_windows and self.count() > 0 and not ignore_tabs_are_windows): window = mainwindow.MainWindow(private=self.private) window.show() tabbed_browser = objreg.get('tabbed-browser', scope='window', window=window.win_id) return tabbed_browser.tabopen(url=url, background=background, related=related) tab = browsertab.create(win_id=self._win_id, private=self.private, parent=self) self._connect_tab_signals(tab) if idx is None: idx = self._get_new_tab_idx(related) self.insertTab(idx, tab, "") if url is not None: tab.openurl(url) if background is None: background = config.val.tabs.background if background: # Make sure the background tab has the correct initial size. # With a foreground tab, it's going to be resized correctly by the # layout anyways. tab.resize(self.currentWidget().size()) self.tab_index_changed.emit(self.currentIndex(), self.count()) else: self.setCurrentWidget(tab) tab.show() self.new_tab.emit(tab, idx) return tab
def delete(data): """Delete a quickmark from the completion menu.""" name = data[0] quickmark_manager = objreg.get('quickmark-manager') log.completion.debug('Deleting quickmark {}'.format(name)) quickmark_manager.delete(name)
def __init__(self, tab, parent=None): super().__init__(tab, parent) self._args = objreg.get('args') self._pos_perc = (0, 0) self._pos_px = QPoint() self._at_bottom = False
def __init__(self, win_id, parent=None): super().__init__(parent) objreg.register('statusbar', self, scope='window', window=win_id) self.setObjectName(self.__class__.__name__) self.setAttribute(Qt.WA_StyledBackground) style.set_register_stylesheet(self) self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) self._win_id = win_id self._option = None self._stopwatch = QTime() self._hbox = QHBoxLayout(self) self._hbox.setContentsMargins(0, 0, 0, 0) self._hbox.setSpacing(5) self._stack = QStackedLayout() self._hbox.addLayout(self._stack) self._stack.setContentsMargins(0, 0, 0, 0) self.cmd = command.Command(win_id) self._stack.addWidget(self.cmd) objreg.register('status-command', self.cmd, scope='window', window=win_id) self.txt = textwidget.Text() self._stack.addWidget(self.txt) self._timer_was_active = False self._text_queue = collections.deque() self._text_pop_timer = usertypes.Timer(self, 'statusbar_text_pop') self._text_pop_timer.timeout.connect(self._pop_text) self.set_pop_timer_interval() objreg.get('config').changed.connect(self.set_pop_timer_interval) self.prompt = prompt.Prompt(win_id) self._stack.addWidget(self.prompt) self._previous_widget = PreviousWidget.none self.cmd.show_cmd.connect(self._show_cmd_widget) self.cmd.hide_cmd.connect(self._hide_cmd_widget) self._hide_cmd_widget() prompter = objreg.get('prompter', scope='window', window=self._win_id) prompter.show_prompt.connect(self._show_prompt_widget) prompter.hide_prompt.connect(self._hide_prompt_widget) self._hide_prompt_widget() self.keystring = keystring.KeyString() self._hbox.addWidget(self.keystring) self.url = url.UrlText() self._hbox.addWidget(self.url) self.percentage = percentage.Percentage() self._hbox.addWidget(self.percentage) # We add a parent to Progress here because it calls self.show() based # on some signals, and if that happens before it's added to the layout, # it will quickly blink up as independent window. self.prog = progress.Progress(self) self._hbox.addWidget(self.prog)
def _shutdown(self, status, restart): # noqa """Second stage of shutdown.""" log.destroy.debug("Stage 2 of shutting down...") if qApp is None: # No QApplication exists yet, so quit hard. sys.exit(status) # Remove eventfilter try: log.destroy.debug("Removing eventfilter...") event_filter = objreg.get('event-filter', None) if event_filter is not None: qApp.removeEventFilter(event_filter) except AttributeError: pass # Close all windows QApplication.closeAllWindows() # Shut down IPC try: ipc.server.shutdown() except KeyError: pass # Save everything try: save_manager = objreg.get('save-manager') except KeyError: log.destroy.debug("Save manager not initialized yet, so not " "saving anything.") else: for key in save_manager.saveables: try: save_manager.save(key, is_exit=True) except OSError as e: error.handle_fatal_exc( e, self._args, "Error while saving!", pre_text="Error while saving {}".format(key)) # Disable storage so removing tempdir will work websettings.shutdown() # Disable application proxy factory to fix segfaults with Qt 5.10.1 proxy.shutdown() # Re-enable faulthandler to stdout, then remove crash log log.destroy.debug("Deactivating crash log...") objreg.get('crash-handler').destroy_crashlogfile() # Delete temp basedir if ((self._args.temp_basedir or self._args.temp_basedir_restarted) and not restart): atexit.register(shutil.rmtree, self._args.basedir, ignore_errors=True) # Delete temp download dir downloads.temp_download_manager.cleanup() # If we don't kill our custom handler here we might get segfaults log.destroy.debug("Deactivating message handler...") qInstallMessageHandler(None) # Now we can hopefully quit without segfaults log.destroy.debug("Deferring QApplication::exit...") objreg.get('signal-handler').deactivate() session_manager = objreg.get('session-manager', None) if session_manager is not None: session_manager.delete_autosave() # We use a singleshot timer to exit here to minimize the likelihood of # segfaults. QTimer.singleShot(0, functools.partial(qApp.exit, status))
def add_js_bridge(self): """Add the javascript bridge for qute:... pages.""" frame = self.sender() if frame.url().scheme() == 'qute': bridge = objreg.get('js-bridge') frame.addToJavaScriptWindowObject('qute', bridge)
def set_command(self, win_id, section_=None, option=None, value=None, temp=False, print_=False): """Set an option. If the option name ends with '?', the value of the option is shown instead. If the option name ends with '!' and it is a boolean value, toggle it. // Wrapper for self.set() to output exceptions in the status bar. Args: section_: The section where the option is in. option: The name of the option. value: The value to set. temp: Set value temporarily. print_: Print the value after setting. """ if section_ is not None and option is None: raise cmdexc.CommandError( "set: Either both section and option have to be given, or " "neither!") if section_ is None and option is None: tabbed_browser = objreg.get('tabbed-browser', scope='window', window=win_id) tabbed_browser.openurl(QUrl('qute:settings'), newtab=False) return if option.endswith('?') and option != '?': option = option[:-1] print_ = True else: with self._handle_config_error(): if option.endswith('!') and option != '!' and value is None: option = option[:-1] val = self.get(section_, option) layer = 'temp' if temp else 'conf' if isinstance(val, bool): self.set(layer, section_, option, str(not val).lower()) else: raise cmdexc.CommandError( "set: Attempted inversion of non-boolean value.") elif value is not None: layer = 'temp' if temp else 'conf' self.set(layer, section_, option, value) else: raise cmdexc.CommandError("set: The following arguments " "are required: value") if print_: with self._handle_config_error(): val = self.get(section_, option, transformed=False) message.info("{} {} = {}".format(section_, option, val))
def version(win_id): """Show version information.""" tabbed_browser = objreg.get('tabbed-browser', scope='window', window=win_id) tabbed_browser.openurl(QUrl('qute://version'), newtab=True)
def get(*args, **kwargs): """Convenience method to call get(...) of the config instance.""" return objreg.get('config').get(*args, **kwargs)
def start(self, rapid=False, group=webelem.Group.all, target=Target.normal, *args, win_id, mode=None, add_history=False): """Start hinting. Args: rapid: Whether to do rapid hinting. This is only possible with targets `tab` (with `tabs.background_tabs=true`), `tab-bg`, `window`, `run`, `hover`, `userscript` and `spawn`. add_history: Whether to add the spawned or yanked link to the browsing history. group: The element types to hint. - `all`: All clickable elements. - `links`: Only links. - `images`: Only images. - `inputs`: Only input fields. target: What to do with the selected element. - `normal`: Open the link. - `current`: Open the link in the current tab. - `tab`: Open the link in a new tab (honoring the `tabs.background_tabs` setting). - `tab-fg`: Open the link in a new foreground tab. - `tab-bg`: Open the link in a new background tab. - `window`: Open the link in a new window. - `hover` : Hover over the link. - `yank`: Yank the link to the clipboard. - `yank-primary`: Yank the link to the primary selection. - `run`: Run the argument as command. - `fill`: Fill the commandline with the command given as argument. - `download`: Download the link. - `userscript`: Call a userscript with `$QUTE_URL` set to the link. - `spawn`: Spawn a command. mode: The hinting mode to use. - `number`: Use numeric hints. - `letter`: Use the chars in the hints.chars setting. - `word`: Use hint words based on the html elements and the extra words. *args: Arguments for spawn/userscript/run/fill. - With `spawn`: The executable and arguments to spawn. `{hint-url}` will get replaced by the selected URL. - With `userscript`: The userscript to execute. Either store the userscript in `~/.local/share/qutebrowser/userscripts` (or `$XDG_DATA_DIR`), or use an absolute path. - With `fill`: The command to fill the statusbar with. `{hint-url}` will get replaced by the selected URL. - With `run`: Same as `fill`. """ tabbed_browser = objreg.get('tabbed-browser', scope='window', window=self._win_id) tab = tabbed_browser.currentWidget() if tab is None: raise cmdexc.CommandError("No WebView available yet!") mode_manager = objreg.get('mode-manager', scope='window', window=self._win_id) if mode_manager.mode == usertypes.KeyMode.hint: modeman.leave(win_id, usertypes.KeyMode.hint, 're-hinting') if rapid: if target in [ Target.tab_bg, Target.window, Target.run, Target.hover, Target.userscript, Target.spawn, Target.download, Target.normal, Target.current ]: pass elif target == Target.tab and config.val.tabs.background: pass else: name = target.name.replace('_', '-') raise cmdexc.CommandError("Rapid hinting makes no sense with " "target {}!".format(name)) if mode is None: mode = config.val.hints.mode self._check_args(target, *args) self._context = HintContext() self._context.tab = tab self._context.target = target self._context.rapid = rapid self._context.hint_mode = mode self._context.add_history = add_history try: self._context.baseurl = tabbed_browser.current_url() except qtutils.QtValueError: raise cmdexc.CommandError("No URL set for this page yet!") self._context.args = args self._context.group = group selector = webelem.SELECTORS[self._context.group] self._context.tab.elements.find_css(selector, self._start_cb, only_visible=True)
def _shutdown(self, status): # noqa """Second stage of shutdown.""" # pylint: disable=too-many-branches, too-many-statements # FIXME refactor this # https://github.com/The-Compiler/qutebrowser/issues/113 log.destroy.debug("Stage 2 of shutting down...") # Remove eventfilter try: log.destroy.debug("Removing eventfilter...") self.removeEventFilter(self._event_filter) except AttributeError: pass # Close all windows QApplication.closeAllWindows() # Shut down IPC try: objreg.get('ipc-server').shutdown() except KeyError: pass # Save everything try: config_obj = objreg.get('config') except KeyError: log.destroy.debug("Config not initialized yet, so not saving " "anything.") else: to_save = [] if config.get('general', 'auto-save-config'): to_save.append(("config", config_obj.save)) try: key_config = objreg.get('key-config') except KeyError: pass else: to_save.append(("keyconfig", key_config.save)) to_save += [("window geometry", self._save_geometry)] to_save += [("version", self._save_version)] try: command_history = objreg.get('command-history') except KeyError: pass else: to_save.append(("command history", command_history.save)) try: quickmark_manager = objreg.get('quickmark-manager') except KeyError: pass else: to_save.append(("command history", quickmark_manager.save)) try: state_config = objreg.get('state-config') except KeyError: pass else: to_save.append(("window geometry", state_config.save)) try: cookie_jar = objreg.get('cookie-jar') except KeyError: pass else: to_save.append(("cookies", cookie_jar.save)) for what, handler in to_save: log.destroy.debug("Saving {} (handler: {})".format( what, utils.qualname(handler))) try: handler() except OSError as e: msgbox = QMessageBox( QMessageBox.Critical, "Error while saving!", "Error while saving {}: {}".format(what, e)) msgbox.exec_() except AttributeError as e: log.destroy.warning("Could not save {}.".format(what)) log.destroy.debug(e) # Re-enable faulthandler to stdout, then remove crash log log.destroy.debug("Deactiving crash log...") self._destroy_crashlogfile() # If we don't kill our custom handler here we might get segfaults log.destroy.debug("Deactiving message handler...") qInstallMessageHandler(None) # Now we can hopefully quit without segfaults log.destroy.debug("Deferring QApplication::exit...") # We use a singleshot timer to exit here to minimize the likelyhood of # segfaults. QTimer.singleShot(0, functools.partial(self.exit, status))
def section(sect): """Get a config section from the global config.""" return objreg.get('config')[sect]
def _connect_signals(self): """Connect all signals to their slots.""" config_obj = objreg.get('config') self.lastWindowClosed.connect(self.shutdown) config_obj.style_changed.connect(style.get_stylesheet.cache_clear) self.focusChanged.connect(self.on_focus_changed)
def open_desktopservices_url(self, url): """Handler to open an URL via QDesktopServices.""" win_id = self._get_window(via_ipc=True, force_window=False) tabbed_browser = objreg.get('tabbed-browser', scope='window', window=win_id) tabbed_browser.tabopen(url)
def _save_version(): """Save the current version to the state config.""" state_config = objreg.get('state-config') state_config['general']['version'] = qutebrowser.__version__
def _exception_hook(self, exctype, excvalue, tb): # noqa """Handle uncaught python exceptions. It'll try very hard to write all open tabs to a file, and then exit gracefully. """ # pylint: disable=broad-except exc = (exctype, excvalue, tb) if not self._quit_status['crash']: log.misc.error("ARGH, there was an exception while the crash " "dialog is already shown:", exc_info=exc) return log.misc.error("Uncaught exception", exc_info=exc) is_ignored_exception = (exctype is bdb.BdbQuit or not issubclass(exctype, Exception)) if is_ignored_exception or self._args.no_crash_dialog: # pdb exit, KeyboardInterrupt, ... status = 0 if is_ignored_exception else 2 try: self.shutdown(status) return except Exception: log.init.exception("Error while shutting down") self.quit() return self._quit_status['crash'] = False try: pages = self._recover_pages(forgiving=True) except Exception: log.destroy.exception("Error while recovering pages") pages = [] try: history = objreg.get('command-history')[-5:] except Exception: log.destroy.exception("Error while getting history: {}") history = [] try: objects = self.get_all_objects() except Exception: log.destroy.exception("Error while getting objects") objects = "" try: objreg.get('ipc-server').ignored = True except Exception: log.destroy.exception("Error while ignoring ipc") try: self.lastWindowClosed.disconnect(self.shutdown) except TypeError: log.destroy.exception("Error while preventing shutdown") QApplication.closeAllWindows() self._crashdlg = crashdialog.ExceptionCrashDialog( self._args.debug, pages, history, exc, objects) ret = self._crashdlg.exec_() if ret == QDialog.Accepted: # restore self.restart(shutdown=False, pages=pages) # We might risk a segfault here, but that's better than continuing to # run in some undefined state, so we only do the most needed shutdown # here. qInstallMessageHandler(None) self._destroy_crashlogfile() sys.exit(1)
def _get_object(self, name): """Get an object for this window in the object registry.""" return objreg.get(name, scope='window', window=self.win_id)
def _current_tab(self): """Get the currently displayed tab.""" window = objreg.get('tabbed-browser', scope='window', window=self._win_id) return window.currentWidget()
def __init__(self, geometry=None, parent=None): """Create a new main window. Args: geometry: The geometry to load, as a bytes-object (or None). parent: The parent the window should get. """ super().__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) self._commandrunner = None self._overlays = [] self.win_id = next(win_id_gen) self.registry = objreg.ObjectRegistry() objreg.window_registry[self.win_id] = self objreg.register('main-window', self, scope='window', window=self.win_id) tab_registry = objreg.ObjectRegistry() objreg.register('tab-registry', tab_registry, scope='window', window=self.win_id) message_bridge = message.MessageBridge(self) objreg.register('message-bridge', message_bridge, scope='window', window=self.win_id) self.setWindowTitle('qutebrowser') self._vbox = QVBoxLayout(self) self._vbox.setContentsMargins(0, 0, 0, 0) self._vbox.setSpacing(0) self._init_downloadmanager() self._downloadview = downloadview.DownloadView(self.win_id) self.tabbed_browser = tabbedbrowser.TabbedBrowser(self.win_id) objreg.register('tabbed-browser', self.tabbed_browser, scope='window', window=self.win_id) self._init_command_dispatcher() # We need to set an explicit parent for StatusBar because it does some # show/hide magic immediately which would mean it'd show up as a # window. self.status = bar.StatusBar(self.win_id, parent=self) self._add_widgets() self._downloadview.show() self._init_completion() log.init.debug("Initializing modes...") modeman.init(self.win_id, self) self._commandrunner = runners.CommandRunner(self.win_id, partial_match=True) self._keyhint = keyhintwidget.KeyHintView(self.win_id, self) self._add_overlay(self._keyhint, self._keyhint.update_geometry) self._messageview = messageview.MessageView(parent=self) self._add_overlay(self._messageview, self._messageview.update_geometry) self._prompt_container = prompt.PromptContainer(self.win_id, self) self._add_overlay(self._prompt_container, self._prompt_container.update_geometry, centered=True, padding=10) objreg.register('prompt-container', self._prompt_container, scope='window', window=self.win_id) self._prompt_container.hide() if geometry is not None: self._load_geometry(geometry) elif self.win_id == 0: self._load_state_geometry() else: self._set_default_geometry() log.init.debug("Initial main window geometry: {}".format( self.geometry())) self._connect_signals() # When we're here the statusbar might not even really exist yet, so # resizing will fail. Therefore, we use singleShot QTimers to make sure # we defer this until everything else is initialized. QTimer.singleShot(0, self._connect_overlay_signals) objreg.get('config').changed.connect(self.on_config_changed) objreg.get("app").new_window.emit(self)
def _connect_signals(self): """Connect all mainwindow signals.""" key_config = objreg.get('key-config') status = self._get_object('statusbar') keyparsers = self._get_object('keyparsers') completion_obj = self._get_object('completion') tabs = self._get_object('tabbed-browser') cmd = self._get_object('status-command') message_bridge = self._get_object('message-bridge') mode_manager = self._get_object('mode-manager') # misc self.tabbed_browser.close_window.connect(self.close) mode_manager.entered.connect(hints.on_mode_entered) # status bar mode_manager.entered.connect(status.on_mode_entered) mode_manager.left.connect(status.on_mode_left) mode_manager.left.connect(cmd.on_mode_left) mode_manager.left.connect(message.global_bridge.mode_left) # commands keyparsers[usertypes.KeyMode.normal].keystring_updated.connect( status.keystring.setText) cmd.got_cmd.connect(self._commandrunner.run_safely) cmd.returnPressed.connect(tabs.on_cmd_return_pressed) # key hint popup for mode, parser in keyparsers.items(): parser.keystring_updated.connect( functools.partial(self._keyhint.update_keyhint, mode.name)) # config for obj in keyparsers.values(): key_config.changed.connect(obj.on_keyconfig_changed) # messages message.global_bridge.show_message.connect( self._messageview.show_message) message_bridge.s_set_text.connect(status.set_text) message_bridge.s_maybe_reset_text.connect(status.txt.maybe_reset_text) # statusbar tabs.current_tab_changed.connect(status.prog.on_tab_changed) tabs.cur_progress.connect(status.prog.setValue) tabs.cur_load_finished.connect(status.prog.hide) tabs.cur_load_started.connect(status.prog.on_load_started) tabs.current_tab_changed.connect(status.percentage.on_tab_changed) tabs.cur_scroll_perc_changed.connect(status.percentage.set_perc) tabs.tab_index_changed.connect(status.tabindex.on_tab_index_changed) tabs.current_tab_changed.connect(status.url.on_tab_changed) tabs.cur_url_changed.connect(status.url.set_url) tabs.cur_link_hovered.connect(status.url.set_hover_url) tabs.cur_load_status_changed.connect(status.url.on_load_status_changed) # command input / completion mode_manager.left.connect(tabs.on_mode_left) cmd.clear_completion_selection.connect( completion_obj.on_clear_completion_selection) cmd.hide_completion.connect(completion_obj.hide)
def _on_pdfjs_requested(self, filename: str, original_url: QUrl): """Open PDF.js when a download requests it.""" tabbed_browser = objreg.get('tabbed-browser', scope='window', window='last-focused') tabbed_browser.tabopen(pdfjs.get_main_url(filename, original_url), background=False)
def _save_geometry(self): """Save the window geometry to the state config.""" state_config = objreg.get('state-config') data = bytes(self.saveGeometry()) geom = base64.b64encode(data).decode('ASCII') state_config['geometry']['mainwindow'] = geom