Qt application for Maemo with DBus support
Article Metadata
Introduction
Let's create typical Debian package containing minimalistic Qt Maemo application Detailed description. You will end up with source tree something like this:
$ tree
.
|-- data
| |-- sample.desktop
| `-- sample.png
|-- debian
| |-- changelog
| |-- compat
| |-- control
| `-- rules
|-- sample.pro
`-- src
|-- main.cpp
|-- mainwindow.cpp
|-- mainwindow.h
`-- src.pro
If you've done everything correctly you will get application integrated into Task launcher menu. But soon you will notice that you can open unlimited number of instances of your application. You can verify that all pre-installed applications effectively limit number of instances to one.
DBus integration
At first you need to modify .desktop file:
[Desktop Entry]
Encoding=UTF-8
Version=0.1
Type=Application
Name=Sample
Exec=/usr/bin/sample
Icon=sample
X-Maemo-Category=Main
X-Window-Icon=sample
X-Window-Icon-Dimmed=sample
X-Osso-Service=org.indt.sample
The line we added was
X-Osso-Service=org.indt.sample
It tells the desktop what is DBus service name of our application. Then we would need to tell DBus how to start your application. More details about that you can learn from Introduction to DBus activation Create org.indt.sample.service file in data/ directory:
# Service description file
[D-BUS Service]
Name=org.indt.sample
Exec=/usr/bin/sample
Installation instructions go to src/src.pro
service.path = $$DATADIR/dbus-1/services
service.files += ../data/org.indt.sample.service
We also need to signal qmake that we are using QDBus in our application, so add the following to src/src.pro:
CONFIG += qdbus
Now we need to register Service and Object name on application startup. To achieve this we can add following code to main.cpp.
Include:
#include <QtDBus>And in the main function:
if (!QDBusConnection::sessionBus().isConnected()) {
qWarning("Cannot connect to the D-Bus session bus.");
exit(1);
}
if (!QDBusConnection::sessionBus().registerService("org.indt.sample")) {
qWarning("%s", qPrintable(QDBusConnection::sessionBus().lastError().
message()));
exit(2);
}
if (!QDBusConnection::sessionBus().registerObject("/org/indt/sample", &win,
QDBusConnection::ExportScriptableSlots)) {
qWarning("%s", qPrintable(QDBusConnection::sessionBus().lastError().
message()));
exit(3);
}
Registering Service will give a name to your application on the DBus bus and registering a object will register methods application can serve.
We need to implement actually only one method top_application without parameters and integer return value. This method call is used by Hildon Desktop to let our application know, when it should show UI.
In mainwindow.h we define class info for DBus, method call and close event handler.
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QCloseEvent>
class MainWindow : public QMainWindow
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.indt.sample")
public:
MainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
public slots:
Q_SCRIPTABLE int top_application();
private:
void closeEvent(QCloseEvent *event);
};
#endif // MAINWINDOW_H
Our primitive and straightforward plan is to hide UI on closeEvent and show it on top_application call. mainwindow.cpp:
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags)
: QMainWindow(parent, flags)
{
}
void MainWindow::closeEvent(QCloseEvent *event)
{
hide();
event->ignore();
}
/* Hildon desktop makes a call to DBus method top_application,
when you tap application icon in a task launcher, if application is already running. */
int MainWindow::top_application()
{
show();
return 0;
}
Note, that this is not the only possible solution. You can achieve similar results using osso_initialize() and osso_application_set_top_cb() from libosso API.


(no comments yet)