Add support for flatpak portals

Adds support for OpenURI and Email Flatpak portals. To support them we
just do specific DBus calls, which are then caught and forwarded by
xdg-desktop-portal daemon/service. This is needed for Qt applications
running in sandbox, otherwise they cannot open links or email clients
inside sandbox. Other portal support, like for opening files can be
added into a platform theme, but adding support for OpenURI and Email
portal requires writing custom platform services plugin and this is only
possible when you write complete platform plugin, thus we want to have
this support directly in Qt. Support for other portals will most likely
follow soon, but at this moment we have to get rid of creating our
custom platform plugin to just have our own platform services for
flatpak support.

[ChangeLog][Platform Specific Changes][Linux] Added support for flatpak
portals. Flatpak is a software utility for software deployment and
package management. It provides a sandbox environment in which users
can run applications in isolation from the rest of the system. To
communicate with the system flatpak uses portals, which are designed to
be a bridge between sandboxed applications and desktop/system running on
user's computer. Flatpak runs automatically this as service, called
xdg-desktop-portal, which exports portals on DBus and which are by
default visible to all applications running under Flatpak.

Change-Id: Ice57ad120d30a3154b133172c79d8e9d6e61bd4c
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Jan Grulich 2017-10-26 13:33:12 +02:00 committed by Thiago Macieira
parent 772863355a
commit c35c017a6c
2 changed files with 108 additions and 1 deletions

View File

@ -49,6 +49,24 @@
#include <QtCore/QStandardPaths>
#include <QtCore/QUrl>
#if QT_CONFIG(dbus)
// These QtCore includes are needed for flatpak support
#include <QtCore/private/qcore_unix_p.h>
#include <QtCore/QFileInfo>
#include <QtCore/QUrlQuery>
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusPendingCall>
#include <QtDBus/QDBusPendingCallWatcher>
#include <QtDBus/QDBusPendingReply>
#include <QtDBus/QDBusUnixFileDescriptor>
#include <fcntl.h>
#endif // QT_CONFIG(dbus)
#include <stdlib.h>
QT_BEGIN_NAMESPACE
@ -153,6 +171,83 @@ static inline bool launch(const QString &launcher, const QUrl &url)
return ok;
}
#if QT_CONFIG(dbus)
static inline bool checkRunningUnderFlatpak()
{
return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, QLatin1String("flatpak-info")).isEmpty();
}
static inline bool flatpakOpenUrl(const QUrl &url)
{
// DBus signature:
// OpenURI (IN s parent_window,
// IN s uri,
// IN a{sv} options,
// OUT o handle)
// Options:
// writable (b) - Whether to allow the chosen application to write to the file.
// This key only takes effect the uri points to a local file that is exported in the document portal,
// and the chosen application is sandboxed itself.
QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"),
QLatin1String("/org/freedesktop/portal/desktop"),
QLatin1String("org.freedesktop.portal.OpenURI"),
QLatin1String("OpenURI"));
// FIXME parent_window_id and handle writable option
message << QString() << url.toString() << QVariantMap();
QDBusPendingReply<QDBusObjectPath> reply = QDBusConnection::sessionBus().call(message);
return !reply.isError();
}
static inline bool flatpakSendEmail(const QUrl &url)
{
// DBus signature:
// ComposeEmail (IN s parent_window,
// IN a{sv} options,
// OUT o handle)
// Options:
// address (s) - The email address to send to.
// subject (s) - The subject for the email.
// body (s) - The body for the email.
// attachment_fds (ah) - File descriptors for files to attach.
QUrlQuery urlQuery(url);
QVariantMap options;
options.insert(QLatin1String("address"), url.path());
options.insert(QLatin1String("subject"), urlQuery.queryItemValue(QLatin1String("subject")));
options.insert(QLatin1String("body"), urlQuery.queryItemValue(QLatin1String("body")));
// O_PATH seems to be present since Linux 2.6.39, which is not case of RHEL 6
#ifdef O_PATH
QList<QDBusUnixFileDescriptor> attachments;
const QStringList attachmentUris = urlQuery.allQueryItemValues(QLatin1String("attachment"));
for (const QString &attachmentUri : attachmentUris) {
const int fd = qt_safe_open(QFile::encodeName(attachmentUri), O_PATH);
if (fd != -1) {
QDBusUnixFileDescriptor descriptor(fd);
attachments << descriptor;
qt_safe_close(fd);
}
}
options.insert(QLatin1String("attachment_fds"), QVariant::fromValue(attachments));
#endif
QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"),
QLatin1String("/org/freedesktop/portal/desktop"),
QLatin1String("org.freedesktop.portal.Email"),
QLatin1String("ComposeEmail"));
// FIXME parent_window_id
message << QString() << options;
QDBusPendingReply<QDBusObjectPath> reply = QDBusConnection::sessionBus().call(message);
return !reply.isError();
}
#endif // QT_CONFIG(dbus)
QByteArray QGenericUnixServices::desktopEnvironment() const
{
static const QByteArray result = detectDesktopEnvironment();
@ -161,8 +256,18 @@ QByteArray QGenericUnixServices::desktopEnvironment() const
bool QGenericUnixServices::openUrl(const QUrl &url)
{
if (url.scheme() == QLatin1String("mailto"))
if (url.scheme() == QLatin1String("mailto")) {
#if QT_CONFIG(dbus)
if (checkRunningUnderFlatpak())
return flatpakSendEmail(url);
#endif
return openDocument(url);
}
#if QT_CONFIG(dbus)
if (checkRunningUnderFlatpak())
return flatpakOpenUrl(url);
#endif
if (m_webBrowser.isEmpty() && !detectWebBrowser(desktopEnvironment(), true, &m_webBrowser)) {
qWarning("Unable to detect a web browser to launch '%s'", qPrintable(url.toString()));

View File

@ -2,6 +2,8 @@ TARGET = QtServiceSupport
MODULE = service_support
QT = core-private gui-private
qtConfig(dbus): QT += dbus
CONFIG += static internal_module
DEFINES += QT_NO_CAST_FROM_ASCII