Beispiel #1
0
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)
Beispiel #2
0
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)
Beispiel #3
0
 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)
Beispiel #4
0
    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)
Beispiel #5
0
 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)
Beispiel #6
0
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()))
Beispiel #7
0
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')
Beispiel #8
0
    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)
Beispiel #9
0
    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
Beispiel #10
0
    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()
Beispiel #11
0
    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
Beispiel #12
0
    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()
Beispiel #13
0
    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)
Beispiel #14
0
    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)
Beispiel #15
0
 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)
Beispiel #16
0
    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')
Beispiel #17
0
    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]))
Beispiel #18
0
    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)
Beispiel #19
0
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)
Beispiel #20
0
    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()
Beispiel #21
0
    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))
Beispiel #22
0
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)
Beispiel #23
0
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)
Beispiel #24
0
    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)
Beispiel #25
0
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)
Beispiel #26
0
    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
Beispiel #27
0
 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)
Beispiel #28
0
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()
Beispiel #29
0
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()
Beispiel #30
0
 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)
Beispiel #31
0
 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)
Beispiel #32
0
    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)
Beispiel #33
0
 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)
Beispiel #34
0
    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
Beispiel #35
0
    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)
Beispiel #36
0
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))
Beispiel #37
0
    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()
Beispiel #38
0
    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
Beispiel #40
0
 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)
Beispiel #41
0
 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
Beispiel #42
0
    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)
Beispiel #43
0
 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))
Beispiel #44
0
 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)
Beispiel #45
0
    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))
Beispiel #46
0
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)
Beispiel #47
0
def get(*args, **kwargs):
    """Convenience method to call get(...) of the config instance."""
    return objreg.get('config').get(*args, **kwargs)
Beispiel #48
0
    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)
Beispiel #49
0
 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))
Beispiel #50
0
def section(sect):
    """Get a config section from the global config."""
    return objreg.get('config')[sect]
Beispiel #51
0
 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)
Beispiel #52
0
 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)
Beispiel #53
0
def _save_version():
    """Save the current version to the state config."""
    state_config = objreg.get('state-config')
    state_config['general']['version'] = qutebrowser.__version__
Beispiel #54
0
    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)
Beispiel #55
0
 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)
Beispiel #56
0
 def _current_tab(self):
     """Get the currently displayed tab."""
     window = objreg.get('tabbed-browser',
                         scope='window',
                         window=self._win_id)
     return window.currentWidget()
Beispiel #57
0
    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)
Beispiel #58
0
    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)
Beispiel #59
0
 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)
Beispiel #60
0
 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