Beispiel #1
0
    def contextMenuEvent(self, e):
        """Save a reference to the context menu so we can close it.

        This is not needed for QtWebEngine, so it's in here.
        """
        menu = self.page().createStandardContextMenu()
        self.shutting_down.connect(menu.close)
        modeman.instance(self.win_id).entered.connect(menu.close)
        menu.exec_(e.globalPos())
Beispiel #2
0
    def contextMenuEvent(self, e):
        """Save a reference to the context menu so we can close it.

        This is not needed for QtWebEngine, so it's in here.
        """
        menu = self.page().createStandardContextMenu()
        self.shutting_down.connect(menu.close)
        modeman.instance(self.win_id).entered.connect(menu.close)
        menu.exec_(e.globalPos())
Beispiel #3
0
    def _handle_wheel(self, e):
        """Zoom on Ctrl-Mousewheel.

        Args:
            e: The QWheelEvent.
        """
        if self._ignore_wheel_event:
            # See https://github.com/qutebrowser/qutebrowser/issues/395
            self._ignore_wheel_event = False
            return True

        if e.modifiers() & Qt.ControlModifier:
            mode = modeman.instance(self._tab.win_id).mode
            if mode == usertypes.KeyMode.passthrough:
                return False

            divider = config.val.zoom.mouse_divider
            if divider == 0:
                return False
            factor = self._tab.zoom.factor() + (e.angleDelta().y() / divider)
            if factor < 0:
                return False
            perc = int(100 * factor)
            message.info("Zoom level: {}%".format(perc), replace=True)
            self._tab.zoom.set_factor(factor)
        elif e.modifiers() & Qt.ShiftModifier:
            if e.angleDelta().y() > 0:
                self._tab.scroller.left()
            else:
                self._tab.scroller.right()
            return True

        return False
Beispiel #4
0
    def eventFilter(self, _obj, event):
        """Act on ChildAdded events."""
        if event.type() != QEvent.ChildAdded:
            return False

        pass_modes = [
            usertypes.KeyMode.command, usertypes.KeyMode.prompt,
            usertypes.KeyMode.yesno
        ]

        if modeman.instance(self._win_id).mode in pass_modes:
            return False

        tabbed_browser = objreg.get('tabbed-browser',
                                    scope='window',
                                    window=self._win_id)
        current_index = tabbed_browser.widget.currentIndex()
        try:
            widget_index = tabbed_browser.widget.indexOf(self._widget.parent())
        except RuntimeError:
            widget_index = -1
        if current_index == widget_index:
            QTimer.singleShot(0, self._widget.setFocus)

        return False
Beispiel #5
0
    def eventFilter(self, obj, event):
        """Act on ChildAdded events."""
        if event.type() == QEvent.ChildAdded:
            child = event.child()
            log.misc.debug("{} got new child {}, installing filter".format(
                obj, child))
            assert obj is self._widget
            child.installEventFilter(self._filter)

            if qtutils.version_check('5.11', compiled=False, exact=True):
                # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-68076
                pass_modes = [
                    usertypes.KeyMode.command, usertypes.KeyMode.prompt,
                    usertypes.KeyMode.yesno
                ]
                if modeman.instance(self._win_id).mode not in pass_modes:
                    tabbed_browser = objreg.get('tabbed-browser',
                                                scope='window',
                                                window=self._win_id)
                    current_index = tabbed_browser.widget.currentIndex()
                    try:
                        widget_index = tabbed_browser.widget.indexOf(
                            self._widget.parent())
                    except RuntimeError:
                        widget_index = -1
                    if current_index == widget_index:
                        QTimer.singleShot(0, self._widget.setFocus)

        elif event.type() == QEvent.ChildRemoved:
            child = event.child()
            log.misc.debug("{}: removed child {}".format(obj, child))

        return False
Beispiel #6
0
def create(win_id: int,
           private: bool,
           parent: QWidget = None) -> 'AbstractTab':
    """Get a QtWebKit/QtWebEngine tab object.

    Args:
        win_id: The window ID where the tab will be shown.
        private: Whether the tab is a private/off the record tab.
        parent: The Qt parent to set.
    """
    # Importing modules here so we don't depend on QtWebEngine without the
    # argument and to avoid circular imports.
    mode_manager = modeman.instance(win_id)
    if objects.backend == usertypes.Backend.QtWebEngine:
        from qutebrowser.browser.webengine import webenginetab
        tab_class: Type[AbstractTab] = webenginetab.WebEngineTab
    elif objects.backend == usertypes.Backend.QtWebKit:
        from qutebrowser.browser.webkit import webkittab
        tab_class = webkittab.WebKitTab
    else:
        raise utils.Unreachable(objects.backend)
    return tab_class(win_id=win_id,
                     mode_manager=mode_manager,
                     private=private,
                     parent=parent)
Beispiel #7
0
    def _do_focus_workaround(self):
        """WORKAROUND for https://bugreports.qt.io/browse/QTBUG-68076."""
        if not self._focus_workaround:
            return

        assert self._widget is not None

        pass_modes = [
            usertypes.KeyMode.command, usertypes.KeyMode.prompt,
            usertypes.KeyMode.yesno
        ]

        if modeman.instance(self._win_id).mode in pass_modes:
            return

        tabbed_browser = objreg.get('tabbed-browser',
                                    scope='window',
                                    window=self._win_id)
        current_index = tabbed_browser.widget.currentIndex()
        try:
            widget_index = tabbed_browser.widget.indexOf(self._widget.parent())
        except RuntimeError:
            widget_index = -1
        if current_index == widget_index:
            QTimer.singleShot(0, self._widget.setFocus)
Beispiel #8
0
    def eventFilter(self, obj, event):
        """Act on ChildAdded events."""
        if event.type() == QEvent.ChildAdded:
            child = event.child()
            log.mouse.debug("{} got new child {}, installing filter".format(
                obj, child))
            assert obj is self._widget
            child.installEventFilter(self._filter)

            if qtutils.version_check('5.11', compiled=False, exact=True):
                # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-68076
                pass_modes = [usertypes.KeyMode.command,
                              usertypes.KeyMode.prompt,
                              usertypes.KeyMode.yesno]
                if modeman.instance(self._win_id).mode not in pass_modes:
                    tabbed_browser = objreg.get('tabbed-browser',
                                                scope='window',
                                                window=self._win_id)
                    current_index = tabbed_browser.widget.currentIndex()
                    try:
                        widget_index = tabbed_browser.widget.indexOf(
                            self._widget.parent())
                    except RuntimeError:
                        widget_index = -1
                    if current_index == widget_index:
                        QTimer.singleShot(0, self._widget.setFocus)

        elif event.type() == QEvent.ChildRemoved:
            child = event.child()
            log.mouse.debug("{}: removed child {}".format(obj, child))

        return False
Beispiel #9
0
    def _handle_wheel(self, e):
        """Zoom on Ctrl-Mousewheel.

        Args:
            e: The QWheelEvent.
        """
        if self._ignore_wheel_event:
            # See https://github.com/qutebrowser/qutebrowser/issues/395
            self._ignore_wheel_event = False
            return True

        if e.modifiers() & Qt.ControlModifier:
            mode = modeman.instance(self._tab.win_id).mode
            if mode == usertypes.KeyMode.passthrough:
                return False

            divider = config.val.zoom.mouse_divider
            if divider == 0:
                return False
            factor = self._tab.zoom.factor() + (e.angleDelta().y() / divider)
            if factor < 0:
                return False
            perc = int(100 * factor)
            message.info("Zoom level: {}%".format(perc), replace=True)
            self._tab.zoom.set_factor(factor)
        elif e.modifiers() & Qt.ShiftModifier:
            if e.angleDelta().y() > 0:
                self._tab.scroller.left()
            else:
                self._tab.scroller.right()
            return True

        return False
