Repository: qutebrowser/qutebrowser

Issue:
Width of pinned tabs in tab-bar flickering
The width of pinned tabs in the tab bar is flickering. This behaviour is seen best when opening a session with pinned tabs.

Steps to reproduce:
```
:open smbc-comics.com
:tab-pin
:open -t xkcd.com
:tab-pin
:open -t about:blank
:session-save test
:session-load test
```
Now while loading the pages, the tab bar is flickering a lot as the pinned tabs often change width.
I expect the pinned tabs to have a fixed width from the beginning and keep this width constant.


```
qutebrowser v1.0.3
Git commit: af93c0fbc-dirty (2017-11-04 17:15:20 +0100)
Backend: QtWebEngine (Chromium 56.0.2924.122)

CPython: 3.6.3
Qt: 5.9.2
PyQt: 5.9

sip: 4.19.3
colorama: no
pypeg2: 2.15
jinja2: 2.9.6
pygments: 2.2.0
yaml: 3.12
cssutils: no
attr: 17.2.0
PyQt5.QtWebEngineWidgets: yes
PyQt5.QtWebKitWidgets: yes
pdf.js: 1.6.210 (/usr/share/javascript/pdf.js/pdf.js)
sqlite: 3.21.0
QtNetwork SSL: OpenSSL 1.0.2l  25 May 2017

Style: Oxygen::Style
Platform: Linux-4.13.11-1-ARCH-x86_64-with-arch, 64bit
Linux distribution: Arch Linux (arch)
Frozen: False
Imported from /home/helch/projects/qutebrowser/qutebrowser
Qt library executable path: /usr/lib/qt/libexec, data path: /usr/share/qt

```


Discussion:
@jgkamat can you take a look?
Hi @helbling, either I don't understand the issue, or I'm not reproducing it. Are you referring to the change of the pinned tab size as the favicon is loaded? Pinned tabs shink to fit their contents, so when the favicon is loaded, the pinned tab must expand to accomodate it. However, that should only happen once per tab as it loads (and the problem you described seemed more severe). We can't allocate space for favicons before-hand since some pages don't have favicons.

[here's a video of me trying to reproduce this, can you tell me if you can see your issue in my video](https://www.youtube.com/watch?v=AOYvIhTVGig&feature=youtu.be)? If not, could you please upload a video of your flickering and/or provide a few more details?
[Here you go](http://helch.ch/tmp/pinned_tabs_width_toggling.mkv)

Looks like much more flickering than yours.

Console output also has some
`libpng warning: iCCP: known incorrect sRGB profile`
in it and some blocked hosts but otherwise nothing.
Hmm, I wonder if this has something to do with the Oxygen style you're using. Can you reproduce it with `--temp-basedir`? What about `--temp-basedir --qt-arg style Fusion`?
Also, if you can only reproduce outside `--temp-basedir`, can you tell me what font (and font size) you are using in the tabbar?
It is still reproducible with `--temp-basedir --qt-arg style Fusion`:
[still on af93c0fbc](http://helch.ch/tmp/pinned_tabs_width_toggling2.mkv)
[newest master commit 4d8ac7486](http://helch.ch/tmp/pinned_tabs_width_toggling3.mkv)
@helbling,

I've made a new branch, [which adds a bunch of default logging information on how the pinned tabs widths are calculated](https://github.com/jgkamat/qutebrowser/tree/jay/debug-tab-widths). Could you try reproducing it again there, and give me a video and the stdout log? I'm trying to figure out which one of the printed values (under minimumTabSizeHintInteral) is flickering on a single tab. You should see something like this:

![2017-11-06-104631_1920x1080_scrot](https://user-images.githubusercontent.com/4349709/32449524-c6deefc0-c2df-11e7-9c4c-0cca9ef95113.png)

It's a ton of logging, but I'm trying to avoid having you do this twice.

For me, the only 'flickering' value is icon_width once, going from 0 -> 16, but I'm hoping there will be a value going up/down in the log for you (since that's what the tabs are doing).
[Here you go](http://helch.ch/tmp/debug_tab_widths.mkv)

hope that helps
That helped a lot, Thanks! The problem seems to be related to calculating the width of the `1` character, but I'm not sure why it would be changing. Maybe the tabs are passing `"1 "` as the title intermittently for some reason, but I've never seen that before...

 would you mind doing it again for me please? Sorry for all this extra debugging... [I've updated that branch so all you should need to do is pull again](https://github.com/jgkamat/qutebrowser/tree/jay/debug-tab-widths).

You should see something like this now:

![2017-11-06-120946_1920x1080_scrot](https://user-images.githubusercontent.com/4349709/32453872-7fecc22a-c2eb-11e7-840d-f340994079a4.png)
[here you go](http://helch.ch/tmp/debug_tab_widths2.mkv)
@helbling it seems that qt is reporting the tab text pre-pended by `&` every so often, thanks so much for the help, I'm going to need a bit of time to figure out why that's happening :smile:.

The-Compiler linked me a few things which are good leads:

- https://riverbankcomputing.com/pipermail/pyqt/2015-October/036503.html
- http://doc.qt.io/qt-5/qshortcut.html#mnemonic
- https://github.com/qutebrowser/qutebrowser/issues/599

thanks again for bearing through all this debugging, it helps a lot! :) 
Like @jgkamat mentioned, this seems to be caused by Qt (sometimes?) adding a `&` to the texts for the keyboard accelerator.

I can see two possibilities:

## Using text flags

We can't pass [text flags](http://doc.qt.io/qt-5/qt.html#TextFlag-enum) (in this case, `Qt::TextShowMnemonic` so the `&` gets interpreted) to [QFontMetrics::width](https://doc.qt.io/qt-5/qfontmetrics.html#width) we're currently using. However, we can switch to getting [QFontMetrics::size](https://doc.qt.io/qt-5/qfontmetrics.html#size) and then get the width of that.

The calculation seems quite different - it looks like `size` gives us the boundingRect, see the width documentation above for how they're different.

However, this seems to be what QTabBar is doing too:

https://github.com/qt/qtbase/blob/3e5dde4766780665c1030003e3af3aefb75c5dbf/src/widgets/widgets/qtabbar.cpp#L1520-L1531

## Remove & ourselves

This means we'd need to strip `&` but not `&&` from the string. Probably the more complicated solution.

Resolving patch:
diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py
--- a/qutebrowser/mainwindow/tabwidget.py
+++ b/qutebrowser/mainwindow/tabwidget.py
@@ -501,8 +501,12 @@ def _minimum_tab_size_hint_helper(self, tab_text: str,
         """
         text = '\u2026' if ellipsis else tab_text
         # Don't ever shorten if text is shorter than the ellipsis
-        text_width = min(self.fontMetrics().width(text),
-                         self.fontMetrics().width(tab_text))
+
+        def _text_to_width(text):
+            # Calculate text width taking into account qt mnemonics
+            return self.fontMetrics().size(Qt.TextShowMnemonic, text).width()
+        text_width = min(_text_to_width(text),
+                         _text_to_width(tab_text))
         padding = config.val.tabs.padding
         indicator_width = config.val.tabs.width.indicator
         indicator_padding = config.val.tabs.indicator_padding


Test patch: