Python Forum
[PyQt] How to pass arguments in QDBusConnection connect() method
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyQt] How to pass arguments in QDBusConnection connect() method
#1
I want to execute commands when some dbus signals are fired. Usually, I make a slot for each signals and it work just fine. However, in this case I need to attach signals dynamically, so a single slot must receive an argument in order to handle multiple signals. I was not able to use lambda like I would do for widgets signals. I tried combinations of all the commented approach below, and altough the connect method return True, the message is not delivered to the slot.

#!/usr/bin/python3
import sys
from PyQt5 import QtCore, QtWidgets, QtDBus

SIGNALS = \
{
    "0":
    {
        "description": "Mute speaker on resume",
        "bus": "system", ## todo
        "service": "org.freedesktop.login1",
        "path": "/org/freedesktop/login1",
        "interface": "org.freedesktop.login1.Manager",
        "name": "PrepareForSleep",
        "exec": "amixer -D pulse sset Master mute"
    }
}


class Main(QtCore.QObject):
    def __init__(self, parent):
        super().__init__()
        self.bus = QtDBus.QDBusConnection.systemBus()
        for num in SIGNALS:
            service = SIGNALS[num]["service"]
            path = SIGNALS[num]["path"]
            interface = SIGNALS[num]["interface"]
            name = SIGNALS[num]["name"]
            cmd = SIGNALS[num]["exec"]
            if QtDBus.QDBusConnection.systemBus().interface().isServiceRegistered(service).value():
                # connect(service, path, interface, name, signature, slot)
                #self.bus.connect(service, path, interface, name, "s", self._slot)

                # connect(service, path, interface, name, argumentMatch, signature, slot)
                self.bus.connect(service, path, interface, name, [cmd], "s", self._slot)
                #self.bus.connect(service, path, interface, name, [cmd], "o", self._slot)

    #@QtCore.pyqtSlot()
    #@QtCore.pyqtSlot(object)
    #@QtCore.pyqtSlot(list)
    @QtCore.pyqtSlot(str)
    def _slot(self, cmd):
        print(f"got '{cmd}'")

if __name__== '__main__':
    app = QtWidgets.QApplication(sys.argv)
    daemon = Main(app)
    sys.exit(app.exec_())
Reply
#2
The problem was that the slot is meant to receive arguments from the signal, so in this case a boolean:

#!/usr/bin/python3
import sys
from PyQt5 import QtCore, QtWidgets, QtDBus

class Main(QtWidgets.QMainWindow):
    def __init__(self, parent):
        super().__init__()
        service = "org.freedesktop.login1"
        if QtDBus.QDBusConnection.systemBus().interface().isServiceRegistered(service).value():
            path = "/org/freedesktop/login1"
            interface = "org.freedesktop.login1.Manager"
            name = "PrepareForSleep"
            self.bus = QtDBus.QDBusConnection.systemBus()
            self.bus.connect(service, path, interface, name, self._slot)
            self.bus.connect(service, path, interface, name, "b", self._slotOverloaded)

    @QtCore.pyqtSlot()
    def _slot(self):
        print("Got 'PrepareForSleep' Signal")

    @QtCore.pyqtSlot(bool)
    def _slotOverloaded(self, data):
        print(f"Got '{data}' from 'PrepareForSleep' Signal")

if __name__== '__main__':
    app = QtWidgets.QApplication([])
    daemon = Main(app)
    sys.exit(app.exec_())
Therefore the solution for my problem is to create an object for each signals-command pair:

#!/usr/bin/python3
import sys
from PyQt5 import QtCore, QtWidgets, QtDBus

SIGNALS = \
{
    0:
    {
        "description": "Mute speaker on resume",
        "bus": "system",
        "service": "org.freedesktop.login1",
        "path": "/org/freedesktop/login1",
        "interface": "org.freedesktop.login1.Manager",
        "name": "PrepareForSleep",
        "exec": "amixer -D pulse sset Master mute"
    }
}


class DBusSignalMonitor(QtCore.QObject):
    def __init__(self, parent, signal):
        super().__init__()
        service = signal["service"]
        path = signal["path"]
        interface = signal["interface"]
        name = signal["name"]
        bus = signal["bus"]
        self.cmd = signal["exec"]

        if bus == "session":
            if QtDBus.QDBusConnection.sessionBus().interface().isServiceRegistered(service).value():
                parent.sessionBus.connect(service, path, interface, name, self._slot)
        elif bus == "system":
            if QtDBus.QDBusConnection.systemBus().interface().isServiceRegistered(service).value():
                parent.systemBus.connect(service, path, interface, name, self._slot)

    @QtCore.pyqtSlot()
    def _slot(self):
        print(f"exec '{self.cmd}'")


class DBusDaemon(QtCore.QObject):
    def __init__(self, parent):
        super().__init__()
        self.sessionBus = QtDBus.QDBusConnection.systemBus()
        self.systemBus = QtDBus.QDBusConnection.systemBus()
        self.signals = {}
        for s in SIGNALS:
            self.signals[s] = DBusSignalMonitor(self, SIGNALS[s])


if __name__== '__main__':
    app = QtWidgets.QApplication(sys.argv)
    daemon = DBusDaemon(app)
    sys.exit(app.exec_())
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020