Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create KDE tray notification in a C++ program?

I have a C++ program (that uses Qt), and I want to create a tray notification with a progress bar. I think Qt can show text notifications, but not progress bar - that's KDE-specific. I can't find any example of managing KDE tray notifications in C++. Any advice?

P. S. Here's what I mean:

enter image description here

like image 693
Violet Giraffe Avatar asked May 04 '14 15:05

Violet Giraffe


3 Answers

I was wondering the same thing, and I spent some time investigating. Here are the results:

Introduction

That progress bar is a special feature of kde that's not linked to libnotify at all. It is provided by a component called kuiserver, and it is meant to display progress of file transfert, though it can be used for other things.

There are two ways

KJob

The first way is to talk to kuiserver in the KDE API, and it's by using KUiServerJobTracker with a KJob. I haven't tried myself, but I guess you should subclass KJob, and pass an instance of your subclass to KUiServerJobTracker.

dbus

You can also talk directly to the kuiserver through dbus, which is what I tried. I used qdbusviewer to explore the API provided by kuiserver. I wanted to show an example of interaction with the command-line tool qdbus, but I couldn't get it to work. If you plan to do this, you probably should use the QDBus library.

What is interesting to us is the /JobViewServer path in the org.kde.kuiserver service. The method we want to call is org.kde.JobViewServer.requestView, which creates a new dbus path for this job, and returns it. For example, I just called requestView with dummy arguments, and got ObjectPath: /JobViewServer/JobView_29 in return. In the meantime, a progress indicator has just started rotating in my tray:

I can now use the content of that path. Here, qdbus worked, so here is the list of the methods:

$ qdbus org.kde.kuiserver /JobViewServer/JobView_29
signal void org.kde.JobViewV2.cancelRequested()
method Q_NOREPLY void org.kde.JobViewV2.clearDescriptionField(uint number)
signal void org.kde.JobViewV2.resumeRequested()
method bool org.kde.JobViewV2.setDescriptionField(uint number, QString name, QString value)
method Q_NOREPLY void org.kde.JobViewV2.setDestUrl(QDBusVariant destUrl)
method Q_NOREPLY void org.kde.JobViewV2.setInfoMessage(QString message)
method Q_NOREPLY void org.kde.JobViewV2.setPercent(uint percent)
method Q_NOREPLY void org.kde.JobViewV2.setProcessedAmount(qulonglong amount, QString unit)
method Q_NOREPLY void org.kde.JobViewV2.setSpeed(qulonglong bytesPerSecond)
method Q_NOREPLY void org.kde.JobViewV2.setSuspended(bool suspended)
method Q_NOREPLY void org.kde.JobViewV2.setTotalAmount(qulonglong amount, QString unit)
signal void org.kde.JobViewV2.suspendRequested()
method Q_NOREPLY void org.kde.JobViewV2.terminate(QString errorMessage)
method QDBusVariant org.freedesktop.DBus.Properties.Get(QString interface_name, QString property_name)
method QVariantMap org.freedesktop.DBus.Properties.GetAll(QString interface_name)
method void org.freedesktop.DBus.Properties.Set(QString interface_name, QString property_name, QDBusVariant value)
method QString org.freedesktop.DBus.Introspectable.Introspect()
method QString org.freedesktop.DBus.Peer.GetMachineId()
method void org.freedesktop.DBus.Peer.Ping()

I'll let you guess and experiment to find what those do, but here is a small example:

# Give it a name, in case we open the tooltip
qdbus org.kde.kuiserver /JobViewServer/JobView_29 setInfoMessage "Example progress"
# Update the progress
qdbus org.kde.kuiserver /JobViewServer/JobView_29 setPercent 50
# End it
qdbus org.kde.kuiserver /JobViewServer/JobView_29 terminate "Some error message"

Conclusion

You should have enough to create a progress bar in the tray with kde. I hope this'll be useful to you. Anyway, I had fun finding this out (including diving in some kde applications code to find out how the progress notification was done), and I'll probably write something that uses this.

like image 68
madjar Avatar answered Oct 17 '22 22:10

madjar


You can use QxtToolTip which is a class in Qxt. It enabales you to show any arbitrary widget as a tooltip. So i think you can create your custom widget and show it using QxtToolTip in the proper position. You can use this static function:

void QxtToolTip::show ( const QPoint & pos, QWidget * tooltip, QWidget * parent = 0, const QRect & rect = QRect() )   [static]

It can be like:

#include <QxtToolTip>

MyCustomWidget widget;
QPoint myPosition(x,y);
QxtToolTip::show ( &myPosition, &widget, parent);
like image 38
Nejat Avatar answered Oct 18 '22 00:10

Nejat


To get in the system tray you want to use KStatusNotifierItem and for the notifications you'll want to take a look at the KNotifications framework.

like image 1
Aleix Avatar answered Oct 17 '22 22:10

Aleix