Merge branch 'master' of https://github.com/qutebrowser/qutebrowser into jay/visible-update-titles
This commit is contained in:
commit
322b053cbf
@ -43,6 +43,10 @@ Added
|
|||||||
- Running qutebrowser with QtWebKit or Qt < 5.9 now shows a warning (only
|
- Running qutebrowser with QtWebKit or Qt < 5.9 now shows a warning (only
|
||||||
once), as support for those is going to be removed in a future release.
|
once), as support for those is going to be removed in a future release.
|
||||||
- New t[iI][hHu] default bindings (similar to `tsh` etc.) to toggle images.
|
- New t[iI][hHu] default bindings (similar to `tsh` etc.) to toggle images.
|
||||||
|
- New `tabs.max_width` setting which allows to have a more "normal" look for
|
||||||
|
tabs.
|
||||||
|
- New `content.mute` setting which allows to mute pages (or all tabs) by
|
||||||
|
default.
|
||||||
|
|
||||||
Changed
|
Changed
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
@ -73,6 +77,11 @@ Changed
|
|||||||
- Editing text in an external editor now simulates a JS "input" event, which
|
- Editing text in an external editor now simulates a JS "input" event, which
|
||||||
improves compatibility with websites reacting via JS to input.
|
improves compatibility with websites reacting via JS to input.
|
||||||
- The `qute://settings` page is now properly sorted on Python 3.5.
|
- The `qute://settings` page is now properly sorted on Python 3.5.
|
||||||
|
- `:zoom`, `:zoom-in` and `:zoom-out` now have a `--quiet` switch which causes
|
||||||
|
them to not display a message.
|
||||||
|
- The `scrolling.bar` setting now takes three values instead of being a
|
||||||
|
boolean: `always`, `never`, and `when-searching` (which only displays it
|
||||||
|
while a search is active).
|
||||||
|
|
||||||
Fixed
|
Fixed
|
||||||
~~~~~
|
~~~~~
|
||||||
|
@ -1413,7 +1413,7 @@ Yank something to the clipboard or primary selection.
|
|||||||
|
|
||||||
[[zoom]]
|
[[zoom]]
|
||||||
=== zoom
|
=== zoom
|
||||||
Syntax: +:zoom ['zoom']+
|
Syntax: +:zoom [*--quiet*] ['zoom']+
|
||||||
|
|
||||||
Set the zoom level for the current tab.
|
Set the zoom level for the current tab.
|
||||||
|
|
||||||
@ -1422,20 +1422,33 @@ The zoom can be given as argument or as [count]. If neither is given, the zoom i
|
|||||||
==== positional arguments
|
==== positional arguments
|
||||||
* +'zoom'+: The zoom percentage to set.
|
* +'zoom'+: The zoom percentage to set.
|
||||||
|
|
||||||
|
==== optional arguments
|
||||||
|
* +*-q*+, +*--quiet*+: Don't show a zoom level message.
|
||||||
|
|
||||||
==== count
|
==== count
|
||||||
The zoom percentage to set.
|
The zoom percentage to set.
|
||||||
|
|
||||||
[[zoom-in]]
|
[[zoom-in]]
|
||||||
=== zoom-in
|
=== zoom-in
|
||||||
|
Syntax: +:zoom-in [*--quiet*]+
|
||||||
|
|
||||||
Increase the zoom level for the current tab.
|
Increase the zoom level for the current tab.
|
||||||
|
|
||||||
|
==== optional arguments
|
||||||
|
* +*-q*+, +*--quiet*+: Don't show a zoom level message.
|
||||||
|
|
||||||
==== count
|
==== count
|
||||||
How many steps to zoom in.
|
How many steps to zoom in.
|
||||||
|
|
||||||
[[zoom-out]]
|
[[zoom-out]]
|
||||||
=== zoom-out
|
=== zoom-out
|
||||||
|
Syntax: +:zoom-out [*--quiet*]+
|
||||||
|
|
||||||
Decrease the zoom level for the current tab.
|
Decrease the zoom level for the current tab.
|
||||||
|
|
||||||
|
==== optional arguments
|
||||||
|
* +*-q*+, +*--quiet*+: Don't show a zoom level message.
|
||||||
|
|
||||||
==== count
|
==== count
|
||||||
How many steps to zoom out.
|
How many steps to zoom out.
|
||||||
|
|
||||||
|
@ -145,6 +145,7 @@
|
|||||||
|<<content.local_storage,content.local_storage>>|Enable support for HTML 5 local storage and Web SQL.
|
|<<content.local_storage,content.local_storage>>|Enable support for HTML 5 local storage and Web SQL.
|
||||||
|<<content.media_capture,content.media_capture>>|Allow websites to record audio/video.
|
|<<content.media_capture,content.media_capture>>|Allow websites to record audio/video.
|
||||||
|<<content.mouse_lock,content.mouse_lock>>|Allow websites to lock your mouse pointer.
|
|<<content.mouse_lock,content.mouse_lock>>|Allow websites to lock your mouse pointer.
|
||||||
|
|<<content.mute,content.mute>>|Automatically mute tabs.
|
||||||
|<<content.netrc_file,content.netrc_file>>|Netrc-file for HTTP authentication.
|
|<<content.netrc_file,content.netrc_file>>|Netrc-file for HTTP authentication.
|
||||||
|<<content.notifications,content.notifications>>|Allow websites to show notifications.
|
|<<content.notifications,content.notifications>>|Allow websites to show notifications.
|
||||||
|<<content.pdfjs,content.pdfjs>>|Allow pdf.js to view PDF files in the browser.
|
|<<content.pdfjs,content.pdfjs>>|Allow pdf.js to view PDF files in the browser.
|
||||||
@ -231,7 +232,7 @@
|
|||||||
|<<qt.highdpi,qt.highdpi>>|Turn on Qt HighDPI scaling.
|
|<<qt.highdpi,qt.highdpi>>|Turn on Qt HighDPI scaling.
|
||||||
|<<qt.low_end_device_mode,qt.low_end_device_mode>>|When to use Chromium's low-end device mode.
|
|<<qt.low_end_device_mode,qt.low_end_device_mode>>|When to use Chromium's low-end device mode.
|
||||||
|<<qt.process_model,qt.process_model>>|Which Chromium process model to use.
|
|<<qt.process_model,qt.process_model>>|Which Chromium process model to use.
|
||||||
|<<scrolling.bar,scrolling.bar>>|Show a scrollbar.
|
|<<scrolling.bar,scrolling.bar>>|When to show the scrollbar.
|
||||||
|<<scrolling.smooth,scrolling.smooth>>|Enable smooth scrolling for web pages.
|
|<<scrolling.smooth,scrolling.smooth>>|Enable smooth scrolling for web pages.
|
||||||
|<<search.ignore_case,search.ignore_case>>|When to find text on a page case-insensitively.
|
|<<search.ignore_case,search.ignore_case>>|When to find text on a page case-insensitively.
|
||||||
|<<search.incremental,search.incremental>>|Find text on a page incrementally, renewing the search for each typed character.
|
|<<search.incremental,search.incremental>>|Find text on a page incrementally, renewing the search for each typed character.
|
||||||
@ -250,6 +251,7 @@
|
|||||||
|<<tabs.indicator.padding,tabs.indicator.padding>>|Padding (in pixels) for tab indicators.
|
|<<tabs.indicator.padding,tabs.indicator.padding>>|Padding (in pixels) for tab indicators.
|
||||||
|<<tabs.indicator.width,tabs.indicator.width>>|Width (in pixels) of the progress indicator (0 to disable).
|
|<<tabs.indicator.width,tabs.indicator.width>>|Width (in pixels) of the progress indicator (0 to disable).
|
||||||
|<<tabs.last_close,tabs.last_close>>|How to behave when the last tab is closed.
|
|<<tabs.last_close,tabs.last_close>>|How to behave when the last tab is closed.
|
||||||
|
|<<tabs.max_width,tabs.max_width>>|Maximum width (in pixels) of tabs (-1 for no maximum).
|
||||||
|<<tabs.min_width,tabs.min_width>>|Minimum width (in pixels) of tabs (-1 for the default minimum size behavior).
|
|<<tabs.min_width,tabs.min_width>>|Minimum width (in pixels) of tabs (-1 for the default minimum size behavior).
|
||||||
|<<tabs.mode_on_change,tabs.mode_on_change>>|When switching tabs, what input mode is applied.
|
|<<tabs.mode_on_change,tabs.mode_on_change>>|When switching tabs, what input mode is applied.
|
||||||
|<<tabs.mousewheel_switching,tabs.mousewheel_switching>>|Switch between tabs using the mouse wheel.
|
|<<tabs.mousewheel_switching,tabs.mousewheel_switching>>|Switch between tabs using the mouse wheel.
|
||||||
@ -1915,6 +1917,17 @@ On QtWebEngine, this setting requires Qt 5.8 or newer.
|
|||||||
|
|
||||||
On QtWebKit, this setting is unavailable.
|
On QtWebKit, this setting is unavailable.
|
||||||
|
|
||||||
|
[[content.mute]]
|
||||||
|
=== content.mute
|
||||||
|
Automatically mute tabs.
|
||||||
|
Note that if the `:tab-mute` command is used, the mute status for the affected tab is now controlled manually, and this setting doesn't have any effect.
|
||||||
|
|
||||||
|
This setting supports URL patterns.
|
||||||
|
|
||||||
|
Type: <<types,Bool>>
|
||||||
|
|
||||||
|
Default: +pass:[false]+
|
||||||
|
|
||||||
[[content.netrc_file]]
|
[[content.netrc_file]]
|
||||||
=== content.netrc_file
|
=== content.netrc_file
|
||||||
Netrc-file for HTTP authentication.
|
Netrc-file for HTTP authentication.
|
||||||
@ -2815,11 +2828,17 @@ This setting is only available with the QtWebEngine backend.
|
|||||||
|
|
||||||
[[scrolling.bar]]
|
[[scrolling.bar]]
|
||||||
=== scrolling.bar
|
=== scrolling.bar
|
||||||
Show a scrollbar.
|
When to show the scrollbar.
|
||||||
|
|
||||||
Type: <<types,Bool>>
|
Type: <<types,String>>
|
||||||
|
|
||||||
Default: +pass:[false]+
|
Valid values:
|
||||||
|
|
||||||
|
* +always+: Always show the scrollbar.
|
||||||
|
* +never+: Never show the scrollbar.
|
||||||
|
* +when-searching+: Show the scrollbar when searching for text in the webpage. With the QtWebKit backend, this is equal to `never`.
|
||||||
|
|
||||||
|
Default: +pass:[when-searching]+
|
||||||
|
|
||||||
[[scrolling.smooth]]
|
[[scrolling.smooth]]
|
||||||
=== scrolling.smooth
|
=== scrolling.smooth
|
||||||
@ -3086,6 +3105,17 @@ Valid values:
|
|||||||
|
|
||||||
Default: +pass:[ignore]+
|
Default: +pass:[ignore]+
|
||||||
|
|
||||||
|
[[tabs.max_width]]
|
||||||
|
=== tabs.max_width
|
||||||
|
Maximum width (in pixels) of tabs (-1 for no maximum).
|
||||||
|
This setting only applies when tabs are horizontal.
|
||||||
|
This setting does not apply to pinned tabs, unless `tabs.pinned.shrink` is False.
|
||||||
|
This setting may not apply properly if max_width is smaller than the minimum size of tab contents, or smaller than tabs.min_width.
|
||||||
|
|
||||||
|
Type: <<types,Int>>
|
||||||
|
|
||||||
|
Default: +pass:[-1]+
|
||||||
|
|
||||||
[[tabs.min_width]]
|
[[tabs.min_width]]
|
||||||
=== tabs.min_width
|
=== tabs.min_width
|
||||||
Minimum width (in pixels) of tabs (-1 for the default minimum size behavior).
|
Minimum width (in pixels) of tabs (-1 for the default minimum size behavior).
|
||||||
|
@ -248,10 +248,19 @@ class AbstractSearch(QObject):
|
|||||||
this view.
|
this view.
|
||||||
_flags: The flags of the last search (needs to be set by subclasses).
|
_flags: The flags of the last search (needs to be set by subclasses).
|
||||||
_widget: The underlying WebView widget.
|
_widget: The underlying WebView widget.
|
||||||
|
|
||||||
|
Signals:
|
||||||
|
finished: Emitted when a search was finished.
|
||||||
|
arg: True if the text was found, False otherwise.
|
||||||
|
cleared: Emitted when an existing search was cleared.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
finished = pyqtSignal(bool)
|
||||||
|
cleared = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, tab, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
self._tab = tab
|
||||||
self._widget = None
|
self._widget = None
|
||||||
self.text = None
|
self.text = None
|
||||||
self.search_displayed = False
|
self.search_displayed = False
|
||||||
@ -668,20 +677,27 @@ class AbstractAudio(QObject):
|
|||||||
muted_changed = pyqtSignal(bool)
|
muted_changed = pyqtSignal(bool)
|
||||||
recently_audible_changed = pyqtSignal(bool)
|
recently_audible_changed = pyqtSignal(bool)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, tab, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._widget = None
|
self._widget = None
|
||||||
|
self._tab = tab
|
||||||
|
|
||||||
def set_muted(self, muted: bool):
|
def set_muted(self, muted: bool, override: bool = False):
|
||||||
"""Set this tab as muted or not."""
|
"""Set this tab as muted or not.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
override: If set to True, muting/unmuting was done manually and
|
||||||
|
overrides future automatic mute/unmute changes based on
|
||||||
|
the URL.
|
||||||
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def is_muted(self):
|
def is_muted(self):
|
||||||
"""Whether this tab is muted."""
|
"""Whether this tab is muted."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def toggle_muted(self):
|
def toggle_muted(self, *, override: bool = False):
|
||||||
self.set_muted(not self.is_muted())
|
self.set_muted(not self.is_muted(), override=override)
|
||||||
|
|
||||||
def is_recently_audible(self):
|
def is_recently_audible(self):
|
||||||
"""Whether this tab has had audio playing recently."""
|
"""Whether this tab has had audio playing recently."""
|
||||||
|
@ -870,37 +870,41 @@ class CommandDispatcher:
|
|||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', scope='window')
|
@cmdutils.register(instance='command-dispatcher', scope='window')
|
||||||
@cmdutils.argument('count', count=True)
|
@cmdutils.argument('count', count=True)
|
||||||
def zoom_in(self, count=1):
|
def zoom_in(self, count=1, quiet=False):
|
||||||
"""Increase the zoom level for the current tab.
|
"""Increase the zoom level for the current tab.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
count: How many steps to zoom in.
|
count: How many steps to zoom in.
|
||||||
|
quiet: Don't show a zoom level message.
|
||||||
"""
|
"""
|
||||||
tab = self._current_widget()
|
tab = self._current_widget()
|
||||||
try:
|
try:
|
||||||
perc = tab.zoom.offset(count)
|
perc = tab.zoom.offset(count)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise cmdexc.CommandError(e)
|
raise cmdexc.CommandError(e)
|
||||||
|
if not quiet:
|
||||||
message.info("Zoom level: {}%".format(int(perc)), replace=True)
|
message.info("Zoom level: {}%".format(int(perc)), replace=True)
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', scope='window')
|
@cmdutils.register(instance='command-dispatcher', scope='window')
|
||||||
@cmdutils.argument('count', count=True)
|
@cmdutils.argument('count', count=True)
|
||||||
def zoom_out(self, count=1):
|
def zoom_out(self, count=1, quiet=False):
|
||||||
"""Decrease the zoom level for the current tab.
|
"""Decrease the zoom level for the current tab.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
count: How many steps to zoom out.
|
count: How many steps to zoom out.
|
||||||
|
quiet: Don't show a zoom level message.
|
||||||
"""
|
"""
|
||||||
tab = self._current_widget()
|
tab = self._current_widget()
|
||||||
try:
|
try:
|
||||||
perc = tab.zoom.offset(-count)
|
perc = tab.zoom.offset(-count)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise cmdexc.CommandError(e)
|
raise cmdexc.CommandError(e)
|
||||||
|
if not quiet:
|
||||||
message.info("Zoom level: {}%".format(int(perc)), replace=True)
|
message.info("Zoom level: {}%".format(int(perc)), replace=True)
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', scope='window')
|
@cmdutils.register(instance='command-dispatcher', scope='window')
|
||||||
@cmdutils.argument('count', count=True)
|
@cmdutils.argument('count', count=True)
|
||||||
def zoom(self, zoom=None, count=None):
|
def zoom(self, zoom=None, count=None, quiet=False):
|
||||||
"""Set the zoom level for the current tab.
|
"""Set the zoom level for the current tab.
|
||||||
|
|
||||||
The zoom can be given as argument or as [count]. If neither is
|
The zoom can be given as argument or as [count]. If neither is
|
||||||
@ -910,6 +914,7 @@ class CommandDispatcher:
|
|||||||
Args:
|
Args:
|
||||||
zoom: The zoom percentage to set.
|
zoom: The zoom percentage to set.
|
||||||
count: The zoom percentage to set.
|
count: The zoom percentage to set.
|
||||||
|
quiet: Don't show a zoom level message.
|
||||||
"""
|
"""
|
||||||
if zoom is not None:
|
if zoom is not None:
|
||||||
try:
|
try:
|
||||||
@ -927,6 +932,7 @@ class CommandDispatcher:
|
|||||||
tab.zoom.set_factor(float(level) / 100)
|
tab.zoom.set_factor(float(level) / 100)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise cmdexc.CommandError("Can't zoom {}%!".format(level))
|
raise cmdexc.CommandError("Can't zoom {}%!".format(level))
|
||||||
|
if not quiet:
|
||||||
message.info("Zoom level: {}%".format(int(level)), replace=True)
|
message.info("Zoom level: {}%".format(int(level)), replace=True)
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', scope='window')
|
@cmdutils.register(instance='command-dispatcher', scope='window')
|
||||||
@ -2231,6 +2237,6 @@ class CommandDispatcher:
|
|||||||
if tab is None:
|
if tab is None:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
tab.audio.toggle_muted()
|
tab.audio.toggle_muted(override=True)
|
||||||
except browsertab.WebTabError as e:
|
except browsertab.WebTabError as e:
|
||||||
raise cmdexc.CommandError(e)
|
raise cmdexc.CommandError(e)
|
||||||
|
@ -274,7 +274,7 @@ def get_tab(win_id, target):
|
|||||||
return tabbed_browser.tabopen(url=None, background=bg_tab)
|
return tabbed_browser.tabopen(url=None, background=bg_tab)
|
||||||
|
|
||||||
|
|
||||||
def get_user_stylesheet():
|
def get_user_stylesheet(searching=False):
|
||||||
"""Get the combined user-stylesheet."""
|
"""Get the combined user-stylesheet."""
|
||||||
css = ''
|
css = ''
|
||||||
stylesheets = config.val.content.user_stylesheets
|
stylesheets = config.val.content.user_stylesheets
|
||||||
@ -283,7 +283,8 @@ def get_user_stylesheet():
|
|||||||
with open(filename, 'r', encoding='utf-8') as f:
|
with open(filename, 'r', encoding='utf-8') as f:
|
||||||
css += f.read()
|
css += f.read()
|
||||||
|
|
||||||
if not config.val.scrolling.bar:
|
if (config.val.scrolling.bar == 'never' or
|
||||||
|
config.val.scrolling.bar == 'when-searching' and not searching):
|
||||||
css += '\nhtml > ::-webkit-scrollbar { width: 0px; height: 0px; }'
|
css += '\nhtml > ::-webkit-scrollbar { width: 0px; height: 0px; }'
|
||||||
|
|
||||||
return css
|
return css
|
||||||
|
@ -162,8 +162,8 @@ class WebEngineSearch(browsertab.AbstractSearch):
|
|||||||
back yet.
|
back yet.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, tab, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(tab, parent)
|
||||||
self._flags = QWebEnginePage.FindFlags(0)
|
self._flags = QWebEnginePage.FindFlags(0)
|
||||||
self._pending_searches = 0
|
self._pending_searches = 0
|
||||||
|
|
||||||
@ -191,8 +191,11 @@ class WebEngineSearch(browsertab.AbstractSearch):
|
|||||||
flag_text = ''
|
flag_text = ''
|
||||||
log.webview.debug(' '.join([caller, found_text, text, flag_text])
|
log.webview.debug(' '.join([caller, found_text, text, flag_text])
|
||||||
.strip())
|
.strip())
|
||||||
|
|
||||||
if callback is not None:
|
if callback is not None:
|
||||||
callback(found)
|
callback(found)
|
||||||
|
self.finished.emit(found)
|
||||||
|
|
||||||
self._widget.findText(text, flags, wrapped_callback)
|
self._widget.findText(text, flags, wrapped_callback)
|
||||||
|
|
||||||
def search(self, text, *, ignore_case='never', reverse=False,
|
def search(self, text, *, ignore_case='never', reverse=False,
|
||||||
@ -213,6 +216,8 @@ class WebEngineSearch(browsertab.AbstractSearch):
|
|||||||
self._find(text, self._flags, result_cb, 'search')
|
self._find(text, self._flags, result_cb, 'search')
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
|
if self.search_displayed:
|
||||||
|
self.cleared.emit()
|
||||||
self.search_displayed = False
|
self.search_displayed = False
|
||||||
self._widget.findText('')
|
self._widget.findText('')
|
||||||
|
|
||||||
@ -637,14 +642,26 @@ class WebEngineElements(browsertab.AbstractElements):
|
|||||||
|
|
||||||
class WebEngineAudio(browsertab.AbstractAudio):
|
class WebEngineAudio(browsertab.AbstractAudio):
|
||||||
|
|
||||||
"""QtWebEngine implemementations related to audio/muting."""
|
"""QtWebEngine implemementations related to audio/muting.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
_overridden: Whether the user toggled muting manually.
|
||||||
|
If that's the case, we leave it alone.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, tab, parent=None):
|
||||||
|
super().__init__(tab, parent)
|
||||||
|
self._overridden = False
|
||||||
|
|
||||||
def _connect_signals(self):
|
def _connect_signals(self):
|
||||||
page = self._widget.page()
|
page = self._widget.page()
|
||||||
page.audioMutedChanged.connect(self.muted_changed)
|
page.audioMutedChanged.connect(self.muted_changed)
|
||||||
page.recentlyAudibleChanged.connect(self.recently_audible_changed)
|
page.recentlyAudibleChanged.connect(self.recently_audible_changed)
|
||||||
|
self._tab.url_changed.connect(self._on_url_changed)
|
||||||
|
config.instance.changed.connect(self._on_config_changed)
|
||||||
|
|
||||||
def set_muted(self, muted: bool):
|
def set_muted(self, muted: bool, override: bool = False):
|
||||||
|
self._overridden = override
|
||||||
page = self._widget.page()
|
page = self._widget.page()
|
||||||
page.setAudioMuted(muted)
|
page.setAudioMuted(muted)
|
||||||
|
|
||||||
@ -656,6 +673,17 @@ class WebEngineAudio(browsertab.AbstractAudio):
|
|||||||
page = self._widget.page()
|
page = self._widget.page()
|
||||||
return page.recentlyAudible()
|
return page.recentlyAudible()
|
||||||
|
|
||||||
|
@pyqtSlot(QUrl)
|
||||||
|
def _on_url_changed(self, url):
|
||||||
|
if self._overridden:
|
||||||
|
return
|
||||||
|
mute = config.instance.get('content.mute', url=url)
|
||||||
|
self.set_muted(mute)
|
||||||
|
|
||||||
|
@config.change_filter('content.mute')
|
||||||
|
def _on_config_changed(self):
|
||||||
|
self._on_url_changed(self._tab.url())
|
||||||
|
|
||||||
|
|
||||||
class _WebEnginePermissions(QObject):
|
class _WebEnginePermissions(QObject):
|
||||||
|
|
||||||
@ -812,17 +840,23 @@ class _WebEngineScripts(QObject):
|
|||||||
self._greasemonkey = objreg.get('greasemonkey')
|
self._greasemonkey = objreg.get('greasemonkey')
|
||||||
|
|
||||||
def connect_signals(self):
|
def connect_signals(self):
|
||||||
|
"""Connect signals to our private slots."""
|
||||||
config.instance.changed.connect(self._on_config_changed)
|
config.instance.changed.connect(self._on_config_changed)
|
||||||
|
|
||||||
|
self._tab.search.cleared.connect(functools.partial(
|
||||||
|
self._update_stylesheet, searching=False))
|
||||||
|
self._tab.search.finished.connect(self._update_stylesheet)
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def _on_config_changed(self, option):
|
def _on_config_changed(self, option):
|
||||||
if option in ['scrolling.bar', 'content.user_stylesheets']:
|
if option in ['scrolling.bar', 'content.user_stylesheets']:
|
||||||
self._init_stylesheet()
|
self._init_stylesheet()
|
||||||
self._update_stylesheet()
|
self._update_stylesheet()
|
||||||
|
|
||||||
def _update_stylesheet(self):
|
@pyqtSlot(bool)
|
||||||
|
def _update_stylesheet(self, searching=False):
|
||||||
"""Update the custom stylesheet in existing tabs."""
|
"""Update the custom stylesheet in existing tabs."""
|
||||||
css = shared.get_user_stylesheet()
|
css = shared.get_user_stylesheet(searching=searching)
|
||||||
code = javascript.assemble('stylesheet', 'set_css', css)
|
code = javascript.assemble('stylesheet', 'set_css', css)
|
||||||
self._tab.run_js_async(code)
|
self._tab.run_js_async(code)
|
||||||
|
|
||||||
@ -991,16 +1025,16 @@ class WebEngineTab(browsertab.AbstractTab):
|
|||||||
private=private, parent=parent)
|
private=private, parent=parent)
|
||||||
widget = webview.WebEngineView(tabdata=self.data, win_id=win_id,
|
widget = webview.WebEngineView(tabdata=self.data, win_id=win_id,
|
||||||
private=private)
|
private=private)
|
||||||
self.history = WebEngineHistory(self)
|
self.history = WebEngineHistory(tab=self)
|
||||||
self.scroller = WebEngineScroller(self, parent=self)
|
self.scroller = WebEngineScroller(tab=self, parent=self)
|
||||||
self.caret = WebEngineCaret(mode_manager=mode_manager,
|
self.caret = WebEngineCaret(mode_manager=mode_manager,
|
||||||
tab=self, parent=self)
|
tab=self, parent=self)
|
||||||
self.zoom = WebEngineZoom(tab=self, parent=self)
|
self.zoom = WebEngineZoom(tab=self, parent=self)
|
||||||
self.search = WebEngineSearch(parent=self)
|
self.search = WebEngineSearch(tab=self, parent=self)
|
||||||
self.printing = WebEnginePrinting(tab=self)
|
self.printing = WebEnginePrinting(tab=self)
|
||||||
self.elements = WebEngineElements(tab=self)
|
self.elements = WebEngineElements(tab=self)
|
||||||
self.action = WebEngineAction(tab=self)
|
self.action = WebEngineAction(tab=self)
|
||||||
self.audio = WebEngineAudio(parent=self)
|
self.audio = WebEngineAudio(tab=self, parent=self)
|
||||||
self._permissions = _WebEnginePermissions(tab=self, parent=self)
|
self._permissions = _WebEnginePermissions(tab=self, parent=self)
|
||||||
self._scripts = _WebEngineScripts(tab=self, parent=self)
|
self._scripts = _WebEngineScripts(tab=self, parent=self)
|
||||||
# We're assigning settings in _set_widget
|
# We're assigning settings in _set_widget
|
||||||
|
@ -84,8 +84,8 @@ class WebKitSearch(browsertab.AbstractSearch):
|
|||||||
|
|
||||||
"""QtWebKit implementations related to searching on the page."""
|
"""QtWebKit implementations related to searching on the page."""
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, tab, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(tab, parent)
|
||||||
self._flags = QWebPage.FindFlags(0)
|
self._flags = QWebPage.FindFlags(0)
|
||||||
|
|
||||||
def _call_cb(self, callback, found, text, flags, caller):
|
def _call_cb(self, callback, found, text, flags, caller):
|
||||||
@ -115,7 +115,11 @@ class WebKitSearch(browsertab.AbstractSearch):
|
|||||||
if callback is not None:
|
if callback is not None:
|
||||||
QTimer.singleShot(0, functools.partial(callback, found))
|
QTimer.singleShot(0, functools.partial(callback, found))
|
||||||
|
|
||||||
|
self.finished.emit(found)
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
|
if self.search_displayed:
|
||||||
|
self.cleared.emit()
|
||||||
self.search_displayed = False
|
self.search_displayed = False
|
||||||
# We first clear the marked text, then the highlights
|
# We first clear the marked text, then the highlights
|
||||||
self._widget.findText('')
|
self._widget.findText('')
|
||||||
@ -637,7 +641,7 @@ class WebKitAudio(browsertab.AbstractAudio):
|
|||||||
|
|
||||||
"""Dummy handling of audio status for QtWebKit."""
|
"""Dummy handling of audio status for QtWebKit."""
|
||||||
|
|
||||||
def set_muted(self, muted: bool):
|
def set_muted(self, muted: bool, override: bool = False):
|
||||||
raise browsertab.WebTabError('Muting is not supported on QtWebKit!')
|
raise browsertab.WebTabError('Muting is not supported on QtWebKit!')
|
||||||
|
|
||||||
def is_muted(self):
|
def is_muted(self):
|
||||||
@ -658,16 +662,16 @@ class WebKitTab(browsertab.AbstractTab):
|
|||||||
private=private, tab=self)
|
private=private, tab=self)
|
||||||
if private:
|
if private:
|
||||||
self._make_private(widget)
|
self._make_private(widget)
|
||||||
self.history = WebKitHistory(self)
|
self.history = WebKitHistory(tab=self)
|
||||||
self.scroller = WebKitScroller(self, parent=self)
|
self.scroller = WebKitScroller(tab=self, parent=self)
|
||||||
self.caret = WebKitCaret(mode_manager=mode_manager,
|
self.caret = WebKitCaret(mode_manager=mode_manager,
|
||||||
tab=self, parent=self)
|
tab=self, parent=self)
|
||||||
self.zoom = WebKitZoom(tab=self, parent=self)
|
self.zoom = WebKitZoom(tab=self, parent=self)
|
||||||
self.search = WebKitSearch(parent=self)
|
self.search = WebKitSearch(tab=self, parent=self)
|
||||||
self.printing = WebKitPrinting(tab=self)
|
self.printing = WebKitPrinting(tab=self)
|
||||||
self.elements = WebKitElements(tab=self)
|
self.elements = WebKitElements(tab=self)
|
||||||
self.action = WebKitAction(tab=self)
|
self.action = WebKitAction(tab=self)
|
||||||
self.audio = WebKitAudio(parent=self)
|
self.audio = WebKitAudio(tab=self, parent=self)
|
||||||
# We're assigning settings in _set_widget
|
# We're assigning settings in _set_widget
|
||||||
self.settings = webkitsettings.WebKitSettings(settings=None)
|
self.settings = webkitsettings.WebKitSettings(settings=None)
|
||||||
self._set_widget(widget)
|
self._set_widget(widget)
|
||||||
|
@ -312,10 +312,14 @@ class Config(QObject):
|
|||||||
name, deleted=deleted, renamed=renamed)
|
name, deleted=deleted, renamed=renamed)
|
||||||
raise exception from None
|
raise exception from None
|
||||||
|
|
||||||
def get(self, name, url=None):
|
def get(self, name, url=None, *, fallback=True):
|
||||||
"""Get the given setting converted for Python code."""
|
"""Get the given setting converted for Python code.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fallback: Use the global value if there's no URL-specific one.
|
||||||
|
"""
|
||||||
opt = self.get_opt(name)
|
opt = self.get_opt(name)
|
||||||
obj = self.get_obj(name, url=url)
|
obj = self.get_obj(name, url=url, fallback=fallback)
|
||||||
return opt.typ.to_py(obj)
|
return opt.typ.to_py(obj)
|
||||||
|
|
||||||
def _maybe_copy(self, value):
|
def _maybe_copy(self, value):
|
||||||
@ -329,14 +333,14 @@ class Config(QObject):
|
|||||||
assert value.__hash__ is not None, value
|
assert value.__hash__ is not None, value
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def get_obj(self, name, *, url=None):
|
def get_obj(self, name, *, url=None, fallback=True):
|
||||||
"""Get the given setting as object (for YAML/config.py).
|
"""Get the given setting as object (for YAML/config.py).
|
||||||
|
|
||||||
Note that the returned values are not watched for mutation.
|
Note that the returned values are not watched for mutation.
|
||||||
If a URL is given, return the value which should be used for that URL.
|
If a URL is given, return the value which should be used for that URL.
|
||||||
"""
|
"""
|
||||||
self.get_opt(name) # To make sure it exists
|
self.get_opt(name) # To make sure it exists
|
||||||
value = self._values[name].get_for_url(url)
|
value = self._values[name].get_for_url(url, fallback=fallback)
|
||||||
return self._maybe_copy(value)
|
return self._maybe_copy(value)
|
||||||
|
|
||||||
def get_obj_for_pattern(self, name, *, pattern):
|
def get_obj_for_pattern(self, name, *, pattern):
|
||||||
|
@ -806,6 +806,17 @@ content.xss_auditing:
|
|||||||
Suspicious scripts will be blocked and reported in the inspector's
|
Suspicious scripts will be blocked and reported in the inspector's
|
||||||
JavaScript console.
|
JavaScript console.
|
||||||
|
|
||||||
|
content.mute:
|
||||||
|
default: false
|
||||||
|
type: Bool
|
||||||
|
supports_pattern: true
|
||||||
|
desc: >-
|
||||||
|
Automatically mute tabs.
|
||||||
|
|
||||||
|
Note that if the `:tab-mute` command is used, the mute status for the
|
||||||
|
affected tab is now controlled manually, and this setting doesn't have any
|
||||||
|
effect.
|
||||||
|
|
||||||
# emacs: '
|
# emacs: '
|
||||||
|
|
||||||
## completion
|
## completion
|
||||||
@ -1271,9 +1282,15 @@ prompt.radius:
|
|||||||
## scrolling
|
## scrolling
|
||||||
|
|
||||||
scrolling.bar:
|
scrolling.bar:
|
||||||
type: Bool
|
type:
|
||||||
default: false
|
name: String
|
||||||
desc: Show a scrollbar.
|
valid_values:
|
||||||
|
- always: Always show the scrollbar.
|
||||||
|
- never: Never show the scrollbar.
|
||||||
|
- when-searching: Show the scrollbar when searching for text in the
|
||||||
|
webpage. With the QtWebKit backend, this is equal to `never`.
|
||||||
|
default: when-searching
|
||||||
|
desc: When to show the scrollbar.
|
||||||
|
|
||||||
scrolling.smooth:
|
scrolling.smooth:
|
||||||
type: Bool
|
type: Bool
|
||||||
@ -1602,6 +1619,23 @@ tabs.min_width:
|
|||||||
|
|
||||||
This setting does not apply to pinned tabs, unless `tabs.pinned.shrink` is False.
|
This setting does not apply to pinned tabs, unless `tabs.pinned.shrink` is False.
|
||||||
|
|
||||||
|
tabs.max_width:
|
||||||
|
default: -1
|
||||||
|
type:
|
||||||
|
name: Int
|
||||||
|
minval: -1
|
||||||
|
maxval: maxint
|
||||||
|
desc: >-
|
||||||
|
Maximum width (in pixels) of tabs (-1 for no maximum).
|
||||||
|
|
||||||
|
This setting only applies when tabs are horizontal.
|
||||||
|
|
||||||
|
This setting does not apply to pinned tabs, unless `tabs.pinned.shrink` is
|
||||||
|
False.
|
||||||
|
|
||||||
|
This setting may not apply properly if max_width is smaller than the
|
||||||
|
minimum size of tab contents, or smaller than tabs.min_width.
|
||||||
|
|
||||||
tabs.width.indicator:
|
tabs.width.indicator:
|
||||||
renamed: tabs.indicator.width
|
renamed: tabs.indicator.width
|
||||||
|
|
||||||
|
@ -292,6 +292,8 @@ class YamlConfig(QObject):
|
|||||||
self._mark_changed()
|
self._mark_changed()
|
||||||
|
|
||||||
self._migrate_bool(settings, 'tabs.favicons.show', 'always', 'never')
|
self._migrate_bool(settings, 'tabs.favicons.show', 'always', 'never')
|
||||||
|
self._migrate_bool(settings, 'scrolling.bar',
|
||||||
|
'when-searching', 'never')
|
||||||
self._migrate_bool(settings, 'qt.force_software_rendering',
|
self._migrate_bool(settings, 'qt.force_software_rendering',
|
||||||
'software-opengl', 'none')
|
'software-opengl', 'none')
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ from PyQt5.QtGui import QColor, QFont
|
|||||||
from PyQt5.QtWidgets import QTabWidget, QTabBar
|
from PyQt5.QtWidgets import QTabWidget, QTabBar
|
||||||
|
|
||||||
from qutebrowser.commands import cmdutils
|
from qutebrowser.commands import cmdutils
|
||||||
from qutebrowser.config import configexc
|
from qutebrowser.config import configexc, configutils
|
||||||
from qutebrowser.utils import standarddir, utils, qtutils, urlutils, urlmatch
|
from qutebrowser.utils import standarddir, utils, qtutils, urlutils, urlmatch
|
||||||
from qutebrowser.keyinput import keyutils
|
from qutebrowser.keyinput import keyutils
|
||||||
|
|
||||||
@ -149,6 +149,9 @@ class BaseType:
|
|||||||
value: The value to check.
|
value: The value to check.
|
||||||
pytype: A Python type to check the value against.
|
pytype: A Python type to check the value against.
|
||||||
"""
|
"""
|
||||||
|
if value is configutils.UNSET:
|
||||||
|
return
|
||||||
|
|
||||||
if (value is None or (pytype == list and value == []) or
|
if (value is None or (pytype == list and value == []) or
|
||||||
(pytype == dict and value == {})):
|
(pytype == dict and value == {})):
|
||||||
if not self.none_ok:
|
if not self.none_ok:
|
||||||
@ -309,7 +312,9 @@ class MappingType(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
self._validate_valid_values(value.lower())
|
self._validate_valid_values(value.lower())
|
||||||
return self.MAPPING[value.lower()]
|
return self.MAPPING[value.lower()]
|
||||||
@ -367,7 +372,9 @@ class String(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
self._validate_encoding(value)
|
self._validate_encoding(value)
|
||||||
@ -399,7 +406,9 @@ class UniqueCharString(String):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
value = super().to_py(value)
|
value = super().to_py(value)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Check for duplicate values
|
# Check for duplicate values
|
||||||
@ -455,7 +464,9 @@ class List(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, list)
|
self._basic_py_validation(value, list)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
for val in value:
|
for val in value:
|
||||||
@ -534,6 +545,9 @@ class ListOrValue(BaseType):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return [self.valtype.to_py(value)]
|
return [self.valtype.to_py(value)]
|
||||||
except configexc.ValidationError:
|
except configexc.ValidationError:
|
||||||
@ -577,6 +591,7 @@ class FlagList(List):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
vals = super().to_py(value)
|
vals = super().to_py(value)
|
||||||
|
if vals is not configutils.UNSET:
|
||||||
self._check_duplicates(vals)
|
self._check_duplicates(vals)
|
||||||
return vals
|
return vals
|
||||||
|
|
||||||
@ -764,7 +779,9 @@ class Perc(_Numeric):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, (float, int, str))
|
self._basic_py_validation(value, (float, int, str))
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
@ -907,7 +924,9 @@ class QtColor(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
color = QColor(value)
|
color = QColor(value)
|
||||||
@ -936,7 +955,9 @@ class QssColor(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
functions = ['rgb', 'rgba', 'hsv', 'hsva', 'qlineargradient',
|
functions = ['rgb', 'rgba', 'hsv', 'hsva', 'qlineargradient',
|
||||||
@ -981,7 +1002,9 @@ class Font(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if not self.font_regex.fullmatch(value): # pragma: no cover
|
if not self.font_regex.fullmatch(value): # pragma: no cover
|
||||||
@ -1000,7 +1023,9 @@ class FontFamily(Font):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
match = self.font_regex.fullmatch(value)
|
match = self.font_regex.fullmatch(value)
|
||||||
@ -1024,7 +1049,9 @@ class QtFont(Font):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
style_map = {
|
style_map = {
|
||||||
@ -1136,7 +1163,9 @@ class Regex(BaseType):
|
|||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
"""Get a compiled regex from either a string or a regex object."""
|
"""Get a compiled regex from either a string or a regex object."""
|
||||||
self._basic_py_validation(value, (str, self._regex_type))
|
self._basic_py_validation(value, (str, self._regex_type))
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
elif isinstance(value, str):
|
elif isinstance(value, str):
|
||||||
return self._compile_regex(value)
|
return self._compile_regex(value)
|
||||||
@ -1214,7 +1243,9 @@ class Dict(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, dict)
|
self._basic_py_validation(value, dict)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return self._fill_fixed_keys({})
|
return self._fill_fixed_keys({})
|
||||||
|
|
||||||
self._validate_keys(value)
|
self._validate_keys(value)
|
||||||
@ -1256,7 +1287,9 @@ class File(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
value = os.path.expanduser(value)
|
value = os.path.expanduser(value)
|
||||||
@ -1282,7 +1315,9 @@ class Directory(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
value = os.path.expandvars(value)
|
value = os.path.expandvars(value)
|
||||||
value = os.path.expanduser(value)
|
value = os.path.expanduser(value)
|
||||||
@ -1309,7 +1344,9 @@ class FormatString(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -1341,8 +1378,10 @@ class ShellCommand(List):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
value = super().to_py(value)
|
value = super().to_py(value)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
return value
|
return value
|
||||||
|
elif not value:
|
||||||
|
return []
|
||||||
|
|
||||||
if (self.placeholder and
|
if (self.placeholder and
|
||||||
'{}' not in ' '.join(value) and
|
'{}' not in ' '.join(value) and
|
||||||
@ -1365,7 +1404,9 @@ class Proxy(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -1401,7 +1442,9 @@ class SearchEngineUrl(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if not ('{}' in value or '{0}' in value):
|
if not ('{}' in value or '{0}' in value):
|
||||||
@ -1429,7 +1472,9 @@ class FuzzyUrl(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -1463,6 +1508,9 @@ class Padding(Dict):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
d = super().to_py(value)
|
d = super().to_py(value)
|
||||||
|
if d is configutils.UNSET:
|
||||||
|
return d
|
||||||
|
|
||||||
return PaddingValues(**d)
|
return PaddingValues(**d)
|
||||||
|
|
||||||
|
|
||||||
@ -1472,7 +1520,9 @@ class Encoding(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
codecs.lookup(value)
|
codecs.lookup(value)
|
||||||
@ -1529,7 +1579,9 @@ class Url(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
qurl = QUrl.fromUserInput(value)
|
qurl = QUrl.fromUserInput(value)
|
||||||
@ -1545,7 +1597,9 @@ class SessionName(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
if value.startswith('_'):
|
if value.startswith('_'):
|
||||||
raise configexc.ValidationError(value, "may not start with '_'!")
|
raise configexc.ValidationError(value, "may not start with '_'!")
|
||||||
@ -1593,8 +1647,10 @@ class ConfirmQuit(FlagList):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
values = super().to_py(value)
|
values = super().to_py(value)
|
||||||
if not values:
|
if values is configutils.UNSET:
|
||||||
return values
|
return values
|
||||||
|
elif not values:
|
||||||
|
return []
|
||||||
|
|
||||||
# Never can't be set with other options
|
# Never can't be set with other options
|
||||||
if 'never' in values and len(values) > 1:
|
if 'never' in values and len(values) > 1:
|
||||||
@ -1630,7 +1686,9 @@ class TimestampTemplate(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -1654,7 +1712,9 @@ class Key(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -1673,7 +1733,9 @@ class UrlPattern(BaseType):
|
|||||||
|
|
||||||
def to_py(self, value):
|
def to_py(self, value):
|
||||||
self._basic_py_validation(value, str)
|
self._basic_py_validation(value, str)
|
||||||
if not value:
|
if value is configutils.UNSET:
|
||||||
|
return value
|
||||||
|
elif not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -642,6 +642,9 @@ class TabBar(QTabBar):
|
|||||||
# Qt shrink us down. If for some reason (tests, bugs)
|
# Qt shrink us down. If for some reason (tests, bugs)
|
||||||
# self.width() gives 0, use a sane min of 10 px
|
# self.width() gives 0, use a sane min of 10 px
|
||||||
width = max(self.width(), 10)
|
width = max(self.width(), 10)
|
||||||
|
max_width = config.cache['tabs.max_width']
|
||||||
|
if max_width > 0:
|
||||||
|
width = min(max_width, width)
|
||||||
size = QSize(width, height)
|
size = QSize(width, height)
|
||||||
qtutils.ensure_valid(size)
|
qtutils.ensure_valid(size)
|
||||||
return size
|
return size
|
||||||
|
@ -257,7 +257,7 @@ class FakeWebTab(browsertab.AbstractTab):
|
|||||||
self.history = FakeWebTabHistory(self, can_go_back=can_go_back,
|
self.history = FakeWebTabHistory(self, can_go_back=can_go_back,
|
||||||
can_go_forward=can_go_forward)
|
can_go_forward=can_go_forward)
|
||||||
self.scroller = FakeWebTabScroller(self, scroll_pos_perc)
|
self.scroller = FakeWebTabScroller(self, scroll_pos_perc)
|
||||||
self.audio = FakeWebTabAudio()
|
self.audio = FakeWebTabAudio(self)
|
||||||
wrapped = QWidget()
|
wrapped = QWidget()
|
||||||
self._layout.wrap(self, wrapped)
|
self._layout.wrap(self, wrapped)
|
||||||
|
|
||||||
|
@ -480,6 +480,17 @@ class TestConfig:
|
|||||||
conf.set_obj(name, False, pattern=pattern)
|
conf.set_obj(name, False, pattern=pattern)
|
||||||
assert conf.get(name, url=QUrl('https://example.com/')) is False
|
assert conf.get(name, url=QUrl('https://example.com/')) is False
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('fallback, expected', [
|
||||||
|
(True, True),
|
||||||
|
(False, configutils.UNSET)
|
||||||
|
])
|
||||||
|
def test_get_for_url_fallback(self, conf, fallback, expected):
|
||||||
|
"""Test conf.get() with an URL and fallback."""
|
||||||
|
value = conf.get('content.javascript.enabled',
|
||||||
|
url=QUrl('https://example.com/'),
|
||||||
|
fallback=fallback)
|
||||||
|
assert value is expected
|
||||||
|
|
||||||
@pytest.mark.parametrize('value', [{}, {'normal': {'a': 'nop'}}])
|
@pytest.mark.parametrize('value', [{}, {'normal': {'a': 'nop'}}])
|
||||||
def test_get_bindings(self, config_stub, conf, value):
|
def test_get_bindings(self, config_stub, conf, value):
|
||||||
"""Test conf.get() with bindings which have missing keys."""
|
"""Test conf.get() with bindings which have missing keys."""
|
||||||
|
@ -34,7 +34,7 @@ from PyQt5.QtCore import QUrl
|
|||||||
from PyQt5.QtGui import QColor, QFont
|
from PyQt5.QtGui import QColor, QFont
|
||||||
from PyQt5.QtNetwork import QNetworkProxy
|
from PyQt5.QtNetwork import QNetworkProxy
|
||||||
|
|
||||||
from qutebrowser.config import configtypes, configexc
|
from qutebrowser.config import configtypes, configexc, configutils
|
||||||
from qutebrowser.utils import debug, utils, qtutils, urlmatch
|
from qutebrowser.utils import debug, utils, qtutils, urlmatch
|
||||||
from qutebrowser.browser.network import pac
|
from qutebrowser.browser.network import pac
|
||||||
from qutebrowser.keyinput import keyutils
|
from qutebrowser.keyinput import keyutils
|
||||||
@ -274,6 +274,11 @@ class TestAll:
|
|||||||
with pytest.raises(configexc.ValidationError):
|
with pytest.raises(configexc.ValidationError):
|
||||||
meth(value)
|
meth(value)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('none_ok', [True, False])
|
||||||
|
def test_unset(self, klass, none_ok):
|
||||||
|
typ = klass(none_ok=none_ok)
|
||||||
|
assert typ.to_py(configutils.UNSET) is configutils.UNSET
|
||||||
|
|
||||||
def test_to_str_none(self, klass):
|
def test_to_str_none(self, klass):
|
||||||
assert klass().to_str(None) == ''
|
assert klass().to_str(None) == ''
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ class TestTabWidget:
|
|||||||
qtbot.addWidget(w)
|
qtbot.addWidget(w)
|
||||||
monkeypatch.setattr(tabwidget.objects, 'backend',
|
monkeypatch.setattr(tabwidget.objects, 'backend',
|
||||||
usertypes.Backend.QtWebKit)
|
usertypes.Backend.QtWebKit)
|
||||||
|
w.show()
|
||||||
return w
|
return w
|
||||||
|
|
||||||
def test_small_icon_doesnt_crash(self, widget, qtbot, fake_web_tab):
|
def test_small_icon_doesnt_crash(self, widget, qtbot, fake_web_tab):
|
||||||
@ -120,6 +121,19 @@ class TestTabWidget:
|
|||||||
|
|
||||||
benchmark(widget.update_tab_titles)
|
benchmark(widget.update_tab_titles)
|
||||||
|
|
||||||
|
def test_tab_min_width(self, widget, fake_web_tab, config_stub, qtbot):
|
||||||
|
widget.addTab(fake_web_tab(), 'foobar')
|
||||||
|
widget.addTab(fake_web_tab(), 'foobar1')
|
||||||
|
min_size = widget.tabBar().tabRect(0).width() + 10
|
||||||
|
config_stub.val.tabs.min_width = min_size
|
||||||
|
assert widget.tabBar().tabRect(0).width() == min_size
|
||||||
|
|
||||||
|
def test_tab_max_width(self, widget, fake_web_tab, config_stub, qtbot):
|
||||||
|
widget.addTab(fake_web_tab(), 'foobar')
|
||||||
|
max_size = widget.tabBar().tabRect(0).width() - 10
|
||||||
|
config_stub.val.tabs.max_width = max_size
|
||||||
|
assert widget.tabBar().tabRect(0).width() == max_size
|
||||||
|
|
||||||
@pytest.mark.parametrize("num_tabs", [4, 100])
|
@pytest.mark.parametrize("num_tabs", [4, 100])
|
||||||
@pytest.mark.parametrize("rev", [True, False])
|
@pytest.mark.parametrize("rev", [True, False])
|
||||||
def test_add_remove_tab_benchmark(self, benchmark, widget,
|
def test_add_remove_tab_benchmark(self, benchmark, widget,
|
||||||
|
Loading…
Reference in New Issue
Block a user