A zero-duration ViewTransition still engages ListView's transition
machinery but resolves within the same frame, so removed delegates are
never released and displaced items are never repositioned. On a filtered
ScriptModel that re-filters on every keystroke this leaves stale rows and
empty gaps behind, visible in any DankListView-backed list.
The shortest sub-duration (remove/add = expressiveDurations.fast =
base * 0.4) is coerced to an int, so it truncates to 0ms for any
animation base duration below 3: animation speed None (0), or a Custom
duration of 1-2ms (1*0.4=0.4->0, 2*0.4=0.8->0, only 3*0.4=1.2->1
survives). Presets (250/500/750) are unaffected, which is why this only
reproduces with animations disabled or a very small custom value.
Gate the four transitions to null whenever that shortest sub-duration
would truncate to 0, so the view takes the correct instant path instead
of a broken 0ms transition. Base >= 3 is unchanged.
This makes it easier for distros to use the Makefile when creating
packages. It enables us to specify a base destination directory to
install the project files to. E.g., on Solus, when creating eopkgs, files
must be installed to a special directory path, which becomes the package
files. I believe Fedora packages, and others, are the same.
Signed-off-by: Evan Maddock <maddock.evan@vivaldi.net>
The notification popup's close button (X), action button clicks, and the
cardClick body's else branch all set notificationData.popup = false
directly. This relies on wrapperConn.onPopupChanged firing startExit(),
which can be interrupted by four races:
1. enterDelay (160 ms Timer) starts notificationData.timer after the
user clicks, on an already-orphan wrapper.
2. The dismiss Timer keeps running post-click and flips popup again.
3. wrapperConn.target is set imperatively in onNotificationDataChanged
(line 293) and may be stale after NotificationPopupManager._sync()
reorders wrappers.
4. exiting or _isDestroying stuck true gates wrapperConn.enabled.
Introduce a single helper dismissPopupReliably() that stops the timer,
sets popup = false, and kicks off startExit() via Qt.callLater as a
belt-and-suspenders fallback. Apply to the three vulnerable handlers.
This matches the existing upstream pattern used in the hover, contextMenu,
and Component.onDestruction paths (which all stop the timer before
mutating popup state).
Closes#2760