Repository: qutebrowser/qutebrowser

Issue:
Introduce separate font setting for selected tab
In my fork of qutebrowser, I have set the selected tab font to bold; this way it is quicker for the eye to differentiate the selected tab from the rest. I thought that other people might find this ability useful. The idea would be to add a `fonts.tabs.selected` config value (the same idea as `colors.*.selected`), which people can set to whatever font they want (e.g. bold). It is a small change and I would be happy to make a pull request for it. I just want to first make sure that it would be a welcome addition.


Discussion:
I assume you mean this? https://github.com/qutebrowser/qutebrowser/commit/8b9cb2f98883e46ab438d0c469c8f36708fff336

Seems fine to me to add a font setting - though I'm not sure how easy it is, because `TabBar` doesn't use a stylesheet for its font currently. I went digging a bit for why that is:

- 95df8a045ca6febac8ff8da20a2942c81696c288 avoided that stylesheet because of this Qt bug: [[QTBUG-40263] Radio buttons/checkboxes in QWebView broken if using stylesheet in a QTabWidget - Qt Bug Tracker](https://bugreports.qt.io/browse/QTBUG-40263)
- However, that only affects QtWebKit on Windows, so probably really isn't relevant anymore
- Since 2dd8966fdcf11972062c540b7a787e4d0de8d372, we set a stylesheet anyways, and nobody has complained so far

So it'd probably be a good idea to switch to stylesheets for the font entirely instead of using `setFont` for the fonts as part of this change - would you be willing to work on that? To do so, change the type of `fonts.tabs` to `Font` (instead of `QtFont`) and add it to the stylesheet. I *think* no config migration should be needed, because anything that's a valid `QtFont` string should also be valid for `Font`.
Ah, also let me note that keeping `fonts.tabs` and adding `fonts.tabs.selected` won't work, because the latter will shadow the former. You'd probably need to rename `fonts.tabs` to `fonts.tabs.unselected` (or perhaps even `fonts.tabs.{odd,even}`, like with `colors.tabs.{odd,even}`).

Resolving patch:
diff --git a/qutebrowser/config/configfiles.py b/qutebrowser/config/configfiles.py
--- a/qutebrowser/config/configfiles.py
+++ b/qutebrowser/config/configfiles.py
@@ -340,6 +340,10 @@ def migrate(self) -> None:
                                        r'(?<!{)\{title\}(?!})',
                                        r'{current_title}')
 
+        self._migrate_to_multiple('fonts.tabs',
+                                  ('fonts.tabs.selected',
+                                   'fonts.tabs.unselected'))
+
         # content.headers.user_agent can't be empty to get the default anymore.
         setting = 'content.headers.user_agent'
         self._migrate_none(setting, configdata.DATA[setting].default)
@@ -446,6 +450,19 @@ def _migrate_none(self, name: str, value: str) -> None:
                 self._settings[name][scope] = value
                 self.changed.emit()
 
+    def _migrate_to_multiple(self, old_name: str,
+                             new_names: typing.Iterator[str]) -> None:
+        if old_name not in self._settings:
+            return
+
+        for new_name in new_names:
+            self._settings[new_name] = {}
+            for scope, val in self._settings[old_name].items():
+                self._settings[new_name][scope] = val
+
+        del self._settings[old_name]
+        self.changed.emit()
+
     def _migrate_string_value(self, name: str,
                               source: str,
                               target: str) -> None:
diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py
--- a/qutebrowser/mainwindow/tabwidget.py
+++ b/qutebrowser/mainwindow/tabwidget.py
@@ -385,8 +385,13 @@ class TabBar(QTabBar):
 
     STYLESHEET = """
         TabBar {
+            font: {{ conf.fonts.tabs.unselected }};
             background-color: {{ conf.colors.tabs.bar.bg }};
         }
+
+        TabBar::tab:selected {
+            font: {{ conf.fonts.tabs.selected }};
+        }
     """
 
     new_tab_requested = pyqtSignal()
@@ -395,8 +400,6 @@ def __init__(self, win_id, parent=None):
         super().__init__(parent)
         self._win_id = win_id
         self.setStyle(TabBarStyle())
-        self._set_font()
-        config.instance.changed.connect(self._on_config_changed)
         self.vertical = False
         self._auto_hide_timer = QTimer()
         self._auto_hide_timer.setSingleShot(True)
@@ -405,6 +408,9 @@ def __init__(self, win_id, parent=None):
         self.setAutoFillBackground(True)
         self.drag_in_progress = False
         stylesheet.set_register(self)
+        self.ensurePolished()
+        config.instance.changed.connect(self._on_config_changed)
+        self._set_icon_size()
         QTimer.singleShot(0, self.maybe_hide)
 
     def __repr__(self):
@@ -416,8 +422,9 @@ def _current_tab(self):
 
     @pyqtSlot(str)
     def _on_config_changed(self, option: str) -> None:
-        if option == 'fonts.tabs':
-            self._set_font()
+        if option.startswith('fonts.tabs.'):
+            self.ensurePolished()
+            self._set_icon_size()
         elif option == 'tabs.favicons.scale':
             self._set_icon_size()
         elif option == 'tabs.show_switching_delay':
@@ -433,7 +440,9 @@ def _on_config_changed(self, option: str) -> None:
                       "tabs.padding",
                       "tabs.indicator.width",
                       "tabs.min_width",
-                      "tabs.pinned.shrink"]:
+                      "tabs.pinned.shrink",
+                      "fonts.tabs.selected",
+                      "fonts.tabs.unselected"]:
             self._minimum_tab_size_hint_helper.cache_clear()
             self._minimum_tab_height.cache_clear()
 
@@ -506,14 +515,6 @@ def refresh(self):
         # code sets layoutDirty so it actually relayouts the tabs.
         self.setIconSize(self.iconSize())
 
-    def _set_font(self):
-        """Set the tab bar font."""
-        self.setFont(config.val.fonts.tabs)
-        self._set_icon_size()
-        # clear tab size cache
-        self._minimum_tab_size_hint_helper.cache_clear()
-        self._minimum_tab_height.cache_clear()
-
     def _set_icon_size(self):
         """Set the tab bar favicon size."""
         size = self.fontMetrics().height() - 2


Test patch:
diff --git a/tests/unit/config/test_configfiles.py b/tests/unit/config/test_configfiles.py
--- a/tests/unit/config/test_configfiles.py
+++ b/tests/unit/config/test_configfiles.py
@@ -588,6 +588,17 @@ def test_font_default_family(self, yaml, autoconfig, old, new):
     def test_font_replacements(self, migration_test, setting, old, new):
         migration_test(setting, old, new)
 
+    def test_migrate_multiple(self, yaml, autoconfig):
+        val = '10pt default_family'
+        autoconfig.write({'fonts.tabs': {'global': val}})
+
+        yaml.load()
+        yaml._save()
+
+        data = autoconfig.read()
+        assert data['fonts.tabs.unselected']['global'] == val
+        assert data['fonts.tabs.selected']['global'] == val
+
 
 class ConfPy: