Merge branch 'haasn-issue1060'
This commit is contained in:
commit
ea14b5bb42
@ -67,7 +67,7 @@ Changed
|
||||
the most recently focused (instead of the last opened) window. This can be
|
||||
configured with the new `new-instance-open-target.window` setting.
|
||||
It can also be set to `last-visible` to show the pages in the most recently
|
||||
visible window.
|
||||
visible window, or `first-opened` to use the first (oldest) available window.
|
||||
- Word hints now are more clever about getting the element text from some elements.
|
||||
- Completions for `:help` and `:bind` now also show hidden commands
|
||||
- The `:buffer` completion now also filters using the first column (id).
|
||||
@ -79,6 +79,8 @@ Changed
|
||||
- Counts can now be used with special keybindings (e.g. with modifiers).
|
||||
This was already implemented for v0.7.0 originally, but got reverted because
|
||||
it caused some issues and then never re-applied.
|
||||
- Sending a command to an existing instance (via "qutebrowser :reload") now
|
||||
doesn't mark it as urgent anymore.
|
||||
|
||||
Deprecated
|
||||
~~~~~~~~~~
|
||||
|
@ -166,10 +166,10 @@ Contributors, sorted by the number of commits in descending order:
|
||||
* Thorsten Wißmann
|
||||
* Austin Anderson
|
||||
* Jimmy
|
||||
* Niklas Haas
|
||||
* Alexey "Averrin" Nabrodov
|
||||
* avk
|
||||
* ZDarian
|
||||
* Niklas Haas
|
||||
* Milan Svoboda
|
||||
* John ShaggyTwoDope Jenkins
|
||||
* Peter Vilim
|
||||
|
@ -454,7 +454,8 @@ Which window to choose when opening links as new tabs.
|
||||
|
||||
Valid values:
|
||||
|
||||
* +last-opened+: Open new tabs in the last opened window.
|
||||
* +first-opened+: Open new tabs in the first (oldest) opened window.
|
||||
* +last-opened+: Open new tabs in the last (newest) opened window.
|
||||
* +last-focused+: Open new tabs in the most recently focused window.
|
||||
* +last-visible+: Open new tabs in the most recently visible window.
|
||||
|
||||
|
@ -230,8 +230,10 @@ def data(readonly=False):
|
||||
('new-instance-open-target.window',
|
||||
SettingValue(typ.String(
|
||||
valid_values=typ.ValidValues(
|
||||
('last-opened', "Open new tabs in the last opened "
|
||||
"window."),
|
||||
('first-opened', "Open new tabs in the first (oldest) "
|
||||
"opened window."),
|
||||
('last-opened', "Open new tabs in the last (newest) "
|
||||
"opened window."),
|
||||
('last-focused', "Open new tabs in the most recently "
|
||||
"focused window."),
|
||||
('last-visible', "Open new tabs in the most recently "
|
||||
|
@ -54,44 +54,62 @@ def get_window(via_ipc, force_window=False, force_tab=False,
|
||||
"""
|
||||
if force_window and force_tab:
|
||||
raise ValueError("force_window and force_tab are mutually exclusive!")
|
||||
|
||||
if not via_ipc:
|
||||
# Initial main window
|
||||
return 0
|
||||
window_to_raise = None
|
||||
|
||||
open_target = config.get('general', 'new-instance-open-target')
|
||||
|
||||
# Apply any target overrides, ordered by precedence
|
||||
if force_target is not None:
|
||||
open_target = force_target
|
||||
else:
|
||||
open_target = config.get('general', 'new-instance-open-target')
|
||||
if (open_target == 'window' or force_window) and not force_tab:
|
||||
if force_window:
|
||||
open_target = 'window'
|
||||
if force_tab and open_target == 'window':
|
||||
# Command sent via IPC
|
||||
open_target = 'tab-silent'
|
||||
|
||||
window = None
|
||||
raise_window = False
|
||||
|
||||
# Try to find the existing tab target if opening in a tab
|
||||
if open_target != 'window':
|
||||
window = get_target_window()
|
||||
raise_window = open_target not in ['tab-silent', 'tab-bg-silent']
|
||||
|
||||
# Otherwise, or if no window was found, create a new one
|
||||
if window is None:
|
||||
window = MainWindow()
|
||||
window.show()
|
||||
win_id = window.win_id
|
||||
window_to_raise = window
|
||||
else:
|
||||
raise_window = True
|
||||
|
||||
if raise_window:
|
||||
window.setWindowState(window.windowState() & ~Qt.WindowMinimized)
|
||||
window.setWindowState(window.windowState() | Qt.WindowActive)
|
||||
window.raise_()
|
||||
window.activateWindow()
|
||||
QApplication.instance().alert(window)
|
||||
|
||||
return window.win_id
|
||||
|
||||
|
||||
def get_target_window():
|
||||
"""Get the target window for new tabs, or None if none exist."""
|
||||
try:
|
||||
win_mode = config.get('general', 'new-instance-open-target.window')
|
||||
if win_mode == 'last-focused':
|
||||
window = objreg.last_focused_window()
|
||||
return objreg.last_focused_window()
|
||||
elif win_mode == 'first-opened':
|
||||
return objreg.window_by_index(0)
|
||||
elif win_mode == 'last-opened':
|
||||
window = objreg.last_window()
|
||||
return objreg.window_by_index(-1)
|
||||
elif win_mode == 'last-visible':
|
||||
window = objreg.last_visible_window()
|
||||
return objreg.last_visible_window()
|
||||
else:
|
||||
raise ValueError("Invalid win_mode {}".format(win_mode))
|
||||
except objreg.NoWindow:
|
||||
# There is no window left, so we open a new one
|
||||
window = MainWindow()
|
||||
window.show()
|
||||
win_id = window.win_id
|
||||
window_to_raise = window
|
||||
win_id = window.win_id
|
||||
if open_target not in ['tab-silent', 'tab-bg-silent']:
|
||||
window_to_raise = window
|
||||
if window_to_raise is not None:
|
||||
window_to_raise.setWindowState(
|
||||
window.windowState() & ~Qt.WindowMinimized | Qt.WindowActive)
|
||||
window_to_raise.raise_()
|
||||
window_to_raise.activateWindow()
|
||||
QApplication.instance().alert(window_to_raise)
|
||||
return win_id
|
||||
return None
|
||||
|
||||
|
||||
class MainWindow(QWidget):
|
||||
|
@ -298,13 +298,13 @@ def last_focused_window():
|
||||
try:
|
||||
return get('last-focused-main-window')
|
||||
except KeyError:
|
||||
return last_window()
|
||||
return window_by_index(-1)
|
||||
|
||||
|
||||
def last_window():
|
||||
"""Get the last opened window object."""
|
||||
def window_by_index(idx):
|
||||
"""Get the Nth opened window object."""
|
||||
if not window_registry:
|
||||
raise NoWindow()
|
||||
else:
|
||||
key = sorted(window_registry)[-1]
|
||||
key = sorted(window_registry)[idx]
|
||||
return window_registry[key]
|
||||
|
@ -156,15 +156,18 @@ def open_path(quteproc, path):
|
||||
"""Open a URL.
|
||||
|
||||
If used like "When I open ... in a new tab", the URL is opened in a new
|
||||
tab. With "... in a new window", it's opened in a new window.
|
||||
tab. With "... in a new window", it's opened in a new window. With
|
||||
"... as a URL", it's opened according to new-instance-open-target.
|
||||
"""
|
||||
new_tab = False
|
||||
new_window = False
|
||||
as_url = False
|
||||
wait = True
|
||||
|
||||
new_tab_suffix = ' in a new tab'
|
||||
new_window_suffix = ' in a new window'
|
||||
do_not_wait_suffix = ' without waiting'
|
||||
as_url_suffix = ' as a URL'
|
||||
|
||||
if path.endswith(new_tab_suffix):
|
||||
path = path[:-len(new_tab_suffix)]
|
||||
@ -172,12 +175,16 @@ def open_path(quteproc, path):
|
||||
elif path.endswith(new_window_suffix):
|
||||
path = path[:-len(new_window_suffix)]
|
||||
new_window = True
|
||||
elif path.endswith(as_url_suffix):
|
||||
path = path[:-len(as_url_suffix)]
|
||||
as_url = True
|
||||
|
||||
if path.endswith(do_not_wait_suffix):
|
||||
path = path[:-len(do_not_wait_suffix)]
|
||||
wait = False
|
||||
|
||||
quteproc.open_path(path, new_tab=new_tab, new_window=new_window, wait=wait)
|
||||
quteproc.open_path(path, new_tab=new_tab, new_window=new_window,
|
||||
as_url=as_url, wait=wait)
|
||||
|
||||
|
||||
@bdd.when(bdd.parsers.parse("I set {sect} -> {opt} to {value}"))
|
||||
|
108
tests/end2end/features/invoke.feature
Normal file
108
tests/end2end/features/invoke.feature
Normal file
@ -0,0 +1,108 @@
|
||||
Feature: Invoking a new process
|
||||
Simulate what happens when running qutebrowser with an existing instance
|
||||
|
||||
Background:
|
||||
Given I clean up open tabs
|
||||
|
||||
Scenario: Using new-instance-open-target = tab
|
||||
When I set general -> new-instance-open-target to tab
|
||||
And I open data/title.html
|
||||
And I open data/search.html as a URL
|
||||
Then the following tabs should be open:
|
||||
- data/title.html
|
||||
- data/search.html (active)
|
||||
|
||||
Scenario: Using new-instance-open-target = tab-bg
|
||||
When I set general -> new-instance-open-target to tab-bg
|
||||
And I open data/title.html
|
||||
And I open data/search.html as a URL
|
||||
Then the following tabs should be open:
|
||||
- data/title.html (active)
|
||||
- data/search.html
|
||||
|
||||
Scenario: Using new-instance-open-target = window
|
||||
When I set general -> new-instance-open-target to window
|
||||
And I open data/title.html
|
||||
And I open data/search.html as a URL
|
||||
Then the session should look like:
|
||||
windows:
|
||||
- tabs:
|
||||
- history:
|
||||
- url: about:blank
|
||||
- url: http://localhost:*/data/title.html
|
||||
- tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/search.html
|
||||
|
||||
Scenario: Using new-instance-open-target.window = last-opened
|
||||
When I set general -> new-instance-open-target to tab
|
||||
And I set general -> new-instance-open-target.window to last-opened
|
||||
And I open data/title.html
|
||||
And I open data/search.html in a new window
|
||||
And I open data/hello.txt as a URL
|
||||
Then the session should look like:
|
||||
windows:
|
||||
- tabs:
|
||||
- history:
|
||||
- url: about:blank
|
||||
- url: http://localhost:*/data/title.html
|
||||
- tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/search.html
|
||||
- history:
|
||||
- url: http://localhost:*/data/hello.txt
|
||||
|
||||
Scenario: Using new-instance-open-target.window = first-opened
|
||||
When I set general -> new-instance-open-target to tab
|
||||
And I set general -> new-instance-open-target.window to first-opened
|
||||
And I open data/title.html
|
||||
And I open data/search.html in a new window
|
||||
And I open data/hello.txt as a URL
|
||||
Then the session should look like:
|
||||
windows:
|
||||
- tabs:
|
||||
- history:
|
||||
- url: about:blank
|
||||
- url: http://localhost:*/data/title.html
|
||||
- history:
|
||||
- url: http://localhost:*/data/hello.txt
|
||||
- tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/search.html
|
||||
|
||||
# issue #1060
|
||||
|
||||
Scenario: Using target.window = first-opened after tab-detach
|
||||
When I set general -> new-instance-open-target to tab
|
||||
And I set general -> new-instance-open-target.window to first-opened
|
||||
And I open data/title.html
|
||||
And I open data/search.html in a new tab
|
||||
And I run :tab-detach
|
||||
And I open data/hello.txt as a URL
|
||||
Then the session should look like:
|
||||
windows:
|
||||
- tabs:
|
||||
- history:
|
||||
- url: about:blank
|
||||
- url: http://localhost:*/data/title.html
|
||||
- history:
|
||||
- url: http://localhost:*/data/hello.txt
|
||||
- tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/search.html
|
||||
|
||||
Scenario: Opening a new qutebrowser instance with no parameters
|
||||
When I set general -> new-instance-open-target to tab
|
||||
And I set general -> startpage to about:blank
|
||||
And I open data/title.html
|
||||
And I spawn a new window
|
||||
And I wait until about:blank is loaded
|
||||
Then the session should look like:
|
||||
windows:
|
||||
- tabs:
|
||||
- history:
|
||||
- url: about:blank
|
||||
- url: http://localhost:*/data/title.html
|
||||
- tabs:
|
||||
- history:
|
||||
- url: about:blank
|
30
tests/end2end/features/test_invoke_bdd.py
Normal file
30
tests/end2end/features/test_invoke_bdd.py
Normal file
@ -0,0 +1,30 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
# qutebrowser is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# qutebrowser is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pytest_bdd as bdd
|
||||
bdd.scenarios('invoke.feature')
|
||||
|
||||
|
||||
@bdd.when(bdd.parsers.parse("I spawn a new window"))
|
||||
def invoke_with(quteproc):
|
||||
"""Spawn a new window via IPC call."""
|
||||
quteproc.log_summary("Create a new window")
|
||||
quteproc.send_ipc([], target_arg='window')
|
||||
quteproc.wait_for(category='init', module='app',
|
||||
function='_open_startpage', message='Opening startpage')
|
@ -365,6 +365,15 @@ class QuteProc(testprocess.Process):
|
||||
finally:
|
||||
super().after_test()
|
||||
|
||||
def send_ipc(self, commands, target_arg=''):
|
||||
"""Send a raw command to the running IPC socket."""
|
||||
time.sleep(self._delay / 1000)
|
||||
|
||||
assert self._ipc_socket is not None
|
||||
ipc.send_to_running_instance(self._ipc_socket, commands, target_arg)
|
||||
self.wait_for(category='ipc', module='ipc', function='on_ready_read',
|
||||
message='Read from socket *')
|
||||
|
||||
def send_cmd(self, command, count=None, invalid=False, *, escape=True):
|
||||
"""Send a command to the running qutebrowser instance.
|
||||
|
||||
@ -379,18 +388,13 @@ class QuteProc(testprocess.Process):
|
||||
summary += ' (count {})'.format(count)
|
||||
self.log_summary(summary)
|
||||
|
||||
assert self._ipc_socket is not None
|
||||
|
||||
time.sleep(self._delay / 1000)
|
||||
|
||||
if escape:
|
||||
command = command.replace('\\', r'\\')
|
||||
|
||||
if count is not None:
|
||||
command = ':{}:{}'.format(count, command.lstrip(':'))
|
||||
|
||||
ipc.send_to_running_instance(self._ipc_socket, [command],
|
||||
target_arg='')
|
||||
self.send_ipc([command])
|
||||
if not invalid:
|
||||
self.wait_for(category='commands', module='command',
|
||||
function='run', message='command called: *')
|
||||
@ -418,18 +422,22 @@ class QuteProc(testprocess.Process):
|
||||
yield
|
||||
self.set_setting(sect, opt, old_value)
|
||||
|
||||
def open_path(self, path, *, new_tab=False, new_window=False, port=None,
|
||||
https=False, wait=True):
|
||||
def open_path(self, path, *, new_tab=False, new_window=False, as_url=False,
|
||||
port=None, https=False, wait=True):
|
||||
"""Open the given path on the local webserver in qutebrowser."""
|
||||
url = self.path_to_url(path, port=port, https=https)
|
||||
self.open_url(url, new_tab=new_tab, new_window=new_window, wait=wait)
|
||||
self.open_url(url, new_tab=new_tab, new_window=new_window,
|
||||
as_url=as_url, wait=wait)
|
||||
|
||||
def open_url(self, url, *, new_tab=False, new_window=False, wait=True):
|
||||
def open_url(self, url, *, new_tab=False, new_window=False, as_url=False,
|
||||
wait=True):
|
||||
"""Open the given url in qutebrowser."""
|
||||
if new_tab and new_window:
|
||||
raise ValueError("new_tab and new_window given!")
|
||||
|
||||
if new_tab:
|
||||
if as_url:
|
||||
self.send_cmd(url, invalid=True)
|
||||
elif new_tab:
|
||||
self.send_cmd(':open -t ' + url)
|
||||
elif new_window:
|
||||
self.send_cmd(':open -w ' + url)
|
||||
|
Loading…
Reference in New Issue
Block a user