Hello Qt Forum,
I am currently trying to learn qt via the python pyside6 package.
The project I have chosen to learn qt with is a password trainer that is supposed to ask you for your future password after every screen-unlock so that you can be sure that you can remember that password before you actually start using it.
To listen to screen-unlocks, I am trying to listen to the DBUS org.freedesktop.ScreenSaver/ScreenSaver -> ActiveChanged(bool) signal. Unfortunately this does not seem to work using the Qt-DBUS library.
Using the dbus-monitor, I can see that the signals are actually being sent:
$ dbus-monitor "interface='org.freedesktop.ScreenSaver'"
...
signal time=1761396762.341364 sender=:1.21 -> destination=(null destination) serial=94408 path=/ScreenSaver; interface=org.freedesktop.ScreenSaver; member=ActiveChanged
boolean true
...
signal time=1761396765.026613 sender=:1.21 -> destination=(null destination) serial=94464 path=/ScreenSaver; interface=org.freedesktop.ScreenSaver; member=ActiveChanged
boolean false
My current attempt to listen to this signal looks something like this:
from __future__ import annotations
from PySide6 import QtDBus, QtCore
from PySide6.QtCore import Slot, QObject
from typing import Annotated, get_type_hints
class DBusEventDispatcher(QtCore.QObject):
def __init__(self):
super().__init__()
sessionBus = QtDBus.QDBusConnection.sessionBus()
if not sessionBus.isConnected():
errorMessage = sessionBus.lastError().message()
raise Exception("Cannot connect to DBUS: " + errorMessage)
success = sessionBus.registerService("my_app")
print(success)
success = sessionBus.registerObject(
'/',
'org.freedesktop.ScreenSaver',
self,
QtDBus.QDBusConnection.ExportAllSlots
)
print(success)
mo = self.metaObject()
for m in range(mo.methodOffset(), mo.methodCount()):
print(mo.method(m).methodSignature())
self.iface = QtDBus.QDBusInterface(
"org.freedesktop.ScreenSaver", # Service
"/ScreenSaver", # Path
"org.freedesktop.ScreenSaver", # Interface
sessionBus
)
print(self.iface.isValid())
self.iface.connect(
QtCore.SIGNAL("ActiveChanged(bool)"),
self.ActiveChanged
)
QtCore.QObject.connect(
self.iface,
QtCore.SIGNAL("ActiveChanged(bool)"),
self.ActiveChanged
)
success = sessionBus.connect(
'org.freedesktop.ScreenSaver', # service,
'/ScreenSaver',
'org.freedesktop.ScreenSaver',
'ActiveChanged',
self,
QtCore.SLOT('ActiveChanged(bool)')
)
print(success)
@QtCore.Slot(bool)
def ActiveChanged(self, active: bool):
print("ActiveChanged")
print(active)
... which produces this output when executed:
$ python3 my_app.py
True
True
b'ActiveChanged(bool)'
True
True
But sadly, that is it. When the screen is locked and unlocked (and produces the dbus-monitor output at the top), nothing more happens from the script.
I have already tried other DBUS-libraries and can confirm that at least one of these is actually able to catch that event, but sadly none of these libraries play nice with qt because they all interfere with the main loop in some way or another.
Does anybody know what may be wrong with the script? Is there maybe some debug-flag that I could set to see what is happening inside the python / Qt-DBUS library?
Any other ideas?
Thanks for any help.
$ python3 --version
Python 3.12.3
$ pip3 list
Package Version
------------------ -------
cysystemd 2.0.1
pip 24.0
PySide6_Essentials 6.10.0
shiboken6 6.10.0
systemd 0.17.1
systemd-python 235
$ uname -a
Linux gerrit-framework 6.14.0-112033-tuxedo #33~24.04.1tux1 SMP PREEMPT_DYNAMIC Tue Sep 30 19:33:36 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
$ cat /etc/issue
TUXEDO OS 24.04.3 LTS \l
KDE-Plasma-Version: 6.4.5
KDE-Frameworks-Version: 6.17.0
Qt-Version: 6.8.2
Graphics-Platform: Wayland