Beispiel #10
0
    def __init__(self, win_id: int, parent: QObject = None) -> None:
        """Constructor."""
        super().__init__(parent)
        self._win_id = win_id
        self._context: Optional[HintContext] = None
        self._word_hinter = WordHinter()

        self._actions = HintActions(win_id)

        mode_manager = modeman.instance(self._win_id)
        mode_manager.left.connect(self.on_mode_left)
Beispiel #11
0
 def on_mode_entered(self, mode):
     """Mark certain modes in the commandline."""
     mode_manager = modeman.instance(self._win_id)
     if mode_manager.parsers[mode].passthrough:
         self._set_mode_text(mode.name)
     if mode in [
             usertypes.KeyMode.insert, usertypes.KeyMode.command,
             usertypes.KeyMode.caret, usertypes.KeyMode.prompt,
             usertypes.KeyMode.yesno, usertypes.KeyMode.passthrough
     ]:
         self.set_mode_active(mode, True)
Beispiel #12
0
def repeat_command(win_id: int, count: int = None) -> None:
    """Repeat the last executed command.

    Args:
        count: Which count to pass the command.
    """
    mode_manager = modeman.instance(win_id)
    if mode_manager.mode not in runners.last_command:
        raise cmdutils.CommandError("You didn't do anything yet.")
    cmd = runners.last_command[mode_manager.mode]
    commandrunner = runners.CommandRunner(win_id)
    commandrunner.run(cmd[0], count if count is not None else cmd[1])
Beispiel #13
0
    def run_macro_command(self, win_id, count=1, register=None):
        """Run a recorded macro.

        Args:
            count: How many times to run the macro.
            register: Which macro to run.
        """
        self._macro_count[win_id] = count
        if register is None:
            mode_manager = modeman.instance(win_id)
            mode_manager.enter(usertypes.KeyMode.run_macro, 'run_macro')
        else:
            self.run_macro(win_id, register)
Beispiel #14
0
    def macro_run(self, win_id: int, count: int = 1, register: str = None) -> None:
        """Run a recorded macro.

        Args:
            count: How many times to run the macro.
            register: Which macro to run.
        """
        self._macro_count[win_id] = count
        if register is None:
            mode_manager = modeman.instance(win_id)
            mode_manager.enter(usertypes.KeyMode.run_macro, 'run_macro')
        else:
            self.run_macro(win_id, register)
Beispiel #15
0
 def on_mode_left(self, old_mode, new_mode):
     """Clear marked mode."""
     mode_manager = modeman.instance(self._win_id)
     if mode_manager.parsers[old_mode].passthrough:
         if mode_manager.parsers[new_mode].passthrough:
             self._set_mode_text(new_mode.name)
         else:
             self.txt.set_text(self.txt.Text.normal, '')
     if old_mode in [
             usertypes.KeyMode.insert, usertypes.KeyMode.command,
             usertypes.KeyMode.caret, usertypes.KeyMode.prompt,
             usertypes.KeyMode.yesno, usertypes.KeyMode.passthrough
     ]:
         self.set_mode_active(old_mode, False)
Beispiel #16
0
 def on_mode_left(self, old_mode, new_mode):
     """Clear marked mode."""
     mode_manager = modeman.instance(self._win_id)
     if config.val.statusbar.show == 'in-mode':
         self.hide()
     if mode_manager.parsers[old_mode].passthrough:
         if mode_manager.parsers[new_mode].passthrough:
             self._set_mode_text(new_mode.name)
         else:
             self.txt.setText('')
     if old_mode in [
             usertypes.KeyMode.insert, usertypes.KeyMode.command,
             usertypes.KeyMode.caret, usertypes.KeyMode.prompt,
             usertypes.KeyMode.yesno, usertypes.KeyMode.passthrough
     ]:
         self.set_mode_active(old_mode, False)
