diff --git a/doc/qutebrowser.1.asciidoc b/doc/qutebrowser.1.asciidoc index 7761b790d..fa33b39d3 100644 --- a/doc/qutebrowser.1.asciidoc +++ b/doc/qutebrowser.1.asciidoc @@ -28,7 +28,7 @@ It was inspired by other browsers/addons like dwb and Vimperator/Pentadactyl. Commands to execute on startup. *'URL'*:: - URLs to open on startup. + URLs to open on startup (empty as a window separator). === optional arguments *-h*, *--help*:: diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index cc0bbe6c4..91d4cc7a3 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -63,10 +63,19 @@ class CommandDispatcher: def __repr__(self): return utils.get_repr(self) - def _tabbed_browser(self): - """Convienence method to get the right tabbed-browser.""" - return objreg.get('tabbed-browser', scope='window', - window=self._win_id) + def _tabbed_browser(self, window=False): + """Convienence method to get the right tabbed-browser. + + Args: + window: If True, open a new window. + """ + if window: + # We have to import this here to avoid a circular import. + from qutebrowser.widgets import mainwindow + win_id = mainwindow.create_window(True) + else: + win_id = self._win_id + return objreg.get('tabbed-browser', scope='window', window=win_id) def _count(self): """Convenience method to get the widget count.""" @@ -104,11 +113,7 @@ class CommandDispatcher: if sum(1 for e in (tab, background, window) if e) > 1: raise cmdexc.CommandError("Only one of -t/-b/-w can be given!") elif window: - # We have to import this here to avoid a circular import. - from qutebrowser.widgets import mainwindow - win_id = mainwindow.create_window(True) - tabbed_browser = objreg.get('tabbed-browser', scope='window', - window=win_id) + tabbed_browser = self._tabbed_browser(window=True) tabbed_browser.tabopen(url) elif tab: tabbed_browser.tabopen(url, background=False, explicit=True) @@ -302,26 +307,29 @@ class CommandDispatcher: diag.open(lambda: tab.print(diag.printer())) @cmdutils.register(instance='command-dispatcher', scope='window') - def tab_clone(self, bg=False): + def tab_clone(self, bg=False, window=False): """Duplicate the current tab. Args: bg: Open in a background tab. + window: Open in a new window. Return: The new QWebView. """ + if bg and window: + raise cmdexc.CommandError("Only one of -b/-w can be given!") curtab = self._current_widget() - tabbed_browser = self._tabbed_browser() + tabbed_browser = self._tabbed_browser(window) newtab = tabbed_browser.tabopen(background=bg, explicit=True) history = qtutils.serialize(curtab.history()) qtutils.deserialize(history, newtab.history()) return newtab - def _back_forward(self, tab, bg, count, forward): + def _back_forward(self, tab, bg, window, count, forward): """Helper function for :back/:forward.""" - if tab or bg: - widget = self.tab_clone(bg) + if tab or bg or window: + widget = self.tab_clone(bg, window) else: widget = self._current_widget() for _ in range(count): @@ -331,34 +339,38 @@ class CommandDispatcher: widget.go_back() @cmdutils.register(instance='command-dispatcher', scope='window') - def back(self, tab=False, bg=False, count=1): + def back(self, tab=False, bg=False, window=False, count=1): """Go back in the history of the current tab. Args: tab: Go back in a new tab. bg: Go back in a background tab. + window: Go back in a new window. count: How many pages to go back. """ - self._back_forward(tab, bg, count, forward=False) + self._back_forward(tab, bg, window, count, forward=False) @cmdutils.register(instance='command-dispatcher', scope='window') - def forward(self, tab=False, bg=False, count=1): + def forward(self, tab=False, bg=False, window=False, count=1): """Go forward in the history of the current tab. Args: tab: Go forward in a new tab. - bg: Go back in a background tab. + bg: Go forward in a background tab. + window: Go forward in a new window. count: How many pages to go forward. """ - self._back_forward(tab, bg, count, forward=True) + self._back_forward(tab, bg, window, count, forward=True) - def _navigate_incdec(self, url, tab, incdec): + def _navigate_incdec(self, url, incdec, tab, background, window): """Helper method for :navigate when `where' is increment/decrement. Args: url: The current url. - tab: Whether to open the link in a new tab. incdec: Either 'increment' or 'decrement'. + tab: Whether to open the link in a new tab. + background: Open the link in a new background tab. + window: Open the link in a new window. """ encoded = bytes(url.toEncoded()).decode('ascii') # Get the last number in a string @@ -383,25 +395,27 @@ class CommandDispatcher: raise ValueError("Invalid value {} for indec!".format(incdec)) urlstr = ''.join([pre, str(val), post]).encode('ascii') new_url = QUrl.fromEncoded(urlstr) - self._open(new_url, tab, background=False, window=False) + self._open(new_url, tab, background, window) - def _navigate_up(self, url, tab): + def _navigate_up(self, url, tab, background, window): """Helper method for :navigate when `where' is up. Args: url: The current url. tab: Whether to open the link in a new tab. + background: Open the link in a new background tab. + window: Open the link in a new window. """ path = url.path() if not path or path == '/': raise cmdexc.CommandError("Can't go up!") new_path = posixpath.join(path, posixpath.pardir) url.setPath(new_path) - self._open(url, tab, background=False, window=False) + self._open(url, tab, background, window) @cmdutils.register(instance='command-dispatcher', scope='window') def navigate(self, where: ('prev', 'next', 'up', 'increment', 'decrement'), - tab=False): + tab=False, bg=False, window=False): """Open typical prev/next links or navigate using the URL path. This tries to automatically click on typical _Previous Page_ or @@ -419,7 +433,11 @@ class CommandDispatcher: - `decrement`: Decrement the last number in the URL. tab: Open in a new tab. + bg: Open in a background tab. + window: Open in a new window. """ + if sum(1 for e in (tab, bg, window) if e) > 1: + raise cmdexc.CommandError("Only one of -t/-b/-w can be given!") widget = self._current_widget() frame = widget.page().currentFrame() url = self._current_url() @@ -427,13 +445,15 @@ class CommandDispatcher: raise cmdexc.CommandError("No frame focused!") hintmanager = objreg.get('hintmanager', scope='tab') if where == 'prev': - hintmanager.follow_prevnext(frame, url, prev=True, newtab=tab) + hintmanager.follow_prevnext(frame, url, prev=True, tab=tab, + background=background, window=window) elif where == 'next': - hintmanager.follow_prevnext(frame, url, prev=False, newtab=tab) + hintmanager.follow_prevnext(frame, url, prev=False, tab=tab, + background=background, window=window) elif where == 'up': - self._navigate_up(url, tab) + self._navigate_up(url, tab, background, window) elif where in ('decrement', 'increment'): - self._navigate_incdec(url, tab, where) + self._navigate_incdec(url, where, tab, background, window) else: raise ValueError("Got called with invalid value {} for " "`where'.".format(where)) diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index 30ce73179..567085dbd 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -37,7 +37,7 @@ from qutebrowser.utils import usertypes, log, qtutils, message, objreg ElemTuple = collections.namedtuple('ElemTuple', ['elem', 'label']) -Target = usertypes.enum('Target', ['normal', 'tab', 'tab_bg', 'yank', +Target = usertypes.enum('Target', ['normal', 'tab', 'tab_bg', 'window', 'yank', 'yank_primary', 'fill', 'rapid', 'download', 'userscript', 'spawn']) @@ -58,7 +58,7 @@ class HintContext: elems: A mapping from keystrings to (elem, label) namedtuples. baseurl: The URL of the current page. target: What to do with the opened links. - normal/tab/tab_bg: Get passed to BrowserTab. + normal/tab/tab_bg/window: Get passed to BrowserTab. yank/yank_primary: Yank to clipboard/primary selection fill: Fill commandline with link. rapid: Rapid mode with background tabs @@ -127,6 +127,7 @@ class HintManager(QObject): Target.normal: "Follow hint...", Target.tab: "Follow hint in new tab...", Target.tab_bg: "Follow hint in background tab...", + Target.window: "Follow hint in new window...", Target.yank: "Yank hint to clipboard...", Target.yank_primary: "Yank hint to primary selection...", Target.fill: "Set hint in commandline...", @@ -500,14 +501,17 @@ class HintManager(QObject): keyparser = keyparsers[usertypes.KeyMode.hint] keyparser.update_bindings(strings) - def follow_prevnext(self, frame, baseurl, prev=False, newtab=False): + def follow_prevnext(self, frame, baseurl, prev=False, tab=False, + background=False, window=False): """Click a "previous"/"next" element on the page. Args: frame: The frame where the element is in. baseurl: The base URL of the current tab. prev: True to open a "previous" link, False to open a "next" link. - newtab: True to open in a new tab, False for the current tab. + tab: True to open in a new tab, False for the current tab. + background: True to open in a background tab. + window: True to open in a new window, False for the current one. """ elem = self._find_prevnext(frame, prev) if elem is None: @@ -518,13 +522,21 @@ class HintManager(QObject): raise cmdexc.CommandError("No {} links found!".format( "prev" if prev else "forward")) qtutils.ensure_valid(url) - if newtab: - tabbed_browser = objreg.get('tabbed-browser', scope='window', - window=self._win_id) - tabbed_browser.tabopen(url, background=False) + if window: + # We have to import this here to avoid a circular import. + from qutebrowser.widgets import mainwindow + win_id = mainwindow.create_window(True) + tab_id = 0 else: - webview = objreg.get('webview', scope='tab', window=self._win_id, - tab=self._tab_id) + win_id = self._win_id + tab_id = self._tab_id + if tab: + tabbed_browser = objreg.get('tabbed-browser', scope='window', + window=win_id) + tabbed_browser.tabopen(url, background=background) + else: + webview = objreg.get('webview', scope='tab', window=win_id, + tab=tab_id) webview.openurl(url) @cmdutils.register(instance='hintmanager', scope='tab', name='hint') @@ -544,6 +556,7 @@ class HintManager(QObject): - `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. - `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 @@ -650,6 +663,7 @@ class HintManager(QObject): Target.normal: self._click, Target.tab: self._click, Target.tab_bg: self._click, + Target.window: self._click, Target.rapid: self._click, # _download needs a QWebElement to get the frame. Target.download: self._download, diff --git a/qutebrowser/browser/webpage.py b/qutebrowser/browser/webpage.py index 09571a51f..e0dcabd61 100644 --- a/qutebrowser/browser/webpage.py +++ b/qutebrowser/browser/webpage.py @@ -302,11 +302,20 @@ class BrowserPage(QWebPage): return False tabbed_browser = objreg.get('tabbed-browser', scope='window', window=self._win_id) - if self.view().open_target == usertypes.ClickTarget.tab: + open_target = self.view().open_target + if open_target == usertypes.ClickTarget.tab: tabbed_browser.tabopen(url, False) return False - elif self.view().open_target == usertypes.ClickTarget.tab_bg: + elif open_target == usertypes.ClickTarget.tab_bg: tabbed_browser.tabopen(url, True) return False + elif open_target == usertypes.ClickTarget.window: + # We have to import this here to avoid a circular import. + from qutebrowser.widgets import mainwindow + win_id = mainwindow.create_window(True) + tabbed_browser = objreg.get('tabbed-browser', scope='window', + window=win_id) + tabbed_browser.openurl(url, False) + return False else: return True diff --git a/qutebrowser/utils/usertypes.py b/qutebrowser/utils/usertypes.py index e3d354eed..1cdc14d9e 100644 --- a/qutebrowser/utils/usertypes.py +++ b/qutebrowser/utils/usertypes.py @@ -228,7 +228,7 @@ PromptMode = enum('PromptMode', ['yesno', 'text', 'user_pwd', 'alert']) # Where to open a clicked link. -ClickTarget = enum('ClickTarget', ['normal', 'tab', 'tab_bg']) +ClickTarget = enum('ClickTarget', ['normal', 'tab', 'tab_bg', 'window']) # Key input modes