API review: KDBusApplicationStarter

David Faure faure at kde.org
Tue May 22 21:03:22 UTC 2012


I'm about to write this class for libkdbus
(or possibly for Qt, if thiago thinks this could go into libQtDBus?),
to replace KToolInvocation::startService*.

Comments welcome :-)


/**
 * KDBusApplicationStarter starts an application with QProcess, and waits for
 * it to register to D-Bus.
 *
 * This makes it possible to make D-Bus calls to the new process without the
 * risk of making these calls too early.
 *
 * @since 5.0
 */
class KDBUSADDONS_EXPORT KDBusApplicationStarter : public QObject
{
    Q_OBJECT

public:
    /**
     * Constructor.
     */
    explicit KDBusApplicationStarter(QObject *parent = 0);

    /**
     * Destructor.
     */
    ~KDBusApplicationStarter();

    /**
     * Sets the process to start.
     * This method allows to use the full QProcess API, for things like setting the work directory.
     */
    void setProcess(QProcess *process);

    /**
     * Sets the D-Bus service name that we expect this process to register with.
     * For instance, korganizer will register as "org.kde.korganizer"
     */
    void setExpectedServiceName(const QString& service);

    /**
     * Starts the process, and returns immediately.
     *
     * Connect to the applicationReady signal to be notified that the application
     * has registered to D-Bus, or use waitForReady().
     */
    bool start(const QString &program, const QStringList &arguments = QStringList());

    /**
     * Blocks until the application has registered to D-Bus.
     *
     * This doesn't use an event loop, so there is no risk of unexpected re-entrancy.
     */
    bool waitForReady(int msecs = 30000);

    /**
     * Returns the error string that can be shown to the user.
     * This can be either an error coming from QProcess, or a timeout
     * waiting for the application to register to DBus.
     */
    QString errorString() const;

    /**
     * Convenience method. Starts the given application and waits for it to register.
     */
    static bool execute(const QString &program, const QString &expectedServiceName,
                        const QStringList &arguments = QStringList(), QString *error = 0);

Q_SIGNALS:
    /**
     * Emitted when the process has registered to D-Bus.
     */
    void applicationReady(const QString& serviceName);
};

In the simplest case, this allows to port directly:
- int ret = KToolInvocation::startServiceByDesktopPath("kglobalaccel.desktop", QStringList(), &error);
+ bool ret = KDBusApplicationStarter::execute("kglobalaccel", "org.kde.kglobalaccel", QStringList(), &error);

Same for the code that starts kwalletd, kuiserver, knotify4, or kttsd.
So all of the kdeui cases, actually.

All these are "unique applications" so setting an expected service name works.
The other case, though, is starting a non-unique application (e.g. konqueror),
to then talk dbus to it -- so the above is missing an enum ServiceMode { Unique, Multiple },
where Multiple watches for the first new process to register with expectedService + "-$PID".

I think what's also missing is to add a method to KService which returns a QProcess, all
configured for starting the service (program, args, working dir). For more direct porting, i.e.
to keep the idea of these things coming from the desktop file rather than being hardcoded
in the calling code. For KRun. Hmm, not sure there's really a need for waiting until the app
registers to DBus in the KRun case.... so let's postpone this part.

-- 
David Faure, faure at kde.org, http://www.davidfaure.fr
Sponsored by Nokia to work on KDE, incl. KDE Frameworks 5



More information about the Kde-frameworks-devel mailing list