Beispiel #17
0
    def record_macro_command(self, win_id, register=None):
        """Start or stop recording a macro.

        Args:
            register: Which register to store the macro in.
        """
        if self._recording_macro is None:
            if register is None:
                mode_manager = modeman.instance(win_id)
                mode_manager.enter(usertypes.KeyMode.record_macro,
                                   'record_macro')
            else:
                self.record_macro(register)
        else:
            message.info("Macro '{}' recorded.".format(self._recording_macro))
            self._recording_macro = None
Beispiel #18
0
    def macro_record(self, win_id: int, register: str = None) -> None:
        """Start or stop recording a macro.

        Args:
            register: Which register to store the macro in.
        """
        if self._recording_macro is None:
            if register is None:
                mode_manager = modeman.instance(win_id)
                mode_manager.enter(usertypes.KeyMode.record_macro,
                                   'record_macro')
            else:
                self.record_macro(register)
        else:
            message.info("Macro '{}' recorded.".format(self._recording_macro))
            self._recording_macro = None
Beispiel #19
0
def create(win_id, parent=None):
    """Get a QtWebKit/QtWebEngine tab object.

    Args:
        win_id: The window ID where the tab will be shown.
        parent: The Qt parent to set.
    """
    # Importing modules here so we don't depend on QtWebEngine without the
    # argument and to avoid circular imports.
    mode_manager = modeman.instance(win_id)
    if objects.backend == usertypes.Backend.QtWebEngine:
        from qutebrowser.browser.webengine import webenginetab
        tab_class = webenginetab.WebEngineTab
    else:
        from qutebrowser.browser.webkit import webkittab
        tab_class = webkittab.WebKitTab
    return tab_class(win_id=win_id, mode_manager=mode_manager, parent=parent)
Beispiel #20
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.
        """
        from qutebrowser.keyinput import modeman
        mode_manager = modeman.instance(win_id)
        self.validate_mode(mode_manager.mode)

        if self.backend is not None and objects.backend != self.backend:
            raise cmdexc.PrerequisitesError("{}: Only available with {} "
                                            "backend.".format(
                                                self.name, self.backend.name))

        if self.deprecated:
            message.warning(f'{self.name} is deprecated - {self.deprecated}')
Beispiel #21
0
def create(win_id, parent=None):
    """Get a QtWebKit/QtWebEngine tab object.

    Args:
        win_id: The window ID where the tab will be shown.
        parent: The Qt parent to set.
    """
    # Importing modules here so we don't depend on QtWebEngine without the
    # argument and to avoid circular imports.
    mode_manager = modeman.instance(win_id)
    if objreg.get('args').backend == 'webengine':
        from qutebrowser.browser.webengine import webenginetab
        tab_class = webenginetab.WebEngineTab
    else:
        from qutebrowser.browser.webkit import webkittab
        tab_class = webkittab.WebKitTab
    return tab_class(win_id=win_id, mode_manager=mode_manager, parent=parent)
Beispiel #22
0
    def _handle_wheel(self, e):
        """Zoom on Ctrl-Mousewheel.

        Args:
            e: The QWheelEvent.

        Return:
            True if the event should be filtered, False otherwise.
        """
        if self._ignore_wheel_event:
            # See https://github.com/qutebrowser/qutebrowser/issues/395
            self._ignore_wheel_event = False
            return True

        # Don't allow scrolling while hinting
        mode = modeman.instance(self._tab.win_id).mode
        if mode == usertypes.KeyMode.hint:
            return True

        elif e.modifiers() & Qt.ControlModifier:
            if mode == usertypes.KeyMode.passthrough:
                return False

            divider = config.val.zoom.mouse_divider
            if divider == 0:
                # Disable mouse zooming
                return True

            factor = self._tab.zoom.factor() + (e.angleDelta().y() / divider)
            if factor < 0:
                return True

            perc = int(100 * factor)
            message.info("Zoom level: {}%".format(perc), replace=True)
            self._tab.zoom.set_factor(factor)
            return True
        elif (e.modifiers() & Qt.ShiftModifier
              and not qtutils.version_check('5.9', compiled=False)):
            if e.angleDelta().y() > 0:
                self._tab.scroller.left()
            else:
                self._tab.scroller.right()
            return True

        return False
Beispiel #23
0
    def run(self, text, count=None, *, safely=False):
        """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.
            safely: Show CmdError exceptions as messages.
        """
        record_last_command = True
        record_macro = True

        mode_manager = modeman.instance(self._win_id)
        cur_mode = mode_manager.mode

        parsed = None
        with self._handle_error(safely):
            parsed = self._parser.parse_all(text)

        if parsed is None:
            return  # type: ignore[unreachable]

        for result in parsed:
            with self._handle_error(safely):
                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 [
                    'macro-record', 'macro-run', '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:
            macros.macro_recorder.record_command(text, count)
Beispiel #24
0
    def on_current_changed(self, idx):
        """Set last-focused-tab and leave hinting mode when focus changed."""
        mode_on_change = config.val.tabs.mode_on_change
        if idx == -1 or self.shutting_down:
            # closing the last tab (before quitting) or shutting down
            return
        tab = self.widget.widget(idx)
        if tab is None:
            log.webview.debug("on_current_changed got called with invalid "
                              "index {}".format(idx))
            return

        log.modes.debug("Current tab changed, focusing {!r}".format(tab))
        tab.setFocus()

        modes_to_leave = [usertypes.KeyMode.hint, usertypes.KeyMode.caret]

        mm_instance = modeman.instance(self._win_id)
        current_mode = mm_instance.mode
        log.modes.debug(
            "Mode before tab change: {} (mode_on_change = {})".format(
                current_mode.name, mode_on_change))
        if mode_on_change == 'normal':
            modes_to_leave += modeman.INPUT_MODES
        for mode in modes_to_leave:
            modeman.leave(self._win_id, mode, 'tab changed', maybe=True)
        if (mode_on_change == 'restore'
                and current_mode not in modeman.PROMPT_MODES):
            modeman.enter(self._win_id, tab.data.input_mode, 'restore')
        if self._now_focused is not None:
            objreg.register('last-focused-tab',
                            self._now_focused,
                            update=True,
                            scope='window',
                            window=self._win_id)
        log.modes.debug(
            "Mode after tab change: {} (mode_on_change = {})".format(
                current_mode.name, mode_on_change))
        self._now_focused = tab
        self.current_tab_changed.emit(tab)
        QTimer.singleShot(0, self._update_window_title)
        self._tab_insert_idx_left = self.widget.currentIndex()
        self._tab_insert_idx_right = self.widget.currentIndex() + 1
Beispiel #25
0
    def _handle_key_event(self, event: QKeyEvent) -> bool:
        """Handle a key press/release event.

        Args:
            event: The QEvent which is about to be delivered.

        Return:
            True if the event should be filtered, False if it's passed through.
        """
        if q_app.activeWindow() not in objreg.window_registry.values():
            # Some other window (print dialog, etc.) is focused so we pass the
            # event through.
            return False
        try:
            man = modeman.instance('current')
            return man.handle_event(event)
        except objreg.RegistryUnavailableError:
            # No window available yet, or not a MainWindow
            return False
Beispiel #26
0
    def on_current_changed(self, idx):
        """Set last-focused-tab and leave hinting mode when focus changed."""
        mode_on_change = config.val.tabs.mode_on_change
        modes_to_save = [
            usertypes.KeyMode.insert, usertypes.KeyMode.passthrough
        ]
        if idx == -1 or self.shutting_down:
            # closing the last tab (before quitting) or shutting down
            return
        tab = self.widget(idx)
        if tab is None:
            log.webview.debug("on_current_changed got called with invalid "
                              "index {}".format(idx))
            return
        if self._now_focused is not None and mode_on_change == 'restore':
            current_mode = modeman.instance(self._win_id).mode
            if current_mode not in modes_to_save:
                current_mode = usertypes.KeyMode.normal
            self._now_focused.data.input_mode = current_mode

        log.modes.debug("Current tab changed, focusing {!r}".format(tab))
        tab.setFocus()

        modes_to_leave = [usertypes.KeyMode.hint, usertypes.KeyMode.caret]
        if mode_on_change != 'persist':
            modes_to_leave += modes_to_save
        for mode in modes_to_leave:
            modeman.leave(self._win_id, mode, 'tab changed', maybe=True)
        if mode_on_change == 'restore':
            modeman.enter(self._win_id, tab.data.input_mode,
                          'restore input mode for tab')
        if self._now_focused is not None:
            objreg.register('last-focused-tab',
                            self._now_focused,
                            update=True,
                            scope='window',
                            window=self._win_id)
        self._now_focused = tab
        self.current_tab_changed.emit(tab)
        QTimer.singleShot(0, self._update_window_title)
        self._tab_insert_idx_left = self.currentIndex()
        self._tab_insert_idx_right = self.currentIndex() + 1
Beispiel #27
0
def create(win_id: int,
           private: bool,
           parent: QWidget = None) -> 'AbstractTab':
    """Get a QtWebKit/QtWebEngine tab object.

    Args:
        win_id: The window ID where the tab will be shown.
        private: Whether the tab is a private/off the record tab.
        parent: The Qt parent to set.
    """
    # Importing modules here so we don't depend on QtWebEngine without the
    # argument and to avoid circular imports.
    mode_manager = modeman.instance(win_id)
    if objects.backend == usertypes.Backend.QtWebEngine:
        from qutebrowser.browser.webengine import webenginetab
        tab_class = webenginetab.WebEngineTab
    else:
        from qutebrowser.browser.webkit import webkittab
        tab_class = webkittab.WebKitTab
    return tab_class(win_id=win_id, mode_manager=mode_manager, private=private,
                     parent=parent)
Beispiel #28
0
 def maybe_hide(self):
     """Hide the statusbar if it's configured to do so."""
     strategy = config.val.statusbar.show
     tab = self._current_tab()
     if tab is not None and tab.data.fullscreen:
         self.hide()
     elif strategy == 'never':
         self.hide()
     elif strategy == 'in-mode':
         try:
             mode_manager = modeman.instance(self._win_id)
         except modeman.UnavailableError:
             self.hide()
         else:
             if mode_manager.mode == usertypes.KeyMode.normal:
                 self.hide()
             else:
                 self.show()
     elif strategy == 'always':
         self.show()
     else:
         raise utils.Unreachable
Beispiel #29
0
    def _handle_wheel(self, e):
        """Zoom on Ctrl-Mousewheel.

        Args:
            e: The QWheelEvent.

        Return:
            True if the event should be filtered, False otherwise.
        """
        if self._ignore_wheel_event:
            # See https://github.com/qutebrowser/qutebrowser/issues/395
            self._ignore_wheel_event = False
            return True

        # Don't allow scrolling while hinting
        mode = modeman.instance(self._tab.win_id).mode
        if mode == usertypes.KeyMode.hint:
            return True

        elif e.modifiers() & Qt.ControlModifier:
            if mode == usertypes.KeyMode.passthrough:
                return False

            divider = config.val.zoom.mouse_divider
            if divider == 0:
                # Disable mouse zooming
                return True

            factor = self._tab.zoom.factor() + (e.angleDelta().y() / divider)
            if factor < 0:
                return True

            perc = int(100 * factor)
            message.info(f"Zoom level: {perc}%", replace='zoom-level')
            self._tab.zoom.set_factor(factor)
            return True

        return False
Beispiel #30
0
    def on_current_changed(self, idx):
        """Set last-focused-tab and leave hinting mode when focus changed."""
        mode_on_change = config.val.tabs.mode_on_change
        modes_to_save = [usertypes.KeyMode.insert,
                         usertypes.KeyMode.passthrough]
        if idx == -1 or self.shutting_down:
            # closing the last tab (before quitting) or shutting down
            return
        tab = self.widget(idx)
        if tab is None:
            log.webview.debug("on_current_changed got called with invalid "
                              "index {}".format(idx))
            return
        if self._now_focused is not None and mode_on_change == 'restore':
            current_mode = modeman.instance(self._win_id).mode
            if current_mode not in modes_to_save:
                current_mode = usertypes.KeyMode.normal
            self._now_focused.data.input_mode = current_mode

        log.modes.debug("Current tab changed, focusing {!r}".format(tab))
        tab.setFocus()

        modes_to_leave = [usertypes.KeyMode.hint, usertypes.KeyMode.caret]
        if mode_on_change != 'persist':
            modes_to_leave += modes_to_save
        for mode in modes_to_leave:
            modeman.leave(self._win_id, mode, 'tab changed', maybe=True)
        if mode_on_change == 'restore':
            modeman.enter(self._win_id, tab.data.input_mode,
                          'restore input mode for tab')
        if self._now_focused is not None:
            objreg.register('last-focused-tab', self._now_focused, update=True,
                            scope='window', window=self._win_id)
        self._now_focused = tab
        self.current_tab_changed.emit(tab)
        QTimer.singleShot(0, self._update_window_title)
        self._tab_insert_idx_left = self.currentIndex()
        self._tab_insert_idx_right = self.currentIndex() + 1
Beispiel #31
0
    def on_current_changed(self, idx):
        """Set last-focused-tab and leave hinting mode when focus changed."""
        mode_on_change = config.val.tabs.mode_on_change
        if idx == -1 or self.shutting_down:
            # closing the last tab (before quitting) or shutting down
            return
        tab = self.widget.widget(idx)
        if tab is None:
            log.webview.debug("on_current_changed got called with invalid "
                              "index {}".format(idx))
            return

        log.modes.debug("Current tab changed, focusing {!r}".format(tab))
        tab.setFocus()

        modes_to_leave = [usertypes.KeyMode.hint, usertypes.KeyMode.caret]

        mm_instance = modeman.instance(self._win_id)
        current_mode = mm_instance.mode
        log.modes.debug("Mode before tab change: {} (mode_on_change = {})"
                        .format(current_mode.name, mode_on_change))
        if mode_on_change == 'normal':
            modes_to_leave += modeman.INPUT_MODES
        for mode in modes_to_leave:
            modeman.leave(self._win_id, mode, 'tab changed', maybe=True)
        if (mode_on_change == 'restore' and
                current_mode not in modeman.PROMPT_MODES):
            modeman.enter(self._win_id, tab.data.input_mode, 'restore')
        if self._now_focused is not None:
            objreg.register('last-focused-tab', self._now_focused, update=True,
                            scope='window', window=self._win_id)
        log.modes.debug("Mode after tab change: {} (mode_on_change = {})"
                        .format(current_mode.name, mode_on_change))
        self._now_focused = tab
        self.current_tab_changed.emit(tab)
        QTimer.singleShot(0, self._update_window_title)
        self._tab_insert_idx_left = self.widget.currentIndex()
        self._tab_insert_idx_right = self.widget.currentIndex() + 1
Beispiel #32
0
    def tabopen(
        self,
        url: QUrl = None,
        background: bool = None,
        related: bool = True,
        idx: int = None,
    ) -> browsertab.AbstractTab:
        """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.

        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:
            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)

        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
Beispiel #33
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_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))

        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.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.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.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.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
Beispiel #34
0
    def _connect_signals(self):
        """Connect all mainwindow signals."""
        mode_manager = modeman.instance(self.win_id)

        # misc
        self.tabbed_browser.close_window.connect(self.close)
        mode_manager.entered.connect(hints.on_mode_entered)

        # status bar
        mode_manager.hintmanager.set_text.connect(self.status.set_text)
        mode_manager.entered.connect(self.status.on_mode_entered)
        mode_manager.left.connect(self.status.on_mode_left)
        mode_manager.left.connect(self.status.cmd.on_mode_left)
        mode_manager.left.connect(message.global_bridge.mode_left)

        # commands
        mode_manager.keystring_updated.connect(
            self.status.keystring.on_keystring_updated)
        self.status.cmd.got_cmd[str].connect(self._commandrunner.run_safely)
        self.status.cmd.got_cmd[str,
                                int].connect(self._commandrunner.run_safely)
        self.status.cmd.returnPressed.connect(
            self.tabbed_browser.on_cmd_return_pressed)
        self.status.cmd.got_search.connect(self._command_dispatcher.search)

        # key hint popup
        mode_manager.keystring_updated.connect(self._keyhint.update_keyhint)

        # messages
        message.global_bridge.show_message.connect(
            self._messageview.show_message)
        message.global_bridge.flush()
        message.global_bridge.clear_messages.connect(
            self._messageview.clear_messages)

        # statusbar
        self.tabbed_browser.current_tab_changed.connect(
            self.status.on_tab_changed)

        self.tabbed_browser.cur_progress.connect(
            self.status.prog.on_load_progress)
        self.tabbed_browser.cur_load_started.connect(
            self.status.prog.on_load_started)

        self.tabbed_browser.cur_scroll_perc_changed.connect(
            self.status.percentage.set_perc)
        self.tabbed_browser.widget.tab_index_changed.connect(
            self.status.tabindex.on_tab_index_changed)

        self.tabbed_browser.cur_url_changed.connect(self.status.url.set_url)
        self.tabbed_browser.cur_url_changed.connect(
            functools.partial(self.status.backforward.on_tab_cur_url_changed,
                              tabs=self.tabbed_browser))
        self.tabbed_browser.cur_link_hovered.connect(
            self.status.url.set_hover_url)
        self.tabbed_browser.cur_load_status_changed.connect(
            self.status.url.on_load_status_changed)

        self.tabbed_browser.cur_caret_selection_toggled.connect(
            self.status.on_caret_selection_toggled)

        self.tabbed_browser.cur_fullscreen_requested.connect(
            self._on_fullscreen_requested)
        self.tabbed_browser.cur_fullscreen_requested.connect(
            self.status.maybe_hide)

        # downloadview
        self.tabbed_browser.cur_fullscreen_requested.connect(
            self._downloadview.on_fullscreen_requested)

        # command input / completion
        mode_manager.entered.connect(self.tabbed_browser.on_mode_entered)
        mode_manager.left.connect(self.tabbed_browser.on_mode_left)
        self.status.cmd.clear_completion_selection.connect(
            self._completion.on_clear_completion_selection)
        self.status.cmd.hide_completion.connect(self._completion.hide)
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 = modeman.instance(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)

        try:
            baseurl = tabbed_browser.current_url()
        except qtutils.QtValueError:
            raise cmdutils.CommandError("No URL set for this page yet!")

        self._context = HintContext(
            tab=tab,
            target=target,
            rapid=rapid,
            hint_mode=self._get_hint_mode(mode),
            add_history=add_history,
            first=first,
            baseurl=baseurl,
            args=list(args),
            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 _get_keyparser(self,
                    mode: usertypes.KeyMode) -> basekeyparser.BaseKeyParser:
     mode_manager = modeman.instance(self._win_id)
     return mode_manager.parsers[mode]