PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Qt Signale und Slots über QtDbus



Der Franz
06-08-2010, 22:47
Hallo. Ich lerne hobbymäßig C++ und habe jetzt versucht, ein Programm zu schreiben, dass Amarok steuern kann. Jetzt habe ich versucht, das Signal TrackChange(QVariantMap), dass Amarok bei jedem neuen Lied über den dbus aussendet (glaube ich zumindest), zu benutzen. Die einzige vernünftige Anleitung, die ich dazu gefunden habe, ist die hier (http://wiki.forum.nokia.com/index.php/QtDbus_quick_tutorial). Ich habe also mit qdbusxml2cpp eine Datei dbusplayer.h aus der Datei org.freedesktop.MediaPlayer.player.xml aus dem Amarok-Quellcode erstellt, ein Objekt definiert, und will jetzt mit connect das Signal abfangen.
QObject::connect(dbusplayer, SIGNAL(TrackChange(QVariantMap)), &props, SLOT(track_changed(QVariantMap)));
Das funktioniert aber nicht (Es passiert nichts, wenn Amarok das Signal sendet). Was mache ich falsch?
PS: Ich kann zum Beispiel ein Lied weiterschalten, ich denke also, dass mit dem Objekt so weit alles in Ordnung ist.

anda_skoa
07-08-2010, 11:32
Vielleicht wird das Signal nicht richtig gesendet.

Eines der D-Bus Standardtools, dbus-monitor, ermöglicht das "Anzeigen" der D-Bus Nachrichten.

Sollte in etwa so funktionieren (nicht getestet, eventuell das eine oder andere Filterkriterium weg lassen):



bus-monitor "type='signal',sender='org.mpris.amarok',interface= 'org.freedesktop.MediaPlayer'"


Ciao,
_

Der Franz
07-08-2010, 20:22
Es sieht schon so aus, als ob das Signal gesendet würde.

> dbus-monitor "type='signal',sender='org.mpris.amarok'" | grep TrackChange
signal sender=:1.32 -> dest=(null destination) serial=181 path=/Player; interface=org.freedesktop.MediaPlayer; member=TrackChange
Danach kommt eine Auflistung der Informationen zum neuen Stück.

anda_skoa
08-08-2010, 14:31
Hmm, sieht wirklich OK aus.

Überprüfe mal den Rückgabewert des QObject::connect() Aufrufs und falls das auch "true" ist, nochmal alle D-Bus Parameter, d.h. Servicename, Objektpfad und Interfacename (letzterer steht glaub ich in der generierten Datei).

Ciao,
_

Der Franz
15-08-2010, 19:10
Der Rückgabewert von connect ist true. Bei den Parametern bin ich mir aber nicht so sicher.
Ich habe als Service org.mpris.amarok genommen, als Pfad /Player und als Interface org.freedesktop.MediaPlayer (die Interface steht auch so in der generierten Datei).
Das Objekt dbusplayer hab ich so erzeugt:
dbusPlayer *dbusplayer = new dbusPlayer("org.mpris.amarok", "/Player", QDBusConnection::sessionBus(), 0);
Stimmt das?

anda_skoa
16-08-2010, 12:33
Das sieht alles gut aus, das sollte so funktionieren :(
Probier vielleicht mal ein anderes Signal, oder den nicht so einfachen Weg über QDBusInterface (man kann dort auch auf Signale connecten, Qt erzeugt sie zur Laufzeit).

Ciao,
_

Der Franz
17-08-2010, 20:53
Nein, es funktioniert mit anderen Signalen auch nicht. (Ich habe z.B. CapsChange probiert).
Wie meinst du das mit QDBusInterface? Ich habs auch schon anders probiert, aber es bringt nix:
QDBusConnection::sessionBus().connect("org.mpris.amarok", "/Player", "org.freedesktop.MediaPlayer", "TrackChange", &props, SLOT(track_changed(QVariantMap)));
Es is aber nicht so schlimm wenns nicht geht. Ich kann auch regelmäßig alle Daten abrufen. Auf jeden Fall Danke für die guten Antworten.

Der Franz
17-08-2010, 21:41
Sorry jetzt hab ich glatt was vergessen: Ich hab die generierte Datei verändern müssen, um das ganze zu kompilieren: Erstens hab ich am Ende der Datei dbusplayer.cpp "#include dbusplayer.moc" einfügen müssen (Sonst "undefined reference to vtable for dbusPlayer") und ich hab das struct DBusStatus aus dem Amarok-Quellcode nach dbusplayer.h kopiert, weil der Rückgabewert vom Signal StatusChange von diesem Typ ist. Geht das auch anders?

struct DBusStatus
{
int Play; //Playing = 0, Paused = 1, Stopped = 2
int Random; //Linearly = 0, Randomly = 1
int Repeat; //Go_To_Next = 0, Repeat_Current = 1
int RepeatPlaylist; //Stop_When_Finished = 0, Never_Give_Up_Playing = 1
};
Q_DECLARE_METATYPE(DBusStatus);

undefined
18-08-2010, 16:51
"undefined reference to vtable for dbusPlayer"
Besagt das du eine Klasse in *.pro oder CMakeLists.txt nicht als zu generierende *.moc Datei angegeben hast.
Ausserdem hat QMake ein Problem mit dem NICHT erkennen von Änderungen des Q_OBJECT Macros. (Abhilfe: Aufräumen neu generieren und make ausführen). Oder CMake verwenden ;)

PS: Siehe die Qt Examples "remotecontrolledcar"
PPS: Ein "export QDBUS_DEBUG=1" wirkt manchmal wunder ;)

anda_skoa
19-08-2010, 09:35
Sorry jetzt hab ich glatt was vergessen: Ich hab die generierte Datei verändern müssen, um das ganze zu kompilieren: Erstens hab ich am Ende der Datei dbusplayer.cpp "#include dbusplayer.moc" einfügen müssen (Sonst "undefined reference to vtable for dbusPlayer")


Wie undefined schon geschrieben hat, wird das normalerweise automatisch gehandhabt, in dem die Datei dbusplayer_moc.cpp erzeugt und getrennt kompiliert wird.

Als Alternative kannst du bei qdbusxml2cpp die Option "-m" benutzen, um das include zu generieren.



und ich hab das struct DBusStatus aus dem Amarok-Quellcode nach dbusplayer.h kopiert, weil der Rückgabewert vom Signal StatusChange von diesem Typ ist. Geht das auch anders?


Der Parameter des Signals is (iiii), d.h. eine Struktur mit vier Integers.
Man kann Codegeneratoren über "Annotations" in der XML Beschreibung Hinweise geben, welche Klassen/Structs sie daraus machen sollten (die Signatur würde z.B. auch auf QRect zutreffen).

Man kann das entfernen und dem Generator etwas generisches erzeugen lassen, oder die Annotation auch auf eine eigene Struktur ändern.

Das kopieren ist bei kompatiblen Lizenzen natürlich auch OK :)

Ciao,
_

Der Franz
20-08-2010, 22:20
Also, ich hab die Datei jetzt mit "-m" neugebaut und DBusStatus nach main.cpp verschoben. Es geht immer noch nicht, und mit QDBUS_DEBUG werden zwar alle meine Aufrufe über den dbus gezeigt, aber keine empfangenen Signale. Is aber nicht so schlimm wenn's nicht geht. Das remote controlled car hat mir auch nicht viel weitergeholfen.