v0.20.6: one press, sixteen hundred songs
A single Right-arrow press skipped 1,676 tracks in 81 s and hard-froze the desktop. On Wayland key repeat is generated by the client until the compositor delivers the release, and the key filter treated every repeat as a new press. Each skip sent gnome-shell an MPRIS Metadata whose xesam:artist was a plain Python list, which marshals as "av" instead of "as". gnome-shell logged an error for every one (50k/min) and reloaded the cover, and that load is what kept it from ever delivering the release. Space/Left/Right now act once per press and swallow the repeats. xesam:artist goes out through mpris.string_array, which build_properties_changed now shares for invalidated_properties. The new test round-trips the signal into GDBus, which is what gnome-shell validates with, and fails 'av' == 'as' against the old code.
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
"""LinTunes — iTunes-style music library manager and player for Linux."""
|
||||
|
||||
__version__ = "0.20.5"
|
||||
__version__ = "0.20.6"
|
||||
|
||||
@@ -1626,6 +1626,15 @@ class MainWindow(QMainWindow):
|
||||
QAbstractSpinBox, QComboBox)):
|
||||
return False
|
||||
key = event.key()
|
||||
if key in (Qt.Key.Key_Space, Qt.Key.Key_Right, Qt.Key.Key_Left) \
|
||||
and event.isAutoRepeat():
|
||||
# On Wayland key repeat is generated client-side until the
|
||||
# compositor delivers the release — and a compositor busy
|
||||
# with our own MPRIS churn delivers it late, so one held
|
||||
# arrow became 1,676 track skips (Round 56). A transport key
|
||||
# acts once per press; the repeats are swallowed so they
|
||||
# don't fall through and move the table's cursor either.
|
||||
return True
|
||||
if key == Qt.Key.Key_Space:
|
||||
self._log_key(event, "space")
|
||||
self.play_pause()
|
||||
|
||||
+20
-6
@@ -259,7 +259,7 @@ class MprisPlayerAdaptor(QDBusAbstractAdaptor):
|
||||
meta = {
|
||||
"mpris:trackid": QDBusObjectPath(f"/org/lintunes/track/{track.track_id}"),
|
||||
"xesam:title": track.name or "",
|
||||
"xesam:artist": [track.artist or ""],
|
||||
"xesam:artist": string_array([track.artist or ""]),
|
||||
"xesam:album": track.album or "",
|
||||
}
|
||||
if track.total_time:
|
||||
@@ -275,17 +275,31 @@ class MprisPlayerAdaptor(QDBusAbstractAdaptor):
|
||||
QDBusConnection.sessionBus().send(build_properties_changed(changed))
|
||||
|
||||
|
||||
def string_array(values) -> QDBusArgument:
|
||||
"""A D-Bus string array ("as"). A plain Python list of str marshals as
|
||||
"av", which GDBus consumers validate and reject — see
|
||||
build_properties_changed and xesam:artist in _metadata."""
|
||||
string_id = QMetaType(QMetaType.Type.QString.value).id()
|
||||
arg = QDBusArgument()
|
||||
arg.beginArray(string_id)
|
||||
for value in values:
|
||||
arg.add(value, string_id)
|
||||
arg.endArray()
|
||||
return arg
|
||||
|
||||
|
||||
def build_properties_changed(changed: dict) -> QDBusMessage:
|
||||
"""A spec-correct Properties.PropertiesChanged signal for the Player
|
||||
interface. invalidated_properties must be marshalled as a D-Bus string
|
||||
array ("as"); a plain Python [] goes over as "av", and GDBus consumers —
|
||||
including gsd-media-keys, which keys its media-key MRU on seeing
|
||||
PlaybackStatus change — validate the signature and drop the signal.
|
||||
(Same pitfall as reveal_paths in track_table.)"""
|
||||
(Same pitfall as reveal_paths in track_table, and as xesam:artist inside
|
||||
Metadata: sent as "av", gnome-shell logged an error and reloaded the
|
||||
cover per track change, and during a runaway key repeat that flood is
|
||||
what froze the desktop — Round 56.)"""
|
||||
msg = QDBusMessage.createSignal(
|
||||
OBJECT_PATH, "org.freedesktop.DBus.Properties", "PropertiesChanged")
|
||||
invalidated = QDBusArgument()
|
||||
invalidated.beginArray(QMetaType(QMetaType.Type.QString.value).id())
|
||||
invalidated.endArray()
|
||||
msg.setArguments(["org.mpris.MediaPlayer2.Player", changed, invalidated])
|
||||
msg.setArguments(["org.mpris.MediaPlayer2.Player", changed,
|
||||
string_array([])])
|
||||
return msg
|
||||
|
||||
Reference in New Issue
Block a user