diff --git a/README.asciidoc b/README.asciidoc index 3ace8f0e6..086eecf28 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -206,6 +206,7 @@ Contributors, sorted by the number of commits in descending order: * Jan Verbeek * Fritz V155 Reichwald * Franz Fellner +* Daryl Finlay * zwarag * xd1le * oniondreams diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index e4d74f247..ac1cfb5b9 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -637,6 +637,7 @@ The format to use for the window title. The following placeholders are defined: * `{title_sep}`: The string ` - ` if a title is set, empty otherwise. * `{id}`: The internal window ID of this window. * `{scroll_pos}`: The page scroll position. +* `{host}`: The host of the current web page. Default: +pass:[{perc}{title}{title_sep}qutebrowser]+ @@ -1153,6 +1154,7 @@ The format to use for the tab title. The following placeholders are defined: * `{index}`: The index of this tab. * `{id}`: The internal tab ID of this tab. * `{scroll_pos}`: The page scroll position. +* `{host}`: The host of the current web page. Default: +pass:[{index}: {title}]+ diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index c246524f7..5feec1e92 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -330,7 +330,7 @@ def data(readonly=False): ('window-title-format', SettingValue(typ.FormatString(fields=['perc', 'perc_raw', 'title', 'title_sep', 'id', - 'scroll_pos']), + 'scroll_pos', 'host']), '{perc}{title}{title_sep}qutebrowser'), "The format to use for the window title. The following " "placeholders are defined:\n\n" @@ -340,7 +340,8 @@ def data(readonly=False): "* `{title_sep}`: The string ` - ` if a title is set, empty " "otherwise.\n" "* `{id}`: The internal window ID of this window.\n" - "* `{scroll_pos}`: The page scroll position."), + "* `{scroll_pos}`: The page scroll position.\n" + "* `{host}`: The host of the current web page."), ('hide-mouse-cursor', SettingValue(typ.Bool(), 'false'), @@ -627,7 +628,7 @@ def data(readonly=False): ('title-format', SettingValue(typ.FormatString( fields=['perc', 'perc_raw', 'title', 'title_sep', 'index', - 'id', 'scroll_pos']), '{index}: {title}'), + 'id', 'scroll_pos', 'host']), '{index}: {title}'), "The format to use for the tab title. The following placeholders " "are defined:\n\n" "* `{perc}`: The percentage as a string like `[10%]`.\n" @@ -637,7 +638,8 @@ def data(readonly=False): "otherwise.\n" "* `{index}`: The index of this tab.\n" "* `{id}`: The internal tab ID of this tab.\n" - "* `{scroll_pos}`: The page scroll position."), + "* `{scroll_pos}`: The page scroll position.\n" + "* `{host}`: The host of the current web page."), ('title-alignment', SettingValue(typ.TextAlignment(), 'left'), diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py index aa18f7997..45508d051 100644 --- a/qutebrowser/mainwindow/tabbedbrowser.py +++ b/qutebrowser/mainwindow/tabbedbrowser.py @@ -161,27 +161,9 @@ class TabbedBrowser(tabwidget.TabWidget): # (e.g. last tab removed) log.webview.debug("Not updating window title because index is -1") return - tabtitle = self.page_title(idx) - widget = self.widget(idx) - - fields = {} - if widget.load_status == webview.LoadStatus.loading: - fields['perc'] = '[{}%] '.format(widget.progress) - else: - fields['perc'] = '' - fields['perc_raw'] = widget.progress - fields['title'] = tabtitle - fields['title_sep'] = ' - ' if tabtitle else '' + fields = self.get_tab_fields(idx) fields['id'] = self._win_id - y = widget.scroll_pos[1] - if y <= 0: - scroll_pos = 'top' - elif y >= 100: - scroll_pos = 'bot' - else: - scroll_pos = '{:2}%'.format(y) - fields['scroll_pos'] = scroll_pos fmt = config.get('ui', 'window-title-format') self.window().setWindowTitle(fmt.format(**fields)) @@ -231,14 +213,8 @@ class TabbedBrowser(tabwidget.TabWidget): Return: The current URL as QUrl. """ - widget = self.currentWidget() - if widget is None: - url = QUrl() - else: - url = widget.cur_url - # It's possible for url to be invalid, but the caller will handle that. - qtutils.ensure_valid(url) - return url + idx = self.currentIndex() + return super().tab_url(idx) def shutdown(self): """Try to shut down all tabs cleanly.""" diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py index 3d0a418a1..ec9fd7fcb 100644 --- a/qutebrowser/mainwindow/tabwidget.py +++ b/qutebrowser/mainwindow/tabwidget.py @@ -22,7 +22,7 @@ import collections import functools -from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QSize, QRect, QTimer +from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QSize, QRect, QTimer, QUrl from PyQt5.QtWidgets import (QTabWidget, QTabBar, QSizePolicy, QCommonStyle, QStyle, QStylePainter, QStyleOptionTab) from PyQt5.QtGui import QIcon, QPalette, QColor @@ -99,19 +99,34 @@ class TabWidget(QTabWidget): def update_tab_title(self, idx): """Update the tab text for the given tab.""" + fields = self.get_tab_fields(idx) + fields['title'] = fields['title'].replace('&', '&&') + fields['index'] = idx + 1 + + fmt = config.get('tabs', 'title-format') + self.tabBar().setTabText(idx, fmt.format(**fields)) + + def get_tab_fields(self, idx): + """Get the tab field data.""" widget = self.widget(idx) - page_title = self.page_title(idx).replace('&', '&&') + page_title = self.page_title(idx) fields = {} + fields['id'] = widget.tab_id + fields['title'] = page_title + fields['title_sep'] = ' - ' if page_title else '' + fields['perc_raw'] = widget.progress + if widget.load_status == webview.LoadStatus.loading: fields['perc'] = '[{}%] '.format(widget.progress) else: fields['perc'] = '' - fields['perc_raw'] = widget.progress - fields['title'] = page_title - fields['index'] = idx + 1 - fields['id'] = widget.tab_id - fields['title_sep'] = ' - ' if page_title else '' + + try: + fields['host'] = self.tab_url(idx).host() + except qtutils.QtValueError: + fields['host'] = '' + y = widget.scroll_pos[1] if y <= 0: scroll_pos = 'top' @@ -121,9 +136,7 @@ class TabWidget(QTabWidget): scroll_pos = '{:2}%'.format(y) fields['scroll_pos'] = scroll_pos - - fmt = config.get('tabs', 'title-format') - self.tabBar().setTabText(idx, fmt.format(**fields)) + return fields @config.change_filter('tabs', 'title-format') def update_tab_titles(self): @@ -205,6 +218,21 @@ class TabWidget(QTabWidget): self.tabBar().on_change() self.tab_index_changed.emit(index, self.count()) + def tab_url(self, idx): + """Get the URL of the tab at the given index. + + Return: + The tab URL as QUrl. + """ + widget = self.widget(idx) + if widget is None: + url = QUrl() + else: + url = widget.cur_url + # It's possible for url to be invalid, but the caller will handle that. + qtutils.ensure_valid(url) + return url + class TabBar(QTabBar): diff --git a/tests/helpers/stubs.py b/tests/helpers/stubs.py index 91519d558..157690f8d 100644 --- a/tests/helpers/stubs.py +++ b/tests/helpers/stubs.py @@ -134,10 +134,12 @@ class FakeQApplication: class FakeUrl: - """QUrl stub which provides .path().""" + """QUrl stub which provides .path(), isValid() and host().""" - def __init__(self, path=None): + def __init__(self, path=None, valid=True, host=None): self.path = mock.Mock(return_value=path) + self.isValid = mock.Mock(returl_value=valid) + self.host = mock.Mock(returl_value=host) class FakeNetworkReply: @@ -222,6 +224,7 @@ class FakeWebView(QWidget): self.scroll_pos = (-1, -1) self.load_status = webview.LoadStatus.none self.tab_id = 0 + self.cur_url = FakeUrl() class FakeSignal: