Commit Graph

25777 Commits

Author SHA1 Message Date
owl 37e10da4fa
#8547: disable discard state by default 2025-12-20 16:48:50 +01:00
owl fb85d47eac
#8547: address comments 2025-12-20 16:00:29 +01:00
toofar f73f651f7c
Switch to two lifecycle state timers
The previous implementation of the lifecycle timer had one timer that we
would change based on what state were were heading into. Because we
connected a new function to it every time we had to disconnect previous
connections before using it again which was a bit awkward, it raised a
TypeError if there were no connections, which isn't very specific.

This commit is an attempt to switch to using two timers, each with their
own callback.

I took a stateless/idempotent approach where the logic doesn't know what
state it might have been in previously so needs to stop any timers that
might be set each time, and needs to check if the timer it wants to set
is already active. Potentially the line count could be reduced by
encoding a bit more state in the logic. But hopefully it's simpler to
maintain like this.

Since I had need to (potentially) stop the timers at several points in
the logic, I pulled that out to a helper function which is where most of
the complexity is now. I tried to make the helper function a little more
dynamic by using a dict lookup to get the new timer and a loop to
reactive the old one. This didn't really add much, I think it's a
slightly higher line count, and probably a little harder to parse. The
previous implementation just looked a bit repetitive and hard to scan
over:

    to_start = delay = None
    if state == QWebEnginePage.LifecycleState.Frozen:
        to_start = self._lifecycle_timer_freeze
        self._lifecycle_timer_discard.stop()
        delay = config.val.qt.chromium.lifecycle_state_freeze_delay
    elif state == QWebEnginePage.LifecycleState.Discarded:
        self._lifecycle_timer_freeze.stop()
        to_start = self._lifecycle_timer_discard
        delay = config.val.qt.chromium.lifecycle_state_discard_delay
    elif state == None:
        self._lifecycle_timer_freeze.stop()
        self._lifecycle_timer_discard.stop()
    else:
        raise utils.Unreachable(recommended_state)

    if to_start and not to_start.isActive() and delay != -1:
        log.webview.debug(f"Scheduling recommended lifecycle change {delay=} {state=} tab={self}")
        to_start.start(delay)

I re-worked the logic of the `_on_recommended_state_changed()` changed
function a little. Not moving into the `Active` state is done immediately
instead of via a 0ms timer. So it's more like an guard clause and early
exit. I think it flows a little better now with all the decisions layed
out clearly and acted on one at a time instead of having the disabled
check right at the start but still proceeding through the function in
one case.
2025-12-17 01:06:51 +01:00
toofar 38d9469846
s/spy/mock/g
The meaning of the terms mock/stub/spy can differ accross languages,
projects and frameworks. Python doesn't have a super consistent
terminology but often a "spy" won't prevent a real object being called
by default, but will let you verify that a method was called. In this
case I'm preventing the `setLifecycleState()` method from being called
at all. So calling it a spy is a bit misleading. The reason I'm
preventing it being called is because I feel like calling into the real
browser code isn't essential for these tests and could complicated the
ideally simple unit tests

This commit renames it to be called a mock, which is hopefully more
clear.

These xunit docs has a decent overview of the various different terms
like mock/stub/spy: http://xunitpatterns.com/Test%20Double.html
2025-12-17 01:06:50 +01:00
toofar ae17b47b71
fixup! Add test coverage for page lifecycle states 2025-12-17 01:06:50 +01:00
toofar 734b30f7d1
Update min/max values for lifecycle settings
It doesn't make sense to allow setting these to negative values, so lets
help the user out by refusing to do so if they try.

But leave `-1` as an allowed value for the "discard" option so users can
have "freeze" enabled but turn the discard state off.

Remove the mention of -1 from the freeze setting since we don't allow
that anymore.
2025-12-17 01:06:50 +01:00
toofar fec97696ae
Restrict page lifecycle feature to Qt6.5+
There is some weirdness preventing us from connecting to the
`QWebEnginePage.recommendedStateChanged` on WebEngine 6.4 and below. We
get this message from QT:

    qt.core.qobject.connect: QObject::connect: No such signal WebEnginePage::recommendedStateChanged(QWebEnginePage::LifecycleState)

and this message from PyQt:

    TypeError: connect() failed between recommendedStateChanged(QWebEnginePage::LifecycleState) and _on_recommended_state_changed()

We couldn't get to the root of it, but we shouldn't have a pressing need
to support this on older versions anyway since later Qt versions are
already widespread.
2025-12-17 01:06:50 +01:00
toofar 7105003a7d
cover all members of the LifecycleState enum 2025-12-17 01:06:50 +01:00
toofar cf29f305e1
Don't apply lifecycle rules to pinned tabs
I want to make sure tabs in the background that might show notifications
or update their favicons or whatever can keep running if I want them to,
and not get frozen. Previous iterations of this feature have re-used the
pinned state to demark tabs that shouldn't be frozen. So that's what
I've implemented here. What could go wrong?

If kept the same "do act on the state change if we are transitioning to
an active state" check from the top of the function for consistency, but
neither check is needed. Qt will put tabs into the Active state when
they are shown without anything needed from our code.

I also haven't implemented a lifecycle change when you un-pin a tab.
It'll get picked up when you switch away from the tab.
2025-12-17 01:06:50 +01:00
toofar bf9df26538
Support disabling a lifecycle state by setting a delay of -1
This is inspired by previous iterations of this feature. Discarding a
page can lose information on the page, for example, if you go to
duckduckgo.com and put some text in the search box, then switch to a
different tab and wait for the ddg tab to be discarded, when you switch
back to the ddg tab the search box will be empty.

Until a point where we have more sophisticated controls of what sites
these transitions apply to, it may be useful for users to disable the
discard state completely. I know that's how I've had the lazier loading
implementation set up for years.

Negative numbers would previously have raised a warning on every state
transition where the time complained that negative numbers weren't
supported.
2025-12-17 01:06:50 +01:00
toofar 0d73ca833a
Tweak _on_recommended_state_changed log message
I was looking at the logs to verify this behavior and I thought this
message could be a little clearer. It didn't mention the tab being acted
on (important when tying together logs across signal firings and with
multiple tabs open) and I switched it to be in logfmt instead of a
whole sentence for ease of parsing.

I also added a `if current == new: return` check, again because of the
logs. Having log messages that won't have any effect probably aren't
needed, and I was confusing them with the important logs.

Unfortunately exciting early means we don't connect new signals, so next
time we come through there is nothing to disconnect. Which makes the
`disconnect()` call grumpy. TypeError is not a super meaningful error to
be throwing here, but I assume that's a result of the python and c++
integration. If the signal was connected to a slot we could
unambiguously disconnect just that one slot, but it's anonymous
currently so we'll see how this goes.
2025-12-17 01:06:50 +01:00
toofar 906ebb0470
Add test coverage for page lifecycle states
I tried to add most of them as "unit" tests (but with a real tab). For
testing that the lifecycle state actually changes though we need an
integration tests, but the tab won't change state if it's focused, and
the unit tests don't have a tab widget.
2025-12-17 01:06:50 +01:00
owl 552908cd67
use recommended page lifecycle state
Lets the browser engine freeze or discard inactive tabs, reducing resource consumption
and increasing battery life.
2025-12-17 01:06:50 +01:00
dependabot[bot] b417f2a23b build(deps): bump peter-evans/create-pull-request from 7 to 8
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 7 to 8.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v7...v8)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-16 12:51:26 +01:00
dependabot[bot] 615cee7309 build(deps): bump actions/upload-artifact from 5 to 6
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-16 12:51:19 +01:00
dependabot[bot] 65c1ca9691 build(deps): bump actions/cache from 4 to 5
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-16 12:51:09 +01:00
qutebrowser bot 12bed611c5 Update dependencies 2025-12-15 17:05:29 +01:00
Florian Bruhin bc72687d7d Update changelog URLs 2025-12-08 16:55:52 +01:00
Florian Bruhin c32b7d4b60 Fix dependency update issues 2025-12-08 10:53:13 +01:00
qutebrowser bot 3f9ef123e7 Update dependencies 2025-12-08 04:29:09 +00:00
Florian Bruhin f2547f8a09 scripts: Make smoke test fail output less confusing 2025-11-30 18:46:03 +01:00
qutebrowser bot edd5114492 Release v3.6.3
(cherry picked from commit ee13dac738)
2025-11-30 17:37:53 +00:00
Florian Bruhin 184a242937 ci: Make sure git knows the main branch
Something seems to have changed about how sparse checkouts are done on GHA, so the main branch isn't found.
2025-11-30 18:35:05 +01:00
Florian Bruhin 17c19a09b7 build_release: Try to get more information on crashes
Currently CI crashes on macOS, but without any useful logs.
2025-11-30 18:11:25 +01:00
Florian Bruhin 88aa47c377 Add qt.workarounds.disable_accessibility setting
This disables accessibility with Qt 6.10.1, which
causes frequent segfaults.

Closes #8797
2025-11-30 17:54:33 +01:00
dependabot[bot] 0570545342 build(deps): bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-30 00:15:59 +01:00
qutebrowser bot f408f20ad9 Release v3.6.2
(cherry picked from commit b2c5d5fa0d)
2025-11-27 20:57:13 +00:00
Florian Bruhin 500a8df209 Update user agents 2025-11-27 21:55:44 +01:00
Florian Bruhin 13d9904b90 Update changelog for v3.6.2 2025-11-27 21:29:21 +01:00
Florian Bruhin b3e4dba731 qtargs: Remove old workaround with Qt 6.10.1 2025-11-27 21:28:34 +01:00
qutebrowser bot 4164205663 Update dependencies 2025-11-27 17:21:32 +01:00
qutebrowser bot f5e2660890 Update dependencies 2025-11-24 16:37:39 +01:00
Florian Bruhin 69f3882ce3 tests: Skip hangouts extension test on Qt 5 2025-11-23 11:42:49 +01:00
Florian Bruhin 8e42727d31 Update changelog 2025-11-22 10:40:30 +01:00
Florian Bruhin 31a5737c61 Avoid disabling off-the-record profile Hangouts extension with Qt 6.10.1
Otherwise this results in a crash, see #8785
2025-11-22 10:38:46 +01:00
Florian Bruhin 8ae5e3d83b version: Use correct profile for extension list
See #8785
2025-11-21 22:50:52 +01:00
Florian Bruhin 4f40a8b46b tests: Improve test_version output 2025-11-21 18:39:24 +01:00
Florian Bruhin 59a64af67f tests: Adjust permissions storage workaround for Qt 6.10.1 2025-11-21 18:35:03 +01:00
Florian Bruhin 66cbe0d9c9 Add QtWebEngine 6.10.1 security patch version 2025-11-21 18:31:43 +01:00
Florian Bruhin 0ef5053a65 tests: Stabilize flaky session scrolling test
Equivalent of d8079515fa
See #5390
2025-11-18 15:00:20 +01:00
qutebrowser bot 6ddff3ae0d Update dependencies 2025-11-18 14:08:13 +01:00
Florian Bruhin 9316d428ef ci: Drop Archlinux Qt 5 images/jobs
For now, Qt 5 is still tested via the Qt 5.15 PyPI wheels.

See https://github.com/qutebrowser/qutebrowser/issues/8417#issuecomment-3495979318
https://lists.archlinux.org/archives/list/arch-dev-public@lists.archlinux.org/thread/U45C4RAW4IXVLO376XGFNLEGGFFXCULV/
2025-11-11 09:13:30 +01:00
Florian Bruhin 71ed8cdbf5 Update changelog 2025-11-11 09:09:05 +01:00
Florian Bruhin 62fdb15532 Merge commit 'bc191b798' 2025-11-11 09:07:00 +01:00
Florian Bruhin bc191b798d wmname: Remove trivial functions 2025-11-11 09:06:49 +01:00
Florian Bruhin f8fbb0609f Update changelog 2025-11-11 08:46:36 +01:00
Florian Bruhin 55fb26fce1 Revert "fix: change fullscreen state when switching tab"
This reverts commit b89bf07d1e.

This turned out to be annoying when enabling fullscreen manually and then
switching through tabs.
2025-11-11 08:45:55 +01:00
Jan Palus 25dc019886
Unify librarry loading for X11/Wayland wmname
libwayland-client.so is development symlink used during linking and there's no need to
have it installed (usually shipped in -devel/-dev packages) on user's machines. Instead
of hardcoding library file name, use same mechanism as in libX11 which let's Python
figure the details and share common logic between X11 and Wayland.

Fixes #8771
2025-11-11 00:51:05 +01:00
Florian Bruhin 81d7b6a74c tests: Use star-unpacking instead of itertools.chain
pytest will soon deprecate using a non-collection iterable in parametrize:
https://docs.pytest.org/en/latest/deprecations.html#parametrize-iterators
2025-11-10 13:02:26 +01:00
qutebrowser bot 6ec5504ab3 Update dependencies 2025-11-10 07:39:05 +01:00