def _start_cb(self, elems): """Initialize the elements and labels based on the context set.""" filterfunc = webelem.FILTERS.get(self._context.group, lambda e: True) elems = [e for e in elems if filterfunc(e)] if not elems: raise cmdexc.CommandError("No elements found.") strings = self._hint_strings(elems) log.hints.debug("hints: {}".format(', '.join(strings))) for e, string in zip(elems, strings): label = self._draw_label(e, string) elem = ElemTuple(e, label) self._context.all_elems.append(elem) self._context.elems[string] = elem keyparsers = objreg.get('keyparsers', scope='window', window=self._win_id) keyparser = keyparsers[usertypes.KeyMode.hint] keyparser.update_bindings(strings) self._context.tab.contents_size_changed.connect( self.on_contents_size_changed) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) message_bridge.set_text(self._get_text()) modeman.enter(self._win_id, usertypes.KeyMode.hint, 'HintManager.start')
def _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 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') if self._context.first: self._fire(strings[0]) return # to make auto_follow == 'always' work self._handle_auto_follow()
def _on_clicked(self) -> None: """Enter insert mode if a docked inspector was clicked.""" if self._position != Position.window: modeman.enter(self._win_id, usertypes.KeyMode.insert, reason='Inspector clicked', only_if_normal=True)
def _auto_insert_mode_cb(elem): """Called from JS after finding the focused element.""" if elem is None: log.webview.debug("No focused element!") return if elem.is_editable(): modeman.enter(self.win_id, usertypes.KeyMode.insert, "load finished", only_if_normal=True)
def on_load_finished(self): """Handle auto-insert-mode after loading finished. We don't take loadFinished's ok argument here as it always seems to be true when the QWebPage has an ErrorPageExtension implemented. See https://github.com/The-Compiler/qutebrowser/issues/84 """ ok = not self.page().error_occured if ok and not self._has_ssl_errors: self._set_load_status(LoadStatus.success) elif ok: self._set_load_status(LoadStatus.warn) else: self._set_load_status(LoadStatus.error) if not config.get('input', 'auto-insert-mode'): return mode_manager = objreg.get('mode-manager', scope='window', window=self._win_id) cur_mode = mode_manager.mode if cur_mode == usertypes.KeyMode.insert or not ok: return frame = self.page().currentFrame() try: elem = webelem.WebElementWrapper(frame.findFirstElement(':focus')) except webelem.IsNullError: log.webview.debug("Focused element is null!") return log.modes.debug("focus element: {}".format(repr(elem))) if elem.is_editable(): modeman.enter(self._win_id, usertypes.KeyMode.insert, 'load finished', only_if_normal=True)
def eventFilter(self, _obj: QObject, event: QEvent) -> bool: """Enter insert mode if the inspector is clicked.""" if event.type() == QEvent.MouseButtonPress: modeman.enter(self._win_id, usertypes.KeyMode.insert, reason='Inspector clicked') return False
def click(self, click_target, *, force_event=False): """Simulate a click on the element. Args: click_target: A usertypes.ClickTarget member, what kind of click to simulate. force_event: Force generating a fake mouse event. """ if force_event: self._click_fake_event(click_target) return href_tags = ['a', 'area', 'link'] if click_target == usertypes.ClickTarget.normal: if self.tag_name() in href_tags: log.webelem.debug("Clicking via JS click()") self._click_js(click_target) elif self.is_editable(strict=True): log.webelem.debug("Clicking via JS focus()") self._click_editable() modeman.enter(self._tab.win_id, usertypes.KeyMode.insert, 'clicking input') else: self._click_fake_event(click_target) elif click_target in [ usertypes.ClickTarget.tab, usertypes.ClickTarget.tab_bg, usertypes.ClickTarget.window ]: if self.tag_name() in href_tags: self._click_href(click_target) else: self._click_fake_event(click_target) else: raise ValueError("Unknown ClickTarget {}".format(click_target))
def _start_cb(self, elems): """Initialize the elements and labels based on the context set.""" if self._context is None: log.hints.debug("In _start_cb without context!") return if elems is None: message.error("There was an error while getting hint elements") return if not elems: message.error("No elements found.") return strings = self._hint_strings(elems) log.hints.debug("hints: {}".format(', '.join(strings))) for elem, string in zip(elems, strings): label = HintLabel(elem, self._context) label.update_text('', string) self._context.all_labels.append(label) self._context.labels[string] = label keyparsers = objreg.get('keyparsers', scope='window', window=self._win_id) keyparser = keyparsers[usertypes.KeyMode.hint] keyparser.update_bindings(strings) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) message_bridge.set_text(self._get_text()) modeman.enter(self._win_id, usertypes.KeyMode.hint, 'HintManager.start') # to make auto_follow == 'always' work self._handle_auto_follow()
def _restore_ctx(self, ctx): """Restore state from a PromptContext. Args: ctx: A PromptContext previously saved by _get_ctx, or None. Return: True if a context was restored, False otherwise. """ log.statusbar.debug("Restoring context {}".format(ctx)) if ctx is None: self.hide_prompt.emit() self._busy = False return False self._question = ctx.question prompt = objreg.get('prompt', scope='window', window=self._win_id) prompt.txt.setText(ctx.text) prompt.lineedit.setText(ctx.input_text) prompt.lineedit.setEchoMode(ctx.echo_mode) prompt.lineedit.setVisible(ctx.input_visible) self.show_prompt.emit() mode = self.KEY_MODES[ctx.question.mode] ctx.question.aborted.connect( lambda: modeman.maybe_leave(self._win_id, mode, 'aborted')) modeman.enter(self._win_id, mode, 'question asked') return True
def on_current_changed(self, idx): """Set last-focused-tab and leave hinting mode when focus changed.""" if idx == -1 or self._shutting_down: # closing the last tab (before quitting) or shutting down return tab = self.widget(idx) log.modes.debug("Current tab changed, focusing {!r}".format(tab)) tab.setFocus() for mode in (usertypes.KeyMode.hint, usertypes.KeyMode.insert, usertypes.KeyMode.caret, usertypes.KeyMode.passthrough): modeman.maybe_leave(self._win_id, mode, 'tab changed') if self._now_focused is not None: objreg.register('last-focused-tab', self._now_focused, update=True, scope='window', window=self._win_id) ai = False for r in pt_masks: if re.match(r, tab.url().host()) is not None: ai = True break if ai: modeman.enter(self._win_id, usertypes.KeyMode.passthrough, 'load finished', only_if_normal=True) 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
def _start_cb(self, elems): """Initialize the elements and labels based on the context set.""" filterfunc = webelem.FILTERS.get(self._context.group, lambda e: True) elems = [e for e in elems if filterfunc(e)] if not elems: message.error(self._win_id, "No elements found.", immediately=True) return strings = self._hint_strings(elems) log.hints.debug("hints: {}".format(', '.join(strings))) for elem, string in zip(elems, strings): label = HintLabel(elem, self._context) label.update_text('', string) self._context.all_labels.append(label) self._context.labels[string] = label keyparsers = objreg.get('keyparsers', scope='window', window=self._win_id) keyparser = keyparsers[usertypes.KeyMode.hint] keyparser.update_bindings(strings) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) message_bridge.set_text(self._get_text()) modeman.enter(self._win_id, usertypes.KeyMode.hint, 'HintManager.start') # to make auto-follow == 'always' work self._handle_auto_follow()
def _handle_auto_insert_mode(self, ok): """Handle auto-insert-mode after loading finished.""" ai = False for mode in (usertypes.KeyMode.hint, usertypes.KeyMode.insert, usertypes.KeyMode.caret, usertypes.KeyMode.passthrough): modeman.maybe_leave(self.win_id, mode, 'load finished') for r in pt_masks: if re.match(r, self.cur_url.host()) is not None: print(re.match(r, self.cur_url.host()), re.match(r, self.cur_url.host()).groups()) ai = True break if ai: modeman.enter(self.win_id, usertypes.KeyMode.passthrough, 'load finished', only_if_normal=True) return if not config.get('input', 'auto-insert-mode'): return mode_manager = objreg.get('mode-manager', scope='window', window=self.win_id) cur_mode = mode_manager.mode if cur_mode == usertypes.KeyMode.insert or not ok: return frame = self.page().currentFrame() try: elem = webelem.WebElementWrapper(frame.findFirstElement(':focus')) except webelem.IsNullError: log.webview.debug("Focused element is null!") log.modes.debug("focus element: {}".format(repr(elem))) print("bazqux" in self.cur_url.host(), self.cur_url.host()) if elem.is_editable() or rss: modeman.enter(self.win_id, usertypes.KeyMode.insert, 'load finished', only_if_normal=True)
def _start_cb(self, elems): """Initialize the elements and labels based on the context set.""" if elems is None: message.error("There was an error while getting hint elements") return filterfunc = webelem.FILTERS.get(self._context.group, lambda e: True) elems = [e for e in elems if filterfunc(e)] if not elems: message.error("No elements found.") return strings = self._hint_strings(elems) log.hints.debug("hints: {}".format(', '.join(strings))) for elem, string in zip(elems, strings): label = HintLabel(elem, self._context) label.update_text('', string) self._context.all_labels.append(label) self._context.labels[string] = label keyparsers = objreg.get('keyparsers', scope='window', window=self._win_id) keyparser = keyparsers[usertypes.KeyMode.hint] keyparser.update_bindings(strings) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) message_bridge.set_text(self._get_text()) modeman.enter(self._win_id, usertypes.KeyMode.hint, 'HintManager.start') # to make auto-follow == 'always' work self._handle_auto_follow()
def click(self, click_target, *, force_event=False): """Simulate a click on the element. Args: click_target: A usertypes.ClickTarget member, what kind of click to simulate. force_event: Force generating a fake mouse event. """ log.webelem.debug("Clicking {!r} with click_target {}, force_event {}" .format(self, click_target, force_event)) if force_event: self._click_fake_event(click_target) return if click_target == usertypes.ClickTarget.normal: if self.is_link(): log.webelem.debug("Clicking via JS click()") self._click_js(click_target) elif self.is_editable(strict=True): log.webelem.debug("Clicking via JS focus()") self._click_editable(click_target) modeman.enter(self._tab.win_id, usertypes.KeyMode.insert, 'clicking input') else: self._click_fake_event(click_target) elif click_target in [usertypes.ClickTarget.tab, usertypes.ClickTarget.tab_bg, usertypes.ClickTarget.window]: if self.is_link(): self._click_href(click_target) else: self._click_fake_event(click_target) else: raise ValueError("Unknown ClickTarget {}".format(click_target))
def _auto_insert_mode_cb(elem: 'webelem.AbstractWebElement') -> None: """Called from JS after finding the focused element.""" if elem is None: log.webview.debug("No focused element!") return if elem.is_editable(): modeman.enter(self._tab.win_id, usertypes.KeyMode.insert, 'load finished', only_if_normal=True)
def _start_cb(self, elems: _ElemsType) -> None: """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 not elems: message.error("No elements found.") return # Because _start_cb is called asynchronously, it's possible that the # user switched to another tab or closed the tab/window. In that case # we should not start hinting. tabbed_browser = objreg.get('tabbed-browser', default=None, scope='window', window=self._win_id) tab = tabbed_browser.widget.currentWidget() if tab.tab_id != self._context.tab.tab_id: log.hints.debug( "Current tab changed ({} -> {}) before _start_cb is run.". format(self._context.tab.tab_id, tab.tab_id)) return unique, urls = self._get_unique_url_elems_collection(elems) strings = self._hint_strings(unique) log.hints.debug("hints: {}".format(', '.join(strings))) #urls = dict(map(lambda e: (e[1][1], e[1]), urls.items())) strings = list( map( lambda e: strings[unique.index(e)] if e in unique else strings[unique.index( [item[0] for item in urls.values() if e in item][0])], elems)) 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 keyparser = self._get_keyparser(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') if self._context.first: self._fire(strings[0]) return # to make auto_follow == 'always' work self._handle_auto_follow()
def ask_question(self, question, blocking): """Dispkay a question in the statusbar. Args: question: The Question object to ask. blocking: If True, this function blocks and returns the result. Return: The answer of the user when blocking=True. None if blocking=False. """ log.statusbar.debug("Asking question {}, blocking {}, loops {}, queue " "{}".format(question, blocking, self._loops, self._queue)) if self._shutting_down: # If we're currently shutting down we have to ignore this question # to avoid segfaults - see # https://github.com/The-Compiler/qutebrowser/issues/95 log.statusbar.debug("Ignoring question because we're shutting " "down.") question.abort() return None if self._busy and not blocking: # We got an async question, but we're already busy with one, so we # just queue it up for later. log.statusbar.debug("Adding {} to queue.".format(question)) self._queue.append(question) return if blocking: # If we're blocking we save the old state on the stack, so we can # restore it after exec, if exec gets called multiple times. context = self._get_ctx() self._question = question self._display_question() mode = self.KEY_MODES[self._question.mode] question.aborted.connect( lambda: modeman.maybe_leave(self._win_id, mode, 'aborted')) modeman.enter(self._win_id, mode, 'question asked') if blocking: loop = qtutils.EventLoop() self._loops.append(loop) loop.destroyed.connect(lambda: self._loops.remove(loop)) question.completed.connect(loop.quit) question.completed.connect(loop.deleteLater) loop.exec_() if not self._restore_ctx(context): # Nothing left to restore, so we can go back to popping async # questions. if self._queue: self._pop_later() return self._question.answer else: question.completed.connect(self._pop_later)
def ask_question(self, question, blocking): """Display a question in the statusbar. Args: question: The Question object to ask. blocking: If True, this function blocks and returns the result. Return: The answer of the user when blocking=True. None if blocking=False. """ log.statusbar.debug("Asking question {}, blocking {}, loops {}, queue " "{}".format(question, blocking, self._loops, self._queue)) if self._shutting_down: # If we're currently shutting down we have to ignore this question # to avoid segfaults - see # https://github.com/The-Compiler/qutebrowser/issues/95 log.statusbar.debug("Ignoring question because we're shutting " "down.") question.abort() return None if self._busy and not blocking: # We got an async question, but we're already busy with one, so we # just queue it up for later. log.statusbar.debug("Adding {} to queue.".format(question)) self._queue.append(question) return if blocking: # If we're blocking we save the old state on the stack, so we can # restore it after exec, if exec gets called multiple times. context = self._get_ctx() self._question = question self._display_question() mode = self.KEY_MODES[self._question.mode] question.aborted.connect( lambda: modeman.maybe_leave(self._win_id, mode, 'aborted')) modeman.enter(self._win_id, mode, 'question asked') if blocking: loop = qtutils.EventLoop() self._loops.append(loop) loop.destroyed.connect(lambda: self._loops.remove(loop)) question.completed.connect(loop.quit) question.completed.connect(loop.deleteLater) loop.exec_() if not self._restore_ctx(context): # Nothing left to restore, so we can go back to popping async # questions. if self._queue: self._pop_later() return self._question.answer else: question.completed.connect(self._pop_later)
def start(self, group=webelem.Group.all, target=Target.normal, *args: {'nargs': '*'}): """Start hinting. Args: group: The hinting mode to use. - `all`: All clickable elements. - `links`: Only links. - `images`: Only images. target: What to do with the selected element. - `normal`: Open the link in the current tab. - `tab`: Open the link in a new tab. - `tab-bg`: Open the link in a new background tab. - `yank`: Yank the link to the clipboard. - `yank-primary`: Yank the link to the primary selection. - `fill`: Fill the commandline with the command given as argument. - `rapid`: Open the link in a new tab and stay in hinting mode. - `download`: Download the link. - `userscript`: Call an userscript with `$QUTE_URL` set to the link. - `spawn`: Spawn a command. *args: Arguments for spawn/userscript/fill. - With `spawn`: The executable and arguments to spawn. `{hint-url}` will get replaced by the selected URL. - With `userscript`: The userscript to execute. - With `fill`: The command to fill the statusbar with. `{hint-url}` will get replaced by the selected URL. """ tabbed_browser = objreg.get('tabbed-browser') widget = tabbed_browser.currentWidget() if widget is None: raise cmdexc.CommandError("No WebView available yet!") mainframe = widget.page().mainFrame() if mainframe is None: raise cmdexc.CommandError("No frame focused!") self._check_args(target, *args) self._context = HintContext() self._context.target = target self._context.baseurl = tabbed_browser.current_url() self._context.frames = webelem.get_child_frames(mainframe) self._context.args = args self._init_elements(mainframe, group) objreg.get('message-bridge').set_text(self.HINT_TEXTS[target]) self._connect_frame_signals() try: modeman.enter(usertypes.KeyMode.hint, 'HintManager.start') except modeman.ModeLockedError: self._cleanup()
def ask_question(self, question, blocking): """Dispkay a question in the statusbar. Args: question: The Question object to ask. blocking: If True, this function blocks and returns the result. Return: The answer of the user when blocking=True. None if blocking=False. """ log.statusbar.debug("Asking question {}, blocking {}, loops {}, queue " "{}".format(question, blocking, self._loops, self._queue)) if self._busy and not blocking: # We got an async question, but we're already busy with one, so we # just queue it up for later. log.statusbar.debug("Adding {} to queue.".format(question)) self._queue.append(question) return if blocking: # If we're blocking we save the old state on the stack, so we can # restore it after exec, if exec gets called multiple times. context = self._get_ctx() self._question = question mode = self._display_question() question.aborted.connect( lambda: modeman.maybe_leave(self._win_id, mode, 'aborted')) mode_manager = objreg.get('mode-manager', scope='window', window=self._win_id) try: modeman.enter(self._win_id, mode, 'question asked', override=True) except modeman.ModeLockedError: if mode_manager.mode() != usertypes.KeyMode.prompt: question.abort() return None mode_manager.locked = True if blocking: loop = qtutils.EventLoop() self._loops.append(loop) loop.destroyed.connect(lambda: self._loops.remove(loop)) question.completed.connect(loop.quit) question.completed.connect(loop.deleteLater) loop.exec_() if not self._restore_ctx(context): # Nothing left to restore, so we can go back to popping async # questions. if self._queue: self._pop_later() return self._question.answer else: question.completed.connect(self._pop_later)
def set_cmd_text(self, text: str) -> None: """Preset the statusbar to some text. Args: text: The text to set as string. """ self.setText(text) log.modes.debug("Setting command text, focusing {!r}".format(self)) modeman.enter(self._win_id, usertypes.KeyMode.command, 'cmd focus') self.setFocus() self.show_cmd.emit()
def set_cmd_text(self, text): """Preset the statusbar to some text. Args: text: The text to set as string. """ self.setText(text) log.modes.debug("Setting command text, focusing {!r}".format(self)) modeman.enter(self._win_id, usertypes.KeyMode.command, 'cmd focus') self.setFocus() self.show_cmd.emit()
def ask_question(self, question, blocking): """Dispkay a question in the statusbar. Args: question: The Question object to ask. blocking: If True, this function blocks and returns the result. Return: The answer of the user when blocking=True. None if blocking=False. """ log.statusbar.debug("Asking question {}, blocking {}, loops {}, queue " "{}".format(question, blocking, self._loops, self._queue)) if self._busy and not blocking: # We got an async question, but we're already busy with one, so we # just queue it up for later. log.statusbar.debug("Adding {} to queue.".format(question)) self._queue.append(question) return if blocking: # If we're blocking we save the old state on the stack, so we can # restore it after exec, if exec gets called multiple times. context = self._get_ctx() self._question = question mode = self._display_question() question.aborted.connect(lambda: modeman.maybe_leave(mode, 'aborted')) mode_manager = objreg.get('mode-manager') try: modeman.enter(mode, 'question asked', override=True) except modeman.ModeLockedError: if mode_manager.mode() != usertypes.KeyMode.prompt: question.abort() return None mode_manager.locked = True if blocking: loop = qtutils.EventLoop() self._loops.append(loop) loop.destroyed.connect(lambda: self._loops.remove(loop)) question.completed.connect(loop.quit) question.completed.connect(loop.deleteLater) loop.exec_() if not self._restore_ctx(context): # Nothing left to restore, so we can go back to popping async # questions. if self._queue: self._pop_later() return self._question.answer else: question.completed.connect(self._pop_later)
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 not elems: message.error("No elements found.") return # Because _start_cb is called asynchronously, it's possible that the # user switched to another tab or closed the tab/window. In that case # we should not start hinting. tabbed_browser = objreg.get('tabbed-browser', default=None, scope='window', window=self._win_id) tab = tabbed_browser.widget.currentWidget() if tab.tab_id != self._tab_id: log.hints.debug( "Current tab changed ({} -> {}) before _start_cb is run.". format(self._tab_id, tab.tab_id)) 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') if self._context.first: self._fire(strings[0]) return # to make auto_follow == 'always' work self._handle_auto_follow()
def _on_show_prompts(self, question): """Show a prompt for the given question. Args: question: A Question object or None. """ item = self._layout.takeAt(0) if item is not None: widget = item.widget() log.prompt.debug("Deleting old prompt {}".format(widget)) widget.hide() widget.deleteLater() if question is None: log.prompt.debug("No prompts left, hiding prompt container.") self._prompt = None self.hide() return classes = { usertypes.PromptMode.yesno: YesNoPrompt, usertypes.PromptMode.text: LineEditPrompt, usertypes.PromptMode.user_pwd: AuthenticationPrompt, usertypes.PromptMode.download: DownloadFilenamePrompt, usertypes.PromptMode.alert: AlertPrompt, } klass = classes[question.mode] prompt = klass(question) log.prompt.debug("Displaying prompt {}".format(prompt)) self._prompt = prompt if not question.interrupted: # If this question was interrupted, we already connected the signal def on_aborted(): try: modeman.leave(self._win_id, prompt.KEY_MODE, 'aborted', maybe=True) except objreg.RegistryUnavailableError: # window was deleted: ignore pass question.aborted.connect(on_aborted) modeman.enter(self._win_id, prompt.KEY_MODE, 'question asked') self.setSizePolicy(prompt.sizePolicy()) self._layout.addWidget(prompt) prompt.show() self.show() prompt.setFocus() self.update_geometry.emit()
def mouserelease_insertmode_cb(elem): """Callback which gets called from JS.""" if elem is None: log.mouse.debug("Element vanished!") return if elem.is_editable(): log.mouse.debug("Clicked editable element (delayed)!") modeman.enter(self._tab.win_id, usertypes.KeyMode.insert, 'click-delayed', only_if_normal=True) else: log.mouse.debug("Clicked non-editable element (delayed)!") if config.get('input', 'auto-leave-insert-mode'): modeman.leave(self._tab.win_id, usertypes.KeyMode.insert, 'click-delayed', maybe=True)
def mouserelease_insertmode_cb(elem): """Callback which gets called from JS.""" if elem is None: log.mouse.debug("Element vanished!") return if elem.is_editable(): log.mouse.debug("Clicked editable element (delayed)!") modeman.enter(self._tab.win_id, usertypes.KeyMode.insert, 'click-delayed', only_if_normal=True) else: log.mouse.debug("Clicked non-editable element (delayed)!") if config.val.input.insert_mode.auto_leave: modeman.leave(self._tab.win_id, usertypes.KeyMode.insert, 'click-delayed', maybe=True)
def _mousepress_insertmode(self, e): """Switch to insert mode when an editable element was clicked. Args: e: The QMouseEvent. """ pos = e.pos() frame = self.page().frameAt(pos) if frame is None: # This happens when we click inside the webview, but not actually # on the QWebPage - for example when clicking the scrollbar # sometimes. log.mouse.debug("Clicked at {} but frame is None!".format(pos)) return # You'd think we have to subtract frame.geometry().topLeft() from the # position, but it seems QWebFrame::hitTestContent wants a position # relative to the QWebView, not to the frame. This makes no sense to # me, but it works this way. hitresult = frame.hitTestContent(pos) if hitresult.isNull(): # For some reason, the whole hit result can be null sometimes (e.g. # on doodle menu links). If this is the case, we schedule a check # later (in mouseReleaseEvent) which uses webelem.focus_elem. log.mouse.debug("Hitresult is null!") self._check_insertmode = True return try: elem = webelem.WebElementWrapper(hitresult.element()) except webelem.IsNullError: # For some reason, the hit result element can be a null element # sometimes (e.g. when clicking the timetable fields on # http://www.sbb.ch/ ). If this is the case, we schedule a check # later (in mouseReleaseEvent) which uses webelem.focus_elem. log.mouse.debug("Hitresult element is null!") self._check_insertmode = True return if ((hitresult.isContentEditable() and elem.is_writable()) or elem.is_editable()): log.mouse.debug("Clicked editable element!") modeman.enter(self.win_id, usertypes.KeyMode.insert, 'click', only_if_normal=True) else: log.mouse.debug("Clicked non-editable element!") if config.get('input', 'auto-leave-insert-mode'): modeman.maybe_leave(self.win_id, usertypes.KeyMode.insert, 'click')
def _mode_override(self, url: QUrl) -> None: """Override mode if url matches pattern. Args: url: The QUrl to match for """ if not url.isValid(): return mode = config.instance.get('input.mode_override', url=url) if mode: log.modes.debug(f"Mode change to {mode} triggered for url {url}") modeman.enter( self._win_id, usertypes.KeyMode[mode], reason='mode_override', )
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 not elems: message.error("No elements found.") return # Because _start_cb is called asynchronously, it's possible that the # user switched to another tab or closed the tab/window. In that case # we should not start hinting. tabbed_browser = objreg.get('tabbed-browser', default=None, scope='window', window=self._win_id) tab = tabbed_browser.widget.currentWidget() if tab.tab_id != self._tab_id: log.hints.debug( "Current tab changed ({} -> {}) before _start_cb is run." .format(self._tab_id, tab.tab_id)) 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') if self._context.first: self._fire(strings[0]) return # to make auto_follow == 'always' work self._handle_auto_follow()
def _mousepress_insertmode(self, e): """Switch to insert mode when an editable element was clicked. Args: e: The QMouseEvent. """ pos = e.pos() frame = self.page().frameAt(pos) if frame is None: # This happens when we click inside the webview, but not actually # on the QWebPage - for example when clicking the scrollbar # sometimes. log.mouse.debug("Clicked at {} but frame is None!".format(pos)) return # You'd think we have to subtract frame.geometry().topLeft() from the # position, but it seems QWebFrame::hitTestContent wants a position # relative to the QWebView, not to the frame. This makes no sense to # me, but it works this way. hitresult = frame.hitTestContent(pos) if hitresult.isNull(): # For some reason, the whole hitresult can be null sometimes (e.g. # on doodle menu links). If this is the case, we schedule a check # later (in mouseReleaseEvent) which uses webelem.focus_elem. log.mouse.debug("Hitresult is null!") self._check_insertmode = True return try: elem = webelem.WebElementWrapper(hitresult.element()) except webelem.IsNullError: # For some reason, the hitresult element can be a null element # sometimes (e.g. when clicking the timetable fields on # http://www.sbb.ch/ ). If this is the case, we schedule a check # later (in mouseReleaseEvent) which uses webelem.focus_elem. log.mouse.debug("Hitresult element is null!") self._check_insertmode = True return if ((hitresult.isContentEditable() and elem.is_writable()) or elem.is_editable()): log.mouse.debug("Clicked editable element!") modeman.enter(self._win_id, usertypes.KeyMode.insert, 'click', only_if_normal=True) else: log.mouse.debug("Clicked non-editable element!") if config.get('input', 'auto-leave-insert-mode'): modeman.maybe_leave(self._win_id, usertypes.KeyMode.insert, 'click')
def _on_show_prompts(self, question): """Show a prompt for the given question. Args: question: A Question object or None. """ item = self._layout.takeAt(0) if item is not None: widget = item.widget() log.prompt.debug("Deleting old prompt {}".format(widget)) widget.hide() widget.deleteLater() if question is None: log.prompt.debug("No prompts left, hiding prompt container.") self._prompt = None self.hide() return classes = { usertypes.PromptMode.yesno: YesNoPrompt, usertypes.PromptMode.text: LineEditPrompt, usertypes.PromptMode.user_pwd: AuthenticationPrompt, usertypes.PromptMode.download: DownloadFilenamePrompt, usertypes.PromptMode.alert: AlertPrompt, } klass = classes[question.mode] prompt = klass(question) log.prompt.debug("Displaying prompt {}".format(prompt)) self._prompt = prompt if not question.interrupted: # If this question was interrupted, we already connected the signal question.aborted.connect( lambda: modeman.leave(self._win_id, prompt.KEY_MODE, 'aborted', maybe=True)) modeman.enter(self._win_id, prompt.KEY_MODE, 'question asked') self.setSizePolicy(prompt.sizePolicy()) self._layout.addWidget(prompt) prompt.show() self.show() prompt.setFocus() self.update_geometry.emit()
def _on_show_prompts(self, question): """Show a prompt for the given question. Args: question: A Question object or None. """ item = self._layout.takeAt(0) if item is not None: widget = item.widget() log.prompt.debug("Deleting old prompt {}".format(widget)) widget.hide() widget.deleteLater() if question is None: log.prompt.debug("No prompts left, hiding prompt container.") self._prompt = None self.hide() return classes = { usertypes.PromptMode.yesno: YesNoPrompt, usertypes.PromptMode.text: LineEditPrompt, usertypes.PromptMode.user_pwd: AuthenticationPrompt, usertypes.PromptMode.download: DownloadFilenamePrompt, usertypes.PromptMode.alert: AlertPrompt, } klass = classes[question.mode] prompt = typing.cast(_BasePrompt, klass(question)) log.prompt.debug("Displaying prompt {}".format(prompt)) self._prompt = prompt # If this question was interrupted, we already connected the signal if not question.interrupted: question.aborted.connect( functools.partial(self._on_aborted, prompt.KEY_MODE)) modeman.enter(self._win_id, prompt.KEY_MODE, 'question asked') self.setSizePolicy(prompt.sizePolicy()) self._layout.addWidget(prompt) prompt.show() self.show() prompt.setFocus() self.update_geometry.emit()
def mouserelease_insertmode(self): """If we have an insertmode check scheduled, handle it.""" if not self._check_insertmode: return self._check_insertmode = False try: elem = webelem.focus_elem(self.page().currentFrame()) except (webelem.IsNullError, RuntimeError): log.mouse.debug("Element/page vanished!") return if elem.is_editable(): log.mouse.debug("Clicked editable element (delayed)!") modeman.enter(self.win_id, usertypes.KeyMode.insert, 'click-delayed', only_if_normal=True) else: log.mouse.debug("Clicked non-editable element (delayed)!") if config.get('input', 'auto-leave-insert-mode'): modeman.maybe_leave(self.win_id, usertypes.KeyMode.insert, 'click-delayed')
def _mousepress_insertmode_cb(self, elem): """Check if the clicked element is editable.""" if elem is None: # Something didn't work out, let's find the focus element after # a mouse release. log.mouse.debug("Got None element, scheduling check on " "mouse release") self._check_insertmode_on_release = True return if elem.is_editable(): log.mouse.debug("Clicked editable element!") modeman.enter(self._tab.win_id, usertypes.KeyMode.insert, 'click', only_if_normal=True) else: log.mouse.debug("Clicked non-editable element!") if config.val.input.insert_mode.auto_leave: modeman.leave(self._tab.win_id, usertypes.KeyMode.insert, 'click', maybe=True)
def _mousepress_insertmode_cb(self, elem): """Check if the clicked element is editable.""" if elem is None: # Something didn't work out, let's find the focus element after # a mouse release. log.mouse.debug("Got None element, scheduling check on " "mouse release") self._check_insertmode_on_release = True return if elem.is_editable(): log.mouse.debug("Clicked editable element!") modeman.enter(self._tab.win_id, usertypes.KeyMode.insert, 'click', only_if_normal=True) else: log.mouse.debug("Clicked non-editable element!") if config.get('input', 'auto-leave-insert-mode'): modeman.leave(self._tab.win_id, usertypes.KeyMode.insert, 'click', maybe=True)
def mouserelease_insertmode(self): """If we have an insertmode check scheduled, handle it.""" if not self._check_insertmode: return self._check_insertmode = False try: elem = webelem.focus_elem(self.page().currentFrame()) except webelem.IsNullError: log.mouse.warning("Element vanished!") return if elem.is_editable(): log.mouse.debug("Clicked editable element (delayed)!") modeman.enter(self._win_id, usertypes.KeyMode.insert, 'click-delayed', only_if_normal=True) else: log.mouse.debug("Clicked non-editable element (delayed)!") if config.get('input', 'auto-leave-insert-mode'): modeman.maybe_leave(self._win_id, usertypes.KeyMode.insert, 'click-delayed')
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
def _handle_auto_insert_mode(self, ok): """Handle auto-insert-mode after loading finished.""" if not config.get('input', 'auto-insert-mode'): return mode_manager = objreg.get('mode-manager', scope='window', window=self.win_id) cur_mode = mode_manager.mode if cur_mode == usertypes.KeyMode.insert or not ok: return frame = self.page().currentFrame() try: elem = webelem.WebElementWrapper(frame.findFirstElement(':focus')) except webelem.IsNullError: log.webview.debug("Focused element is null!") return log.modes.debug("focus element: {}".format(repr(elem))) if elem.is_editable(): modeman.enter(self.win_id, usertypes.KeyMode.insert, 'load finished', only_if_normal=True)
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
def click(self, click_target: usertypes.ClickTarget, *, force_event: bool = False) -> None: """Simulate a click on the element. Args: click_target: A usertypes.ClickTarget member, what kind of click to simulate. force_event: Force generating a fake mouse event. """ log.webelem.debug( "Clicking {!r} with click_target {}, force_event {}".format( self, click_target, force_event)) if force_event: self._click_fake_event(click_target) return if click_target == usertypes.ClickTarget.normal: if self.is_link() and not self._requires_user_interaction(): log.webelem.debug("Clicking via JS click()") self._click_js(click_target) elif self.is_editable(strict=True): log.webelem.debug("Clicking via JS focus()") self._click_editable(click_target) if config.val.input.insert_mode.auto_enter: modeman.enter(self._tab.win_id, usertypes.KeyMode.insert, 'clicking input') else: self._click_fake_event(click_target) elif click_target in [ usertypes.ClickTarget.tab, usertypes.ClickTarget.tab_bg, usertypes.ClickTarget.window ]: if self.is_link(): self._click_href(click_target) else: self._click_fake_event(click_target) else: raise ValueError("Unknown ClickTarget {}".format(click_target))
def cycle_focus(self): """Cycle keyboard focus between the main/inspector widget.""" if self.count() == 1: raise inspector.Error("No inspector inside main window") assert self._main_idx is not None assert self._inspector_idx is not None main_widget = self.widget(self._main_idx) inspector_widget = self.widget(self._inspector_idx) if not inspector_widget.isVisible(): raise inspector.Error("No inspector inside main window") if main_widget.hasFocus(): inspector_widget.setFocus() modeman.enter(self._win_id, usertypes.KeyMode.insert, reason='Inspector focused', only_if_normal=True) elif inspector_widget.hasFocus(): main_widget.setFocus()
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
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
def start(self, group=webelem.Group.all, target=Target.normal, *args: {'nargs': '*'}): """Start hinting. Args: group: The hinting mode to use. - `all`: All clickable elements. - `links`: Only links. - `images`: Only images. target: What to do with the selected element. - `normal`: Open the link in the current tab. - `tab`: Open the link in a new 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. - `rapid`: Open the link in a new tab and stay in hinting mode. - `rapid-win`: Open the link in a new window and stay in hinting mode. - `download`: Download the link. - `userscript`: Call an userscript with `$QUTE_URL` set to the link. - `spawn`: Spawn a command. *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. - 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) widget = tabbed_browser.currentWidget() if widget is None: raise cmdexc.CommandError("No WebView available yet!") mainframe = widget.page().mainFrame() if mainframe is None: raise cmdexc.CommandError("No frame focused!") mode_manager = objreg.get('mode-manager', scope='window', window=self._win_id) if mode_manager.mode == usertypes.KeyMode.hint: raise cmdexc.CommandError("Already hinting!") self._check_args(target, *args) self._context = HintContext() self._context.target = target self._context.baseurl = tabbed_browser.current_url() self._context.frames = webelem.get_child_frames(mainframe) for frame in self._context.frames: # WORKAROUND for # https://github.com/The-Compiler/qutebrowser/issues/152 frame.destroyed.connect( functools.partial(self._context.destroyed_frames.append, id(frame))) self._context.args = args self._init_elements(mainframe, group) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) message_bridge.set_text(self.HINT_TEXTS[target]) self._connect_frame_signals() modeman.enter(self._win_id, usertypes.KeyMode.hint, 'HintManager.start')
def ifenter_passthrough(self,tab): """enter passthrough hook""" url = str(tab.url()) if any([x in url for x in ['localhost:888','overleaf.com']]): #if "localhost:888" in str(tab.url()): modeman.enter(self._win_id, usertypes.KeyMode.passthrough,reason='super cool hack', only_if_normal=False)
def __init__(self, args): """Constructor. Args: Argument namespace from argparse. """ self._quit_status = { 'crash': True, 'tabs': False, 'main': False, } self._shutting_down = False self._crashdlg = None self._crashlogfile = None self._commandrunner = None if args.debug: # We don't enable this earlier because some imports trigger # warnings (which are not our fault). warnings.simplefilter('default') qt_args = qtutils.get_args(args) log.init.debug("Qt arguments: {}, based on {}".format(qt_args, args)) super().__init__(qt_args) sys.excepthook = self._exception_hook self._args = args objreg.register('args', args) QTimer.singleShot(0, self._process_init_args) objreg.register('app', self) if self._args.version: print(version.version()) print() print() print(qutebrowser.__copyright__) print() print(version.GPL_BOILERPLATE.strip()) sys.exit(0) log.init.debug("Starting init...") self.setQuitOnLastWindowClosed(False) self.setOrganizationName("qutebrowser") self.setApplicationName("qutebrowser") self.setApplicationVersion(qutebrowser.__version__) utils.actute_warning() self._init_modules() log.init.debug("Initializing eventfilter...") mode_manager = objreg.get('mode-manager') self.installEventFilter(mode_manager) log.init.debug("Connecting signals...") self._connect_signals() modeman.enter(usertypes.KeyMode.normal, 'init') log.init.debug("Showing mainwindow...") if not args.nowindow: objreg.get('main-window').show() log.init.debug("Applying python hacks...") self._python_hacks() log.init.debug("Init done!") if self._crashdlg is not None: self._crashdlg.raise_()
def start(self, rapid=False, group=webelem.Group.all, target=Target.normal, *args: {'nargs': '*'}, win_id): """Start hinting. Args: rapid: Whether to do rapid hinting. This is only possible with targets `tab` (with background-tabs=true), `tab-bg`, `window`, `run`, `hover`, `userscript` and `spawn`. group: The hinting mode to use. - `all`: All clickable elements. - `links`: Only links. - `images`: Only images. target: What to do with the selected element. - `normal`: Open the link in the current tab. - `tab`: Open the link in a new tab (honoring the 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. *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) widget = tabbed_browser.currentWidget() if widget is None: raise cmdexc.CommandError("No WebView available yet!") mainframe = widget.page().mainFrame() if mainframe is None: raise cmdexc.CommandError("No frame focused!") 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 ]: pass elif (target == Target.tab and config.get('tabs', 'background-tabs')): pass else: name = target.name.replace('_', '-') raise cmdexc.CommandError("Rapid hinting makes no sense with " "target {}!".format(name)) self._check_args(target, *args) self._context = HintContext() self._context.target = target self._context.rapid = rapid try: self._context.baseurl = tabbed_browser.current_url() except qtutils.QtValueError: raise cmdexc.CommandError("No URL set for this page yet!") self._context.frames = webelem.get_child_frames(mainframe) for frame in self._context.frames: # WORKAROUND for # https://github.com/The-Compiler/qutebrowser/issues/152 frame.destroyed.connect( functools.partial(self._context.destroyed_frames.append, id(frame))) self._context.args = args self._context.mainframe = mainframe self._context.group = group self._init_elements() message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) message_bridge.set_text(self._get_text()) self._connect_frame_signals() modeman.enter(self._win_id, usertypes.KeyMode.hint, 'HintManager.start')
def start(self, rapid=False, group=webelem.Group.all, target=Target.normal, *args: {'nargs': '*'}, win_id): """Start hinting. Args: rapid: Whether to do rapid hinting. This is only possible with targets `tab` (with background-tabs=true), `tab-bg`, `window`, `run`, `hover`, `userscript` and `spawn`. group: The hinting mode to use. - `all`: All clickable elements. - `links`: Only links. - `images`: Only images. target: What to do with the selected element. - `normal`: Open the link in the current tab. - `tab`: Open the link in a new tab (honoring the 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. *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) widget = tabbed_browser.currentWidget() if widget is None: raise cmdexc.CommandError("No WebView available yet!") mainframe = widget.page().mainFrame() if mainframe is None: raise cmdexc.CommandError("No frame focused!") 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]: pass elif (target == Target.tab and config.get('tabs', 'background-tabs')): pass else: name = target.name.replace('_', '-') raise cmdexc.CommandError("Rapid hinting makes no sense with " "target {}!".format(name)) self._check_args(target, *args) self._context = HintContext() self._context.target = target self._context.rapid = rapid try: self._context.baseurl = tabbed_browser.current_url() except qtutils.QtValueError: raise cmdexc.CommandError("No URL set for this page yet!") self._context.frames = webelem.get_child_frames(mainframe) for frame in self._context.frames: # WORKAROUND for # https://github.com/The-Compiler/qutebrowser/issues/152 frame.destroyed.connect(functools.partial( self._context.destroyed_frames.append, id(frame))) self._context.args = args self._context.mainframe = mainframe self._context.group = group self._init_elements() message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) message_bridge.set_text(self._get_text()) self._connect_frame_signals() modeman.enter(self._win_id, usertypes.KeyMode.hint, 'HintManager.start')
def start(self, group=webelem.Group.all, target=Target.normal, *args: {'nargs': '*'}): """Start hinting. Args: group: The hinting mode to use. - `all`: All clickable elements. - `links`: Only links. - `images`: Only images. target: What to do with the selected element. - `normal`: Open the link in the current tab. - `tab`: Open the link in a new 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. - `rapid`: Open the link in a new tab and stay in hinting mode. - `rapid-win`: Open the link in a new window and stay in hinting mode. - `download`: Download the link. - `userscript`: Call an userscript with `$QUTE_URL` set to the link. - `spawn`: Spawn a command. *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. - 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) widget = tabbed_browser.currentWidget() if widget is None: raise cmdexc.CommandError("No WebView available yet!") mainframe = widget.page().mainFrame() if mainframe is None: raise cmdexc.CommandError("No frame focused!") mode_manager = objreg.get('mode-manager', scope='window', window=self._win_id) if mode_manager.mode == usertypes.KeyMode.hint: raise cmdexc.CommandError("Already hinting!") self._check_args(target, *args) self._context = HintContext() self._context.target = target self._context.baseurl = tabbed_browser.current_url() self._context.frames = webelem.get_child_frames(mainframe) for frame in self._context.frames: # WORKAROUND for # https://github.com/The-Compiler/qutebrowser/issues/152 frame.destroyed.connect(functools.partial( self._context.destroyed_frames.append, id(frame))) self._context.args = args self._init_elements(mainframe, group) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) message_bridge.set_text(self.HINT_TEXTS[target]) self._connect_frame_signals() modeman.enter(self._win_id, usertypes.KeyMode.hint, 'HintManager.start')