diff --git a/src/access.cpp b/src/access.cpp index 194415d..e467a1f 100644 --- a/src/access.cpp +++ b/src/access.cpp @@ -1,86 +1,86 @@ /* * Copyright © 2017 Red Hat, Inc * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #include "access.h" #include "accessdialog.h" #include #include Q_LOGGING_CATEGORY(XdgDesktopPortalKdeAccess, "xdg-desktop-portal-kde-access") -Access::Access(QObject *parent) - : QObject(parent) +AccessPortal::AccessPortal(QObject *parent) + : QDBusAbstractAdaptor(parent) { } -Access::~Access() +AccessPortal::~AccessPortal() { } -uint Access::accessDialog(const QDBusObjectPath &handle, +uint AccessPortal::AccessDialog(const QDBusObjectPath &handle, const QString &app_id, const QString &parent_window, const QString &title, const QString &subtitle, const QString &body, const QVariantMap &options, QVariantMap &results) { qCDebug(XdgDesktopPortalKdeAccess) << "AccessDialog called with parameters:"; qCDebug(XdgDesktopPortalKdeAccess) << " handle: " << handle.path(); qCDebug(XdgDesktopPortalKdeAccess) << " app_id: " << app_id; qCDebug(XdgDesktopPortalKdeAccess) << " parent_window: " << parent_window; qCDebug(XdgDesktopPortalKdeAccess) << " title: " << title; qCDebug(XdgDesktopPortalKdeAccess) << " subtitle: " << subtitle; qCDebug(XdgDesktopPortalKdeAccess) << " body: " << body; qCDebug(XdgDesktopPortalKdeAccess) << " options: " << options; - AccessDialog *accessDialog = new AccessDialog(); + auto accessDialog = new ::AccessDialog(); accessDialog->setBody(body); accessDialog->setTitle(title); accessDialog->setSubtitle(subtitle); if (options.contains(QLatin1String("modal"))) { accessDialog->setModal(options.value(QLatin1String("modal")).toBool()); } if (options.contains(QLatin1String("deny_label"))) { accessDialog->setRejectLabel(options.value(QLatin1String("deny_label")).toString()); } if (options.contains(QLatin1String("grant_label"))) { accessDialog->setAcceptLabel(options.value(QLatin1String("grant_label")).toString()); } if (options.contains(QLatin1String("icon"))) { accessDialog->setIcon(options.value(QLatin1String("icon")).toString()); } // TODO choices if (accessDialog->exec()) { accessDialog->deleteLater(); return 0; } accessDialog->deleteLater(); return 1; } diff --git a/src/access.h b/src/access.h index 65ffd38..a13dd32 100644 --- a/src/access.h +++ b/src/access.h @@ -1,47 +1,47 @@ /* * Copyright © 2017 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #ifndef XDG_DESKTOP_PORTAL_KDE_ACCESS_H #define XDG_DESKTOP_PORTAL_KDE_ACCESS_H -#include +#include #include -class Access : public QObject +class AccessPortal : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.Access") public: - Access(QObject *parent = nullptr); - ~Access(); + AccessPortal(QObject *parent); + ~AccessPortal(); public Q_SLOTS: - uint accessDialog(const QDBusObjectPath &handle, + uint AccessDialog(const QDBusObjectPath &handle, const QString &app_id, const QString &parent_window, const QString &title, const QString &subtitle, const QString &body, const QVariantMap &options, QVariantMap &results); }; #endif // XDG_DESKTOP_PORTAL_KDE_ACCESS_H diff --git a/src/appchooser.cpp b/src/appchooser.cpp index a5c9b9a..0494166 100644 --- a/src/appchooser.cpp +++ b/src/appchooser.cpp @@ -1,73 +1,73 @@ /* * Copyright © 2016 Red Hat, Inc * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #include "appchooser.h" #include "appchooserdialog.h" #include #include Q_LOGGING_CATEGORY(XdgDesktopPortalKdeAppChooser, "xdg-desktop-portal-kde-app-chooser") -AppChooser::AppChooser(QObject *parent) - : QObject(parent) +AppChooserPortal::AppChooserPortal(QObject *parent) + : QDBusAbstractAdaptor(parent) { } -AppChooser::~AppChooser() +AppChooserPortal::~AppChooserPortal() { } -uint AppChooser::chooseApplication(const QDBusObjectPath &handle, +uint AppChooserPortal::ChooseApplication(const QDBusObjectPath &handle, const QString &app_id, const QString &parent_window, const QStringList &choices, const QVariantMap &options, QVariantMap &results) { qCDebug(XdgDesktopPortalKdeAppChooser) << "ChooseApplication called with parameters:"; qCDebug(XdgDesktopPortalKdeAppChooser) << " handle: " << handle.path(); qCDebug(XdgDesktopPortalKdeAppChooser) << " app_id: " << app_id; qCDebug(XdgDesktopPortalKdeAppChooser) << " parent_window: " << parent_window; qCDebug(XdgDesktopPortalKdeAppChooser) << " choices: " << choices; qCDebug(XdgDesktopPortalKdeAppChooser) << " options: " << options; QString latestChoice; if (options.contains(QLatin1String("last_choice"))) { latestChoice = options.value(QLatin1String("last_choice")).toString(); } AppChooserDialog *appDialog = new AppChooserDialog(choices); if (!latestChoice.isEmpty()) { appDialog->setSelectedApplication(latestChoice); } if (appDialog->exec()) { results.insert(QLatin1String("choice"), appDialog->selectedApplication()); appDialog->deleteLater(); return 0; } appDialog->deleteLater(); return 1; } diff --git a/src/appchooser.h b/src/appchooser.h index a6fe5b9..f4ef223 100644 --- a/src/appchooser.h +++ b/src/appchooser.h @@ -1,45 +1,45 @@ /* * Copyright © 2016 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #ifndef XDG_DESKTOP_PORTAL_KDE_APPCHOOSER_H #define XDG_DESKTOP_PORTAL_KDE_APPCHOOSER_H -#include +#include #include -class AppChooser : public QObject +class AppChooserPortal : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.AppChooser") public: - AppChooser(QObject *parent = nullptr); - ~AppChooser(); + AppChooserPortal(QObject *parent); + ~AppChooserPortal(); public Q_SLOTS: - uint chooseApplication(const QDBusObjectPath &handle, + uint ChooseApplication(const QDBusObjectPath &handle, const QString &app_id, const QString &parent_window, const QStringList &choices, const QVariantMap &options, QVariantMap &results); }; #endif // XDG_DESKTOP_PORTAL_KDE_APPCHOOSER_H diff --git a/src/desktopportal.cpp b/src/desktopportal.cpp index 51a12c1..49881c9 100644 --- a/src/desktopportal.cpp +++ b/src/desktopportal.cpp @@ -1,338 +1,45 @@ /* * Copyright © 2016 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #include "desktopportal.h" #include #include #include #include #include Q_LOGGING_CATEGORY(XdgDesktopPortalKdeDesktopPortal, "xdg-desktop-portal-kde-desktop-portal") DesktopPortal::DesktopPortal(QObject *parent) - : QDBusVirtualObject(parent) - , m_access(new Access()) - , m_appChooser(new AppChooser()) - , m_email(new Email()) - , m_fileChooser(new FileChooser()) - , m_inhibit(new Inhibit()) - , m_notification(new Notification()) - , m_print(new Print()) + : QObject(parent) + , m_access(new AccessPortal(this)) + , m_appChooser(new AppChooserPortal(this)) + , m_email(new EmailPortal(this)) + , m_fileChooser(new FileChooserPortal(this)) + , m_inhibit(new InhibitPortal(this)) + , m_notification(new NotificationPortal(this)) + , m_print(new PrintPortal(this)) { } DesktopPortal::~DesktopPortal() { - delete m_access; - delete m_appChooser; - delete m_email; - delete m_fileChooser; - delete m_inhibit; - delete m_notification; - delete m_print; -} - -bool DesktopPortal::handleMessage(const QDBusMessage &message, const QDBusConnection &connection) -{ - /* Check to make sure we're getting properties on our interface */ - if (message.type() != QDBusMessage::MessageType::MethodCallMessage) { - return false; - } - - qCDebug(XdgDesktopPortalKdeDesktopPortal) << message.interface(); - qCDebug(XdgDesktopPortalKdeDesktopPortal) << message.member(); - qCDebug(XdgDesktopPortalKdeDesktopPortal) << message.path(); - - QList arguments; - if (message.interface() == QLatin1String("org.freedesktop.impl.portal.Access")) { - if (message.member() == QLatin1String("AccessDialog")) { - QVariantMap results; - QVariantMap options; - - QDBusArgument dbusArgument = message.arguments().at(6).value(); - dbusArgument >> options; - - uint response = m_access->accessDialog(qvariant_cast(message.arguments().at(0)), // handle - message.arguments().at(1).toString(), // app_id - message.arguments().at(2).toString(), // parent_window - message.arguments().at(3).toString(), // title - message.arguments().at(4).toString(), // subtitle - message.arguments().at(5).toString(), // body - options, // options - results); - arguments << response; - arguments << results; - } - } else if (message.interface() == QLatin1String("org.freedesktop.impl.portal.AppChooser")) { - if (message.member() == QLatin1String("ChooseApplication")) { - QVariantMap results; - QVariantMap choices; - - QDBusArgument dbusArgument = message.arguments().at(4).value(); - dbusArgument >> choices; - - uint response = m_appChooser->chooseApplication(qvariant_cast(message.arguments().at(0)), // handle - message.arguments().at(1).toString(), // app_id - message.arguments().at(2).toString(), // parent_window - message.arguments().at(3).toStringList(), // choices - choices, // options - results); - arguments << response; - arguments << results; - } - } else if (message.interface() == QLatin1String("org.freedesktop.impl.portal.Email")) { - uint response = 2; - QVariantMap results; - QVariantMap options; - - QDBusArgument dbusArgument = message.arguments().at(3).value(); - dbusArgument >> options; - - if (message.member() == QLatin1String("ComposeEmail")) { - response = m_email->composeEmail(qvariant_cast(message.arguments().at(0)), // handle - message.arguments().at(1).toString(), // app_id - message.arguments().at(2).toString(), // parent_window - options, // options - results); - } - - arguments << response; - arguments << results; - } else if (message.interface() == QLatin1String("org.freedesktop.impl.portal.FileChooser")) { - uint response = 2; - QVariantMap results; - QVariantMap choices; - - QDBusArgument dbusArgument = message.arguments().at(4).value(); - dbusArgument >> choices; - - if (message.member() == QLatin1String("OpenFile")) { - response = m_fileChooser->openFile(qvariant_cast(message.arguments().at(0)), // handle - message.arguments().at(1).toString(), // app_id - message.arguments().at(2).toString(), // parent_window - message.arguments().at(3).toString(), // title - choices, // options - results); - } else if (message.member() == QLatin1String("SaveFile")) { - response = m_fileChooser->saveFile(qvariant_cast(message.arguments().at(0)), // handle - message.arguments().at(1).toString(), // app_id - message.arguments().at(2).toString(), // parent_window - message.arguments().at(3).toString(), // title - choices, // options - results); - } - - arguments << response; - arguments << results; - - } else if (message.interface() == QLatin1String("org.freedesktop.impl.portal.Inhibit")) { - if (message.member() == QLatin1String("Inhibit")) { - QVariantMap options; - - QDBusArgument dbusArgument = message.arguments().at(4).value(); - dbusArgument >> options; - - m_inhibit->inhibit(qvariant_cast(message.arguments().at(0)), // handle - message.arguments().at(1).toString(), // app_id - message.arguments().at(2).toString(), // window - message.arguments().at(3).toUInt(), // flags - options); // options - } - } else if (message.interface() == QLatin1String("org.freedesktop.impl.portal.Notification")) { - if (message.member() == QLatin1String("AddNotification")) { - QVariantMap notificationParams; - - QDBusArgument dbusArgument = message.arguments().at(2).value(); - dbusArgument >> notificationParams; - - m_notification->addNotification(message.arguments().at(0).toString(), // app_id - message.arguments().at(1).toString(), // id - notificationParams); // notification - } else if (message.member() == QLatin1String("RemoveNotification")) { - m_notification->removeNotification(message.arguments().at(0).toString(), // app_id - message.arguments().at(1).toString()); // id - } - } else if (message.interface() == QLatin1String("org.freedesktop.impl.portal.Print")) { - uint response = 2; - QVariantMap results; - - if (message.member() == QLatin1String("Print")) { - QVariantMap options; - - QDBusArgument dbusArgument = message.arguments().at(5).value(); - dbusArgument >> options; - - response = m_print->print(qvariant_cast(message.arguments().at(0)), // handle - message.arguments().at(1).toString(), // app_id - message.arguments().at(2).toString(), // parent_window - message.arguments().at(3).toString(), // title - qvariant_cast(message.arguments().at(4)), // fd - options, // options - results); - } else if (message.member() == QLatin1String("PreparePrint")) { - QVariantMap settings; - QVariantMap pageSetup; - QVariantMap options; - - QDBusArgument dbusArgument = message.arguments().at(4).value(); - dbusArgument >> settings; - - QDBusArgument dbusArgument1 = message.arguments().at(5).value(); - dbusArgument1 >> pageSetup; - - QDBusArgument dbusArgument2 = message.arguments().at(6).value(); - dbusArgument2 >> options; - - response = m_print->preparePrint(qvariant_cast(message.arguments().at(0)), // handle - message.arguments().at(1).toString(), // app_id - message.arguments().at(2).toString(), // parent_window - message.arguments().at(3).toString(), // title - settings, // settings - pageSetup, // page_setup - options, // options - results); - } - - arguments << response; - arguments << results; - } - - QDBusMessage reply = message.createReply(); - reply.setArguments(arguments); - return connection.send(reply); -} - -QString DesktopPortal::introspect(const QString &path) const -{ - QString nodes; - - if (path == QLatin1String("/org/freedesktop/portal/desktop/") || path == QLatin1String("/org/freedesktop/portal/desktop")) { - nodes = QStringLiteral( - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - "" - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - "" - "" - " " - " " - " " - " " - " " - " " - " " - " " - "" - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - "" - "" - " " - " " - " " - " " - " " - " " - " " - "" - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - "" - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""); - } - - qCDebug(XdgDesktopPortalKdeDesktopPortal) << nodes; - - return nodes; } diff --git a/src/desktopportal.h b/src/desktopportal.h index 0da9504..0fe1b4c 100644 --- a/src/desktopportal.h +++ b/src/desktopportal.h @@ -1,55 +1,53 @@ /* * Copyright © 2016 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #ifndef XDG_DESKTOP_PORTAL_KDE_DESKTOP_PORTAL_H #define XDG_DESKTOP_PORTAL_KDE_DESKTOP_PORTAL_H #include #include #include "access.h" #include "appchooser.h" #include "email.h" #include "filechooser.h" #include "inhibit.h" #include "notification.h" #include "print.h" -class DesktopPortal : public QDBusVirtualObject +class DesktopPortal : public QObject { Q_OBJECT public: explicit DesktopPortal(QObject *parent = nullptr); ~DesktopPortal(); - bool handleMessage(const QDBusMessage &message, const QDBusConnection &connection) Q_DECL_OVERRIDE; - QString introspect(const QString &path) const Q_DECL_OVERRIDE; private: - Access *m_access; - AppChooser *m_appChooser; - Email *m_email; - FileChooser *m_fileChooser; - Inhibit *m_inhibit; - Notification *m_notification; - Print *m_print; + AccessPortal *m_access; + AppChooserPortal *m_appChooser; + EmailPortal *m_email; + FileChooserPortal *m_fileChooser; + InhibitPortal *m_inhibit; + NotificationPortal *m_notification; + PrintPortal *m_print; }; #endif // XDG_DESKTOP_PORTAL_KDE_DESKTOP_PORTAL_H diff --git a/src/email.cpp b/src/email.cpp index 95b39ea..5918247 100644 --- a/src/email.cpp +++ b/src/email.cpp @@ -1,56 +1,56 @@ /* * Copyright © 2017 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #include "email.h" #include #include #include Q_LOGGING_CATEGORY(XdgDesktopPortalKdeEmail, "xdg-desktop-portal-kde-email") -Email::Email(QObject *parent) - : QObject(parent) +EmailPortal::EmailPortal(QObject *parent) + : QDBusAbstractAdaptor(parent) { } -Email::~Email() +EmailPortal::~EmailPortal() { } -uint Email::composeEmail(const QDBusObjectPath &handle, const QString &app_id, const QString &window, const QVariantMap &options, QVariantMap &results) +uint EmailPortal::ComposeEmail(const QDBusObjectPath &handle, const QString &app_id, const QString &window, const QVariantMap &options, QVariantMap &results) { Q_UNUSED(results) qCDebug(XdgDesktopPortalKdeEmail) << "ComposeEmail called with parameters:"; qCDebug(XdgDesktopPortalKdeEmail) << " handle: " << handle.path(); qCDebug(XdgDesktopPortalKdeEmail) << " app_id: " << app_id; qCDebug(XdgDesktopPortalKdeEmail) << " window: " << window; qCDebug(XdgDesktopPortalKdeEmail) << " options: " << options; // TODO attachements const QString mailtoUrl = QStringLiteral("mailto:%1?subject=%2&body=%3").arg(options.value(QLatin1String("address")).toString()) .arg(options.value(QLatin1String("subject")).toString()) .arg(options.value(QLatin1String("body")).toString()); qCDebug(XdgDesktopPortalKdeEmail) << "Mailto url: " << mailtoUrl; return QDesktopServices::openUrl(QUrl(mailtoUrl)); } diff --git a/src/email.h b/src/email.h index dd6e81b..1c0e3a6 100644 --- a/src/email.h +++ b/src/email.h @@ -1,44 +1,44 @@ /* * Copyright © 2017 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #ifndef XDG_DESKTOP_PORTAL_KDE_EMAIL_H #define XDG_DESKTOP_PORTAL_KDE_EMAIL_H -#include +#include #include -class Email : public QObject +class EmailPortal : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.Email") public: - Email(QObject *parent = 0); - ~Email(); + EmailPortal(QObject *parent); + ~EmailPortal(); public Q_SLOTS: - uint composeEmail(const QDBusObjectPath &handle, + uint ComposeEmail(const QDBusObjectPath &handle, const QString &app_id, const QString &window, const QVariantMap &options, QVariantMap &results); }; #endif // XDG_DESKTOP_PORTAL_KDE_EMAIL_H diff --git a/src/filechooser.cpp b/src/filechooser.cpp index cb4b27b..0938705 100644 --- a/src/filechooser.cpp +++ b/src/filechooser.cpp @@ -1,291 +1,291 @@ /* * Copyright © 2016 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #include "filechooser.h" #include #include #include #include #include Q_LOGGING_CATEGORY(XdgDesktopPortalKdeFileChooser, "xdg-desktop-portal-kde-file-chooser") // Keep in sync with qflatpakfiledialog from flatpak-platform-plugin -Q_DECLARE_METATYPE(FileChooser::Filter); -Q_DECLARE_METATYPE(FileChooser::Filters); -Q_DECLARE_METATYPE(FileChooser::FilterList); -Q_DECLARE_METATYPE(FileChooser::FilterListList); +Q_DECLARE_METATYPE(FileChooserPortal::Filter); +Q_DECLARE_METATYPE(FileChooserPortal::Filters); +Q_DECLARE_METATYPE(FileChooserPortal::FilterList); +Q_DECLARE_METATYPE(FileChooserPortal::FilterListList); -QDBusArgument &operator << (QDBusArgument &arg, const FileChooser::Filter &filter) +QDBusArgument &operator << (QDBusArgument &arg, const FileChooserPortal::Filter &filter) { arg.beginStructure(); arg << filter.type << filter.filterString; arg.endStructure(); return arg; } -const QDBusArgument &operator >> (const QDBusArgument &arg, FileChooser::Filter &filter) +const QDBusArgument &operator >> (const QDBusArgument &arg, FileChooserPortal::Filter &filter) { uint type; QString filterString; arg.beginStructure(); arg >> type >> filterString; filter.type = type; filter.filterString = filterString; arg.endStructure(); return arg; } -QDBusArgument &operator << (QDBusArgument &arg, const FileChooser::FilterList &filterList) +QDBusArgument &operator << (QDBusArgument &arg, const FileChooserPortal::FilterList &filterList) { arg.beginStructure(); arg << filterList.userVisibleName << filterList.filters; arg.endStructure(); return arg; } -const QDBusArgument &operator >> (const QDBusArgument &arg, FileChooser::FilterList &filterList) +const QDBusArgument &operator >> (const QDBusArgument &arg, FileChooserPortal::FilterList &filterList) { QString userVisibleName; - FileChooser::Filters filters; + FileChooserPortal::Filters filters; arg.beginStructure(); arg >> userVisibleName >> filters; filterList.userVisibleName = userVisibleName; filterList.filters = filters; arg.endStructure(); return arg; } -FileChooser::FileChooser(QObject *parent) - : QObject(parent) +FileChooserPortal::FileChooserPortal(QObject *parent) + : QDBusAbstractAdaptor(parent) { qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType(); } -FileChooser::~FileChooser() +FileChooserPortal::~FileChooserPortal() { } -uint FileChooser::openFile(const QDBusObjectPath &handle, +uint FileChooserPortal::OpenFile(const QDBusObjectPath &handle, const QString &app_id, const QString &parent_window, const QString &title, const QVariantMap &options, QVariantMap &results) { Q_UNUSED(app_id); qCDebug(XdgDesktopPortalKdeFileChooser) << "OpenFile called with parameters:"; qCDebug(XdgDesktopPortalKdeFileChooser) << " handle: " << handle.path(); qCDebug(XdgDesktopPortalKdeFileChooser) << " parent_window: " << parent_window; qCDebug(XdgDesktopPortalKdeFileChooser) << " title: " << title; qCDebug(XdgDesktopPortalKdeFileChooser) << " options: " << options; bool modalDialog = true; bool multipleFiles = false; QString acceptLabel; QStringList nameFilters; QStringList mimeTypeFilters; /* TODO * choices a(ssa(ss)s) * List of serialized combo boxes to add to the file chooser. * * For each element, the first string is an ID that will be returned with the response, te second string is a user-visible label. * The a(ss) is the list of choices, each being a is an ID and a user-visible label. The final string is the initial selection, * or "", to let the portal decide which choice will be initially selected. None of the strings, except for the initial selection, should be empty. * * As a special case, passing an empty array for the list of choices indicates a boolean choice that is typically displayed as a check button, using "true" and "false" as the choices. * Example: [('encoding', 'Encoding', [('utf8', 'Unicode (UTF-8)'), ('latin15', 'Western')], 'latin15'), ('reencode', 'Reencode', [], 'false')] */ if (options.contains(QLatin1String("accept_label"))) { acceptLabel = options.value(QLatin1String("accept_label")).toString(); } if (options.contains(QLatin1String("modal"))) { modalDialog = options.value(QLatin1String("modal")).toBool(); } if (options.contains(QLatin1String("multiple"))) { multipleFiles = options.value(QLatin1String("multiple")).toBool(); } if (options.contains(QLatin1String("filters"))) { FilterListList filterListList = qdbus_cast(options.value(QLatin1String("filters"))); Q_FOREACH (const FilterList &filterList, filterListList) { QStringList filterStrings; Q_FOREACH (const Filter &filterStruct, filterList.filters) { if (filterStruct.type == 0) { filterStrings << filterStruct.filterString; } else { mimeTypeFilters << filterStruct.filterString; } } if (!filterStrings.isEmpty()) { nameFilters << QString("%1 (%2)").arg(filterList.userVisibleName).arg(filterStrings.join(QLatin1String(" "))); } } } QFileDialog *fileDialog = new QFileDialog(); fileDialog->setWindowTitle(title); fileDialog->setModal(modalDialog); fileDialog->setFileMode(multipleFiles ? QFileDialog::ExistingFiles : QFileDialog::ExistingFile); fileDialog->setLabelText(QFileDialog::Accept, !acceptLabel.isEmpty() ? acceptLabel : i18n("Open")); if (!nameFilters.isEmpty()) { fileDialog->setNameFilters(nameFilters); } if (!mimeTypeFilters.isEmpty()) { fileDialog->setMimeTypeFilters(mimeTypeFilters); } if (fileDialog->exec() == QDialog::Accepted) { QStringList files; Q_FOREACH (const QString &filename, fileDialog->selectedFiles()) { QUrl url = QUrl::fromLocalFile(filename); files << url.toDisplayString(); } results.insert(QLatin1String("uris"), files); fileDialog->deleteLater(); return 0; } fileDialog->deleteLater(); return 1; } -uint FileChooser::saveFile(const QDBusObjectPath &handle, +uint FileChooserPortal::SaveFile(const QDBusObjectPath &handle, const QString &app_id, const QString &parent_window, const QString &title, const QVariantMap &options, QVariantMap &results) { Q_UNUSED(app_id); qCDebug(XdgDesktopPortalKdeFileChooser) << "SaveFile called with parameters:"; qCDebug(XdgDesktopPortalKdeFileChooser) << " handle: " << handle.path(); qCDebug(XdgDesktopPortalKdeFileChooser) << " parent_window: " << parent_window; qCDebug(XdgDesktopPortalKdeFileChooser) << " title: " << title; qCDebug(XdgDesktopPortalKdeFileChooser) << " options: " << options; bool modalDialog = true; QString acceptLabel; QString currentName; QString currentFolder; QString currentFile; QStringList nameFilters; QStringList mimeTypeFilters; // TODO parse options - choices if (options.contains(QLatin1String("modal"))) { modalDialog = options.value(QLatin1String("modal")).toBool(); } if (options.contains(QLatin1String("accept_label"))) { acceptLabel = options.value(QLatin1String("accept_label")).toString(); } if (options.contains(QLatin1String("current_name"))) { currentName = options.value(QLatin1String("current_name")).toString(); } if (options.contains(QLatin1String("current_folder"))) { currentFolder = options.value(QLatin1String("current_folder")).toByteArray(); } if (options.contains(QLatin1String("current_file"))) { currentFile = options.value(QLatin1String("current_file")).toByteArray(); } if (options.contains(QLatin1String("filters"))) { FilterListList filterListList = qdbus_cast(options.value(QLatin1String("filters"))); Q_FOREACH (const FilterList &filterList, filterListList) { QStringList filterStrings; Q_FOREACH (const Filter &filterStruct, filterList.filters) { if (filterStruct.type == 0) { filterStrings << filterStruct.filterString; } else { mimeTypeFilters << filterStruct.filterString; } } if (!filterStrings.isEmpty()) { nameFilters << QString("%1 (%2)").arg(filterList.userVisibleName).arg(filterStrings.join(QLatin1String(" "))); } } } QFileDialog *fileDialog = new QFileDialog(); fileDialog->setWindowTitle(title); fileDialog->setModal(modalDialog); fileDialog->setAcceptMode(QFileDialog::AcceptSave); // TODO: Looks Qt doesn't have API for this // if (!currentName.isEmpty()) { // fileDialog->selectFile(currentName); // } if (!currentFolder.isEmpty()) { fileDialog->setDirectoryUrl(QUrl(currentFolder)); } if (!currentFile.isEmpty()) { fileDialog->selectFile(currentFile); } if (!acceptLabel.isEmpty()) { fileDialog->setLabelText(QFileDialog::Accept, acceptLabel); } if (!nameFilters.isEmpty()) { fileDialog->setNameFilters(nameFilters); } if (!mimeTypeFilters.isEmpty()) { fileDialog->setMimeTypeFilters(mimeTypeFilters); } if (fileDialog->exec() == QDialog::Accepted) { QStringList files; Q_FOREACH (const QString &filename, fileDialog->selectedFiles()) { QUrl url = QUrl::fromLocalFile(filename); files << url.toDisplayString(); } results.insert(QLatin1String("uris"), files); fileDialog->deleteLater(); return 0; } fileDialog->deleteLater(); return 1; } diff --git a/src/filechooser.h b/src/filechooser.h index eef1b1d..88f78ce 100644 --- a/src/filechooser.h +++ b/src/filechooser.h @@ -1,65 +1,65 @@ /* * Copyright © 2016 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #ifndef XDG_DESKTOP_PORTAL_KDE_FILECHOOSER_H #define XDG_DESKTOP_PORTAL_KDE_FILECHOOSER_H #include #include -#include +#include -class FileChooser : public QObject +class FileChooserPortal : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.FileChooser") public: // Keep in sync with qflatpakfiledialog from flatpak-platform-plugin typedef struct { uint type; QString filterString; } Filter; typedef QList Filters; typedef struct { QString userVisibleName; Filters filters; } FilterList; typedef QList FilterListList; - FileChooser(QObject *parent = 0); - ~FileChooser(); + FileChooserPortal(QObject *parent); + ~FileChooserPortal(); public Q_SLOTS: - uint openFile(const QDBusObjectPath &handle, + uint OpenFile(const QDBusObjectPath &handle, const QString &app_id, const QString &parent_window, const QString &title, const QVariantMap &options, QVariantMap &results); - uint saveFile(const QDBusObjectPath &handle, + uint SaveFile(const QDBusObjectPath &handle, const QString &app_id, const QString &parent_window, const QString &title, const QVariantMap &options, QVariantMap &results); }; #endif // XDG_DESKTOP_PORTAL_KDE_FILECHOOSER_H diff --git a/src/inhibit.cpp b/src/inhibit.cpp index b2c8f32..3bad185 100644 --- a/src/inhibit.cpp +++ b/src/inhibit.cpp @@ -1,80 +1,80 @@ /* * Copyright © 2017 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #include "inhibit.h" #include "request.h" #include #include #include #include #include #include #include Q_LOGGING_CATEGORY(XdgDesktopPortalKdeInhibit, "xdg-desktop-portal-kde-inhibit") -Inhibit::Inhibit(QObject *parent) - : QObject(parent) +InhibitPortal::InhibitPortal(QObject *parent) + : QDBusAbstractAdaptor(parent) { } -Inhibit::~Inhibit() +InhibitPortal::~InhibitPortal() { } -void Inhibit::inhibit(const QDBusObjectPath &handle, const QString &app_id, const QString &window, uint flags, const QVariantMap &options) +void InhibitPortal::Inhibit(const QDBusObjectPath &handle, const QString &app_id, const QString &window, uint flags, const QVariantMap &options) { qCDebug(XdgDesktopPortalKdeInhibit) << "Inhibit called with parameters:"; qCDebug(XdgDesktopPortalKdeInhibit) << " handle: " << handle.path(); qCDebug(XdgDesktopPortalKdeInhibit) << " app_id: " << app_id; qCDebug(XdgDesktopPortalKdeInhibit) << " window: " << window; qCDebug(XdgDesktopPortalKdeInhibit) << " flags: " << flags; qCDebug(XdgDesktopPortalKdeInhibit) << " options: " << options; QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.kde.Solid.PowerManagement"), QLatin1String("/org/kde/Solid/PowerManagement/PolicyAgent"), QLatin1String("org.kde.Solid.PowerManagement.PolicyAgent"), QLatin1String("AddInhibition")); // interrupt session (1) message << (uint)1 << app_id << options.value(QLatin1String("reason")).toString(); QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall); connect(watcher, &QDBusPendingCallWatcher::finished, [handle, this] (QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { qCDebug(XdgDesktopPortalKdeInhibit) << "Inhibition error: " << reply.error().message(); } else { QDBusConnection sessionBus = QDBusConnection::sessionBus(); Request *request = new Request(this, QLatin1String("org.freedesktop.impl.portal.Inhibit"), QVariant(reply.value())); if (sessionBus.registerVirtualObject(handle.path(), request, QDBusConnection::VirtualObjectRegisterOption::SubPath)) { connect(request, &Request::closeRequested, [request, handle] () { QDBusConnection::sessionBus().unregisterObject(handle.path()); request->deleteLater(); }); } else { qCDebug(XdgDesktopPortalKdeInhibit) << sessionBus.lastError().message(); qCDebug(XdgDesktopPortalKdeInhibit) << "Failed to register request object with inhibition"; request->deleteLater(); } } }); } diff --git a/src/inhibit.h b/src/inhibit.h index de92fcf..4b141dd 100644 --- a/src/inhibit.h +++ b/src/inhibit.h @@ -1,46 +1,46 @@ /* * Copyright © 2017 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #ifndef XDG_DESKTOP_PORTAL_KDE_INHIBIT_H #define XDG_DESKTOP_PORTAL_KDE_INHIBIT_H -#include +#include #include #include "request.h" -class Inhibit : public QObject +class InhibitPortal : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.Inhibit") public: - Inhibit(QObject *parent = 0); - ~Inhibit(); + InhibitPortal(QObject *parent); + ~InhibitPortal(); public Q_SLOTS: - void inhibit(const QDBusObjectPath &handle, + void Inhibit(const QDBusObjectPath &handle, const QString &app_id, const QString &window, uint flags, const QVariantMap &options); }; #endif // XDG_DESKTOP_PORTAL_KDE_INHIBIT_H diff --git a/src/notification.cpp b/src/notification.cpp index e3b1936..f052707 100644 --- a/src/notification.cpp +++ b/src/notification.cpp @@ -1,143 +1,144 @@ /* * Copyright © 2016 Red Hat, Inc * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #include "notification.h" #include #include #include #include + Q_LOGGING_CATEGORY(XdgDesktopPortalKdeNotification, "xdg-desktop-portal-kde-notification") -Notification::Notification(QObject *parent) - : QObject(parent) +NotificationPortal::NotificationPortal(QObject *parent) + : QDBusAbstractAdaptor(parent) { } -Notification::~Notification() +NotificationPortal::~NotificationPortal() { } -void Notification::addNotification(const QString &app_id, +void NotificationPortal::AddNotification(const QString &app_id, const QString &id, const QVariantMap ¬ification) { qCDebug(XdgDesktopPortalKdeNotification) << "AddNotification called with parameters:"; qCDebug(XdgDesktopPortalKdeNotification) << " app_id: " << app_id; qCDebug(XdgDesktopPortalKdeNotification) << " id: " << id; qCDebug(XdgDesktopPortalKdeNotification) << " notification: " << notification; // We have to use "notification" as an ID because any other ID will not be configured KNotification *notify = new KNotification(QLatin1String("notification"), KNotification::CloseOnTimeout | KNotification::DefaultEvent, this); if (notification.contains(QLatin1String("title"))) { notify->setTitle(notification.value(QLatin1String("title")).toString()); } if (notification.contains(QLatin1String("body"))) { notify->setText(notification.value(QLatin1String("body")).toString()); } if (notification.contains(QLatin1String("icon"))) { notify->setIconName(notification.value(QLatin1String("icon")).toString()); } if (notification.contains(QLatin1String("priority"))) { // TODO KNotification has no option for priority } if (notification.contains(QLatin1String("default-action"))) { // TODO KNotification has no option for default action } if (notification.contains(QLatin1String("default-action-target"))) { // TODO KNotification has no option for default action } if (notification.contains(QLatin1String("buttons"))) { QList buttons; QDBusArgument dbusArgument = notification.value(QLatin1String("buttons")).value(); while (!dbusArgument.atEnd()) { dbusArgument >> buttons; } QStringList actions; Q_FOREACH (const QVariantMap &button, buttons) { actions << button.value(QLatin1String("label")).toString(); } if (!actions.isEmpty()) { notify->setActions(actions); } } notify->setProperty("app_id", app_id); notify->setProperty("id", id); - connect(notify, static_cast(&KNotification::activated), this, &Notification::notificationActivated); - connect(notify, &KNotification::closed, this, &Notification::notificationClosed); + connect(notify, static_cast(&KNotification::activated), this, &NotificationPortal::notificationActivated); + connect(notify, &KNotification::closed, this, &NotificationPortal::notificationClosed); notify->sendEvent(); m_notifications.insert(QString("%1:%2").arg(app_id, id), notify); } -void Notification::notificationActivated(uint action) +void NotificationPortal::notificationActivated(uint action) { KNotification *notify = qobject_cast(sender()); if (!notify) { return; } const QString appId = notify->property("app_id").toString(); const QString id = notify->property("id").toString(); qCDebug(XdgDesktopPortalKdeNotification) << "Notification activated:"; qCDebug(XdgDesktopPortalKdeNotification) << " app_id: " << appId; qCDebug(XdgDesktopPortalKdeNotification) << " id: " << id; qCDebug(XdgDesktopPortalKdeNotification) << " action: " << action; QDBusMessage message = QDBusMessage::createSignal(QLatin1String("/org/freedesktop/portal/desktop"), QLatin1String("org.freedesktop.impl.portal.Notification"), QLatin1String("ActionInvoked")); message << appId << id << QString::number(action) << QVariantList(); QDBusConnection::sessionBus().send(message); } -void Notification::removeNotification(const QString &app_id, +void NotificationPortal::RemoveNotification(const QString &app_id, const QString &id) { qCDebug(XdgDesktopPortalKdeNotification) << "RemoveNotification called with parameters:"; qCDebug(XdgDesktopPortalKdeNotification) << " app_id: " << app_id; qCDebug(XdgDesktopPortalKdeNotification) << " id: " << id; KNotification *notify = m_notifications.take(QString("%1:%2").arg(app_id, id)); if (notify) { notify->close(); notify->deleteLater(); } } -void Notification::notificationClosed() +void NotificationPortal::notificationClosed() { KNotification *notify = qobject_cast(sender()); if (!notify) { return; } const QString appId = notify->property("app_id").toString(); const QString id = notify->property("id").toString(); m_notifications.remove(QString("%1:%2").arg(appId, id)); notify->deleteLater(); } diff --git a/src/notification.h b/src/notification.h index 17ab01d..8c668dd 100644 --- a/src/notification.h +++ b/src/notification.h @@ -1,51 +1,51 @@ /* * Copyright © 2016 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #ifndef XDG_DESKTOP_PORTAL_KDE_NOTIFICATION_H #define XDG_DESKTOP_PORTAL_KDE_NOTIFICATION_H -#include +#include #include #include -class Notification : public QObject +class NotificationPortal : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.Notification") public: - Notification(QObject *parent = 0); - ~Notification(); + NotificationPortal(QObject *parent); + ~NotificationPortal(); public Q_SLOTS: - void addNotification(const QString &app_id, + void AddNotification(const QString &app_id, const QString &id, const QVariantMap ¬ification); - void removeNotification(const QString &app_id, + void RemoveNotification(const QString &app_id, const QString &id); private Q_SLOTS: void notificationActivated(uint action); void notificationClosed(); private: QHash m_notifications; }; #endif // XDG_DESKTOP_PORTAL_KDE_NOTIFICATION_H diff --git a/src/print.cpp b/src/print.cpp index 0ff9973..439b6ce 100644 --- a/src/print.cpp +++ b/src/print.cpp @@ -1,977 +1,977 @@ /* * Copyright © 2016-2017 Jan Grulich * Copyright © 2007,2010 by John Layt * Copyright © 2007 Alex Merry * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "print.h" #include #include #include #include #include #include #include // #include #include #include #include Q_LOGGING_CATEGORY(XdgDesktopPortalKdePrint, "xdg-desktop-portal-kde-print") // INFO: code below is copied from Qt as there is no public API for converting key to PageSizeId // TODO seems to by Windows only stuff // Standard sources data // struct StandardPaperSource { // QPrinter::PaperSource sourceNum; // const char *source; // } // // static const StandardPaperSource qt_paperSources[] = { // {QPrinter::Auto, "Auto"}, // {QPrinter::Cassette, "Cassette"}, // {QPrinter::Envelope, "Envelope"}, // {QPrinter::EnvelopeManual, "EnvelopeManual"}, // {QPrinter::FormSource, "FormSource"}, // {QPrinter::LargeCapacity, "LargeCapacity"}, // {QPrinter::LargeFormat, "AnyLargeFormat"}, // {QPrinter::Lower, "Lower"}, // {QPrinter::Middle, "Middle"}, // {QPrinter::Manual, "Manual"}, // {QPrinter::Manual, "ManualFeed"}, // {QPrinter::OnlyOne, "OnlyOne"}, // = QPrint::Upper // {QPrinter::Tractor, "Tractor"}, // {QPrinter::SmallFormat, "AnySmallFormat"}, // {QPrinter::Upper, "Upper"}, // }; // Standard sizes data struct StandardPageSize { QPageSize::PageSizeId id; const char *mediaOption; // PPD standard mediaOption ID }; // Standard page sizes taken from the Postscript PPD Standard v4.3 // See http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf // Excludes all Transverse and Rotated sizes // NB!This table needs to be in sync with QPageSize::PageSizeId const static StandardPageSize qt_pageSizes[] = { // Existing Qt sizes including ISO, US, ANSI and other standards {QPageSize::A4, "A4"}, {QPageSize::B5, "ISOB5"}, {QPageSize::Letter, "Letter"}, {QPageSize::Legal, "Legal"}, {QPageSize::Executive, "Executive.7.5x10in"}, // Qt size differs from Postscript / Windows {QPageSize::A0, "A0"}, {QPageSize::A1, "A1"}, {QPageSize::A2, "A2"}, {QPageSize::A3, "A3"}, {QPageSize::A5, "A5"}, {QPageSize::A6, "A6"}, {QPageSize::A7, "A7"}, {QPageSize::A8, "A8"}, {QPageSize::A9, "A9"}, {QPageSize::B0, "ISOB0"}, {QPageSize::B1, "ISOB1"}, {QPageSize::B10, "ISOB10"}, {QPageSize::B2, "ISOB2"}, {QPageSize::B3, "ISOB3"}, {QPageSize::B4, "ISOB4"}, {QPageSize::B6, "ISOB6"}, {QPageSize::B7, "ISOB7"}, {QPageSize::B8, "ISOB8"}, {QPageSize::B9, "ISOB9"}, {QPageSize::C5E, "EnvC5"}, {QPageSize::Comm10E, "Env10"}, {QPageSize::DLE, "EnvDL"}, {QPageSize::Folio, "Folio"}, {QPageSize::Ledger, "Ledger"}, {QPageSize::Tabloid, "Tabloid"}, {QPageSize::Custom, "Custom"}, // Special case to keep in sync with QPageSize::PageSizeId // ISO Standard Sizes {QPageSize::A10, "A10"}, {QPageSize::A3Extra, "A3Extra"}, {QPageSize::A4Extra, "A4Extra"}, {QPageSize::A4Plus, "A4Plus"}, {QPageSize::A4Small, "A4Small"}, {QPageSize::A5Extra, "A5Extra"}, {QPageSize::B5Extra, "ISOB5Extra"}, // JIS Standard Sizes {QPageSize::JisB0, "B0"}, {QPageSize::JisB1, "B1"}, {QPageSize::JisB2, "B2"}, {QPageSize::JisB3, "B3"}, {QPageSize::JisB4, "B4"}, {QPageSize::JisB5, "B5"}, {QPageSize::JisB6, "B6"}, {QPageSize::JisB7, "B7"}, {QPageSize::JisB8, "B8"}, {QPageSize::JisB9, "B9"}, {QPageSize::JisB10, "B10"}, // ANSI / US Standard sizes {QPageSize::AnsiC, "AnsiC"}, {QPageSize::AnsiD, "AnsiD"}, {QPageSize::AnsiE, "AnsiE"}, {QPageSize::LegalExtra, "LegalExtra"}, {QPageSize::LetterExtra, "LetterExtra"}, {QPageSize::LetterPlus, "LetterPlus"}, {QPageSize::LetterSmall, "LetterSmall"}, {QPageSize::TabloidExtra, "TabloidExtra"}, // Architectural sizes {QPageSize::ArchA, "ARCHA"}, {QPageSize::ArchB, "ARCHB"}, {QPageSize::ArchC, "ARCHC"}, {QPageSize::ArchD, "ARCHD"}, {QPageSize::ArchE, "ARCHE"}, // Inch-based Sizes {QPageSize::Imperial7x9, "7x9"}, {QPageSize::Imperial8x10, "8x10"}, {QPageSize::Imperial9x11, "9x11"}, {QPageSize::Imperial9x12, "9x12"}, {QPageSize::Imperial10x11, "10x11"}, {QPageSize::Imperial10x13, "10x13"}, {QPageSize::Imperial10x14, "10x14"}, {QPageSize::Imperial12x11, "12x11"}, {QPageSize::Imperial15x11, "15x11"}, // Other Page Sizes {QPageSize::ExecutiveStandard, "Executive"}, // Qt size differs from Postscript / Windows {QPageSize::Note, "Note"}, {QPageSize::Quarto, "Quarto"}, {QPageSize::Statement, "Statement"}, {QPageSize::SuperA, "SuperA"}, {QPageSize::SuperB, "SuperB"}, {QPageSize::Postcard, "Postcard"}, {QPageSize::DoublePostcard, "DoublePostcard"}, {QPageSize::Prc16K, "PRC16K"}, {QPageSize::Prc32K, "PRC32K"}, {QPageSize::Prc32KBig, "PRC32KBig"}, // Fan Fold Sizes {QPageSize::FanFoldUS, "FanFoldUS"}, {QPageSize::FanFoldGerman, "FanFoldGerman"}, {QPageSize::FanFoldGermanLegal, "FanFoldGermanLegal"}, // ISO Envelopes {QPageSize::EnvelopeB4, "EnvISOB4"}, {QPageSize::EnvelopeB5, "EnvISOB5"}, {QPageSize::EnvelopeB6, "EnvISOB6"}, {QPageSize::EnvelopeC0, "EnvC0"}, {QPageSize::EnvelopeC1, "EnvC1"}, {QPageSize::EnvelopeC2, "EnvC2"}, {QPageSize::EnvelopeC3, "EnvC3"}, {QPageSize::EnvelopeC4, "EnvC4"}, {QPageSize::EnvelopeC6, "EnvC6"}, {QPageSize::EnvelopeC65, "EnvC65"}, {QPageSize::EnvelopeC7, "EnvC7"}, // US Envelopes {QPageSize::Envelope9, "Env9"}, {QPageSize::Envelope11, "Env11"}, {QPageSize::Envelope12, "Env12"}, {QPageSize::Envelope14, "Env14"}, {QPageSize::EnvelopeMonarch, "EnvMonarch"}, {QPageSize::EnvelopePersonal, "EnvPersonal"}, // Other Envelopes {QPageSize::EnvelopeChou3, "EnvChou3"}, {QPageSize::EnvelopeChou4, "EnvChou4"}, {QPageSize::EnvelopeInvite, "EnvInvite"}, {QPageSize::EnvelopeItalian, "EnvItalian"}, {QPageSize::EnvelopeKaku2, "EnvKaku2"}, {QPageSize::EnvelopeKaku3, "EnvKaku3"}, {QPageSize::EnvelopePrc1, "EnvPRC1"}, {QPageSize::EnvelopePrc2, "EnvPRC2"}, {QPageSize::EnvelopePrc3, "EnvPRC3"}, {QPageSize::EnvelopePrc4, "EnvPRC4"}, {QPageSize::EnvelopePrc5, "EnvPRC5"}, {QPageSize::EnvelopePrc6, "EnvPRC6"}, {QPageSize::EnvelopePrc7, "EnvPRC7"}, {QPageSize::EnvelopePrc8, "EnvPRC8"}, {QPageSize::EnvelopePrc9, "EnvPRC9"}, {QPageSize::EnvelopePrc10, "EnvPRC10"}, {QPageSize::EnvelopeYou4, "EnvYou4"} }; // Return key name for PageSize static QString qt_keyForPageSizeId(QPageSize::PageSizeId id) { return QString::fromLatin1(qt_pageSizes[id].mediaOption); } // Return id name for PPD Key static QPageSize::PageSizeId qt_idForPpdKey(const QString &ppdKey) { if (ppdKey.isEmpty()) { return QPageSize::Custom; } for (int i = 0; i <= int(QPageSize::LastPageSize); ++i) { if (QLatin1String(qt_pageSizes[i].mediaOption) == ppdKey) { return qt_pageSizes[i].id; } } return QPageSize::Custom; } -Print::Print(QObject *parent) - : QObject(parent) +PrintPortal::PrintPortal(QObject *parent) + : QDBusAbstractAdaptor(parent) { } -Print::~Print() +PrintPortal::~PrintPortal() { } -uint Print::print(const QDBusObjectPath &handle, +uint PrintPortal::Print(const QDBusObjectPath &handle, const QString &app_id, const QString &parent_window, const QString &title, const QDBusUnixFileDescriptor &fd, const QVariantMap &options, QVariantMap &results) { qCDebug(XdgDesktopPortalKdePrint) << "Print called with parameters:"; qCDebug(XdgDesktopPortalKdePrint) << " handle: " << handle.path(); qCDebug(XdgDesktopPortalKdePrint) << " app_id: " << app_id; qCDebug(XdgDesktopPortalKdePrint) << " parent_window: " << parent_window; qCDebug(XdgDesktopPortalKdePrint) << " title: " << title; qCDebug(XdgDesktopPortalKdePrint) << " fd: " << fd.fileDescriptor(); qCDebug(XdgDesktopPortalKdePrint) << " options: " << options; QFile fileToPrint; if (fileToPrint.open(fd.fileDescriptor(), QIODevice::ReadOnly)) { QPrinter *printer = nullptr; // Use printer associated with token if possible if (options.contains(QLatin1String("token"))) { printer = m_printers.value(options.value(QLatin1String("token")).toUInt()); } else { // Use the last configured printer otherwise if (m_printers.count()) { printer = m_printers.last(); } } if (!printer) { qCDebug(XdgDesktopPortalKdePrint) << "Failed to print: no QPrinter what can be used for printing"; return 1; } // We are going to print to a file if (!printer->outputFileName().isEmpty()) { if (QFile::exists(printer->outputFileName())) { QFile::remove(printer->outputFileName()); } QByteArray pdfContent = fileToPrint.readAll(); QFile outputFile(printer->outputFileName()); if (outputFile.open(QIODevice::ReadWrite)) { outputFile.write(pdfContent); outputFile.close(); } else { qCDebug(XdgDesktopPortalKdePrint) << "Failed to print: couldn't open the file for writing"; } fileToPrint.close(); return 0; // TODO poscript support? // Print to a printer via lpr command } else { // The code below is copied from Okular bool useCupsOptions = cupsAvailable(); QString exe; QStringList argList; //Decide what executable to use to print with, need the CUPS version of lpr if available //Some distros name the CUPS version of lpr as lpr-cups or lpr.cups so try those first //before default to lpr, or failing that to lp if (!QStandardPaths::findExecutable(QStringLiteral("lpr-cups")).isEmpty()) { exe = QStringLiteral("lpr-cups"); } else if (!QStandardPaths::findExecutable(QStringLiteral("lpr.cups")).isEmpty()) { exe = QStringLiteral("lpr.cups"); } else if (!QStandardPaths::findExecutable(QStringLiteral("lpr")).isEmpty()) { exe = QStringLiteral("lpr"); } else if (!QStandardPaths::findExecutable(QStringLiteral("lp")).isEmpty()) { exe = QStringLiteral("lp"); } else { qCDebug(XdgDesktopPortalKdePrint) << "Failed to print: couldn't run lpr command for printing"; return 1; } QTemporaryFile tempFile; if (tempFile.open()) { tempFile.write(fileToPrint.readAll()); tempFile.close(); } else { qCDebug(XdgDesktopPortalKdePrint) << "Failed to print: couldn't create temporary file for printing"; return 1; } argList = printArguments(printer, useCupsOptions, exe, printer->orientation()) << tempFile.fileName(); // qCDebug(XdgDesktopPortalKdePrint) << "Executing" << exe << "with arguments" << argList << tempFile.fileName(); int retValue = KProcess::execute(exe, argList); if (retValue <= 0) { qCDebug(XdgDesktopPortalKdePrint) << "Failed to print: running KProcess failed"; return 1; } return retValue; } } else { qCDebug(XdgDesktopPortalKdePrint) << "Failed to print: couldn't not read from fd"; return 1; } return 0; } -uint Print::preparePrint(const QDBusObjectPath &handle, +uint PrintPortal::PreparePrint(const QDBusObjectPath &handle, const QString &app_id, const QString &parent_window, const QString &title, const QVariantMap &settings, const QVariantMap &page_setup, const QVariantMap &options, QVariantMap &results) { qCDebug(XdgDesktopPortalKdePrint) << "PreparePrint called with parameters:"; qCDebug(XdgDesktopPortalKdePrint) << " handle: " << handle.path(); qCDebug(XdgDesktopPortalKdePrint) << " app_id: " << app_id; qCDebug(XdgDesktopPortalKdePrint) << " parent_window: " << parent_window; qCDebug(XdgDesktopPortalKdePrint) << " title: " << title; qCDebug(XdgDesktopPortalKdePrint) << " settings: " << settings; qCDebug(XdgDesktopPortalKdePrint) << " page_setup: " << page_setup; qCDebug(XdgDesktopPortalKdePrint) << " options: " << options; // Create new one QPrinter *printer = new QPrinter(); // First we have to load pre-configured options // Process settings (used by printer) if (settings.contains(QLatin1String("orientation"))) { // TODO: what is the difference between this and the one in page setup } if (settings.contains(QLatin1String("paper-format"))) { // TODO: what is the difference between this and the one in page setup } if (settings.contains(QLatin1String("paper-width"))) { // TODO: what is the difference between this and the one in page setup } if (settings.contains(QLatin1String("paper-height"))) { // TODO: what is the difference between this and the one in page setup } if (settings.contains(QLatin1String("n-copies"))) { printer->setCopyCount(settings.value(QLatin1String("n-copies")).toString().toInt()); } if (settings.contains(QLatin1String("default-source"))) { // TODO seems to be windows only stuff } if (settings.contains(QLatin1String("quality"))) { // TODO doesn't seem to be used by Qt } if (settings.contains(QLatin1String("resolution"))) { printer->setResolution(settings.value(QLatin1String("resolution")).toString().toInt()); } if (settings.contains(QLatin1String("use-color"))) { printer->setColorMode(settings.value(QLatin1String("use-color")).toString() == QLatin1String("yes") ? QPrinter::Color : QPrinter::GrayScale); } if (settings.contains(QLatin1String("duplex"))) { const QString duplex = settings.value(QLatin1String("duplex")).toString(); if (duplex == QLatin1String("simplex")) { printer->setDuplex(QPrinter::DuplexNone); } else if (duplex == QLatin1String("horizontal")) { printer->setDuplex(QPrinter::DuplexShortSide); } else if (duplex == QLatin1String("vertical")) { printer->setDuplex(QPrinter::DuplexLongSide); } } if (settings.contains(QLatin1String("collate"))) { printer->setCollateCopies(settings.value(QLatin1String("collate")).toString() == QLatin1String("yes")); } if (settings.contains(QLatin1String("reverse"))) { printer->setPageOrder(settings.value(QLatin1String("reverse")).toString() == QLatin1String("yes") ? QPrinter::LastPageFirst : QPrinter::FirstPageFirst); } if (settings.contains(QLatin1String("media-type"))) { // TODO doesn't seem to be used by Qt } if (settings.contains(QLatin1String("dither"))) { // TODO doesn't seem to be used by Qt } if (settings.contains(QLatin1String("scale"))) { // TODO doesn't seem to be used by Qt } if (settings.contains(QLatin1String("print-pages"))) { const QString printPages = settings.value(QLatin1String("print-pages")).toString(); if (printPages == QLatin1String("all")) { printer->setPrintRange(QPrinter::AllPages); } else if (printPages == QLatin1String("selection")) { printer->setPrintRange(QPrinter::Selection); } else if (printPages == QLatin1String("current")) { printer->setPrintRange(QPrinter::CurrentPage); } else if (printPages == QLatin1String("ranges")) { printer->setPrintRange(QPrinter::PageRange); } } if (settings.contains(QLatin1String("page-ranges"))) { const QString range = settings.value(QLatin1String("page-ranges")).toString(); // Gnome supports format like 1-5,7,9,11-15, however Qt support only e.g.1-15 // so get the first and the last value const QStringList ranges = range.split(QLatin1Char(',')); if (ranges.count()) { QStringList firstRangeValues = ranges.first().split(QLatin1Char('-')); QStringList lastRangeValues = ranges.last().split(QLatin1Char('-')); printer->setFromTo(firstRangeValues.first().toInt(), lastRangeValues.last().toInt()); } } if (settings.contains(QLatin1String("page-set"))) { // WARNING Qt internal private API, anyway the print dialog doesn't seem to // read these propertis, but I'll leave it here in case this changes in future const QString pageSet = settings.value(QLatin1String("page-set")).toString(); if (pageSet == QLatin1String("all")) { QCUPSSupport::setPageSet(printer, QCUPSSupport::AllPages); } else if (pageSet == QLatin1String("even")) { QCUPSSupport::setPageSet(printer, QCUPSSupport::EvenPages); } else if (pageSet == QLatin1String("odd")) { QCUPSSupport::setPageSet(printer, QCUPSSupport::OddPages); } } if (settings.contains(QLatin1String("finishings"))) { // TODO doesn't seem to be used by Qt } QCUPSSupport::PagesPerSheet pagesPerSheet = QCUPSSupport::OnePagePerSheet; QCUPSSupport::PagesPerSheetLayout pagesPerSheetLayout = QCUPSSupport::LeftToRightTopToBottom; if (settings.contains(QLatin1String("number-up"))) { // WARNING Qt internal private API, anyway the print dialog doesn't seem to // read these propertis, but I'll leave it here in case this changes in future const QString numberUp = settings.value(QLatin1String("number-up")).toString(); if (numberUp == QLatin1String("1")) { pagesPerSheet = QCUPSSupport::OnePagePerSheet; } else if (numberUp == QLatin1String("2")) { pagesPerSheet = QCUPSSupport::TwoPagesPerSheet; } else if (numberUp == QLatin1String("4")) { pagesPerSheet = QCUPSSupport::FourPagesPerSheet; } else if (numberUp == QLatin1String("6")) { pagesPerSheet = QCUPSSupport::SixPagesPerSheet; } else if (numberUp == QLatin1String("9")) { pagesPerSheet = QCUPSSupport::NinePagesPerSheet; } else if (numberUp == QLatin1String("16")) { pagesPerSheet = QCUPSSupport::SixteenPagesPerSheet; } } if (settings.contains(QLatin1String("number-up-layout"))) { // WARNING Qt internal private API, anyway the print dialog doesn't seem to // read these propertis, but I'll leave it here in case this changes in future const QString layout = settings.value(QLatin1String("number-up-layout")).toString(); if (layout == QLatin1String("lrtb")) { pagesPerSheetLayout = QCUPSSupport::LeftToRightTopToBottom; } else if (layout == QLatin1String("lrbt")) { pagesPerSheetLayout = QCUPSSupport::LeftToRightBottomToTop; } else if (layout == QLatin1String("rltb")) { pagesPerSheetLayout = QCUPSSupport::RightToLeftTopToBottom; } else if (layout == QLatin1String("rlbt")) { pagesPerSheetLayout = QCUPSSupport::RightToLeftBottomToTop; } else if (layout == QLatin1String("tblr")) { pagesPerSheetLayout = QCUPSSupport::TopToBottomLeftToRight; } else if (layout == QLatin1String("tbrl")) { pagesPerSheetLayout = QCUPSSupport::TopToBottomRightToLeft; } else if (layout == QLatin1String("btlr")) { pagesPerSheetLayout = QCUPSSupport::BottomToTopLeftToRight; } else if (layout == QLatin1String("btrl")) { pagesPerSheetLayout = QCUPSSupport::BottomToTopRightToLeft; } } QCUPSSupport::setPagesPerSheetLayout(printer, pagesPerSheet, pagesPerSheetLayout); if (settings.contains(QLatin1String("output-bin"))) { // TODO not sure what this setting represents } if (settings.contains(QLatin1String("resolution-x"))) { // TODO possible to set only full resolution, but I can count the total // resolution I guess, anyway doesn't seem to be used by the print dialog } if (settings.contains(QLatin1String("resolution-y"))) { // TODO possible to set only full resolution, but I can count the total // resolution I guess, anyway doesn't seem to be used by the print dialog } if (settings.contains(QLatin1String("printer-lpi"))) { // TODO not possible to set, maybe count it? } if (settings.contains(QLatin1String("output-basename"))) { // TODO processed in output-uri // printer->setOutputFileName(settings.value(QLatin1String("output-basename")).toString()); } if (settings.contains(QLatin1String("output-file-format"))) { // TODO only PDF supported by Qt so when printing to file we can use PDF only // btw. this should be already set automatically because we set output file name printer->setOutputFormat(QPrinter::PdfFormat); } if (settings.contains(QLatin1String("output-uri"))) { const QUrl uri = QUrl(settings.value(QLatin1String("output-uri")).toString()); // Check whether the uri is not just a directory name and whether we don't need to // append output-basename if (settings.contains(QLatin1String("output-basename"))) { const QString basename = settings.value(QLatin1String("output-basename")).toString(); if (!uri.toDisplayString().endsWith(basename) && uri.toDisplayString().endsWith(QLatin1Char('/'))) { printer->setOutputFileName(uri.toDisplayString() + basename); } } else { printer->setOutputFileName(uri.toDisplayString()); } } // Process page setup QMarginsF pageMargins = printer->pageLayout().margins(QPageLayout::Millimeter); if (page_setup.contains(QLatin1String("PPDName"))) { printer->setPageSize(QPageSize(qt_idForPpdKey(page_setup.value(QLatin1String("PPDName")).toString()))); } if (page_setup.contains(QLatin1String("Name"))) { // TODO: Try to use name instead of PPDName, at least I think it's how it's supposed to be used if (!page_setup.contains(QLatin1String("PPDName"))) { printer->setPageSize(QPageSize(qt_idForPpdKey(page_setup.value(QLatin1String("PPDName")).toString()))); } } if (page_setup.contains(QLatin1String("DisplayName"))) { // TODO: This should just set a different name for the standardized one I guess printer->setPageSize(QPageSize(printer->pageLayout().pageSize().size(QPageSize::Millimeter), QPageSize::Millimeter, page_setup.value(QLatin1String("DisplayName")).toString())); } if (page_setup.contains(QLatin1String("Width")) && page_setup.contains(QLatin1String("Height"))) { QSizeF paperSize; paperSize.setHeight(page_setup.value(QLatin1String("Height")).toReal()); paperSize.setWidth(page_setup.value(QLatin1String("Width")).toReal()); printer->setPageSize(QPageSize(paperSize, QPageSize::Millimeter, page_setup.value(QLatin1String("DisplayName")).toString())); } if (page_setup.contains(QLatin1String("MarginTop"))) { pageMargins.setTop(page_setup.value(QLatin1String("MarginTop")).toReal()); } if (page_setup.contains(QLatin1String("MarginBottom"))) { pageMargins.setBottom(page_setup.value(QLatin1String("MarginBottom")).toReal()); } if (page_setup.contains(QLatin1String("MarginLeft"))) { pageMargins.setLeft(page_setup.value(QLatin1String("MarginLeft")).toReal()); } if (page_setup.contains(QLatin1String("MarginRight"))) { pageMargins.setRight(page_setup.value(QLatin1String("MarginLeft")).toReal()); } if (page_setup.contains(QLatin1String("Orientation"))) { const QString orientation = page_setup.value(QLatin1String("Orientation")).toString(); if (orientation == QLatin1String("landscape") || orientation == QLatin1String("reverse_landscape")) { printer->setPageOrientation(QPageLayout::Landscape); } else if (orientation == QLatin1String("portrait") || orientation == QLatin1String("reverse_portrait")) { printer->setPageOrientation(QPageLayout::Portrait); } } printer->setPageMargins(pageMargins, QPageLayout::Millimeter); QPrintDialog *printDialog = new QPrintDialog(printer); // Process options if (options.contains(QLatin1String("modal"))) { printDialog->setModal(options.value(QLatin1String("modal")).toBool()); } // Pass back what we configured if (printDialog->exec() == QDialog::Accepted) { QVariantMap resultingSettings; QVariantMap resultingPageSetup; // Process back printer settings resultingSettings.insert(QLatin1String("n-copies"), QString::number(printer->copyCount())); resultingSettings.insert(QLatin1String("resolution"), QString::number(printer->resolution())); resultingSettings.insert(QLatin1String("use-color"), printer->colorMode() == QPrinter::Color ? QLatin1String("yes") : QLatin1String("no")); if (printer->duplex() == QPrinter::DuplexNone) { resultingSettings.insert(QLatin1String("duplex"), QLatin1String("simplex")); } else if (printer->duplex() == QPrinter::DuplexShortSide) { resultingSettings.insert(QLatin1String("duplex"), QLatin1String("horizontal")); } else if (printer->duplex() == QPrinter::DuplexLongSide) { resultingSettings.insert(QLatin1String("duplex"), QLatin1String("vertical")); } resultingSettings.insert(QLatin1String("collate"), printer->collateCopies() ? QLatin1String("yes") : QLatin1String("no")); resultingSettings.insert(QLatin1String("reverse"), printer->pageOrder() == QPrinter::LastPageFirst ? QLatin1String("yes") : QLatin1String("no")); if (printer->printRange() == QPrinter::AllPages) { resultingSettings.insert(QLatin1String("print-pages"), QLatin1String("all")); } else if (printer->printRange() == QPrinter::Selection) { resultingSettings.insert(QLatin1String("print-pages"), QLatin1String("selection")); } else if (printer->printRange() == QPrinter::CurrentPage) { resultingSettings.insert(QLatin1String("print-pages"), QLatin1String("current")); } else if (printer->printRange() == QPrinter::PageRange) { resultingSettings.insert(QLatin1String("print-pages"), QLatin1String("ranges")); resultingSettings.insert(QLatin1String("page-ranges"), QString("%1-%2").arg(printer->fromPage()).arg(printer->toPage())); } // Set cups specific properties const QStringList cupsOptions = QCUPSSupport::cupsOptionsList(printer); qCDebug(XdgDesktopPortalKdePrint) << cupsOptions; if (cupsOptions.contains(QLatin1String("page-set"))) { resultingSettings.insert(QLatin1String("page-set"), cupsOptions.at(cupsOptions.indexOf(QLatin1String("page-set")) + 1)); } if (cupsOptions.contains(QLatin1String("number-up"))) { resultingSettings.insert(QLatin1String("number-up"), cupsOptions.at(cupsOptions.indexOf(QLatin1String("number-up")) + 1)); } if (cupsOptions.contains(QLatin1String("number-up-layout"))) { resultingSettings.insert(QLatin1String("number-up-layout"), cupsOptions.at(cupsOptions.indexOf(QLatin1String("number-up-layout")) + 1)); } if (printer->outputFormat() == QPrinter::PdfFormat) { resultingSettings.insert(QLatin1String("output-file-format"), QLatin1String("pdf")); } if (!printer->outputFileName().isEmpty()) { resultingSettings.insert(QLatin1String("output-uri"), QUrl::fromLocalFile(printer->outputFileName()).toDisplayString()); } // Process back page setup resultingPageSetup.insert(QLatin1String("PPDName"), qt_keyForPageSizeId(printer->pageLayout().pageSize().id())); // TODO: verify if this make sense resultingPageSetup.insert(QLatin1String("Name"), qt_keyForPageSizeId(printer->pageLayout().pageSize().id())); // TODO: verify if this make sense resultingPageSetup.insert(QLatin1String("DisplayName"), qt_keyForPageSizeId(printer->pageLayout().pageSize().id())); resultingPageSetup.insert(QLatin1String("Width"), printer->pageLayout().pageSize().size(QPageSize::Millimeter).width()); resultingPageSetup.insert(QLatin1String("Height"), printer->pageLayout().pageSize().size(QPageSize::Millimeter).height()); resultingPageSetup.insert(QLatin1String("MarginTop"), printer->pageLayout().margins(QPageLayout::Millimeter).top()); resultingPageSetup.insert(QLatin1String("MarginBottom"), printer->pageLayout().margins(QPageLayout::Millimeter).bottom()); resultingPageSetup.insert(QLatin1String("MarginLeft"), printer->pageLayout().margins(QPageLayout::Millimeter).left()); resultingPageSetup.insert(QLatin1String("MarginRight"), printer->pageLayout().margins(QPageLayout::Millimeter).right()); resultingPageSetup.insert(QLatin1String("Orientation"), printer->pageLayout().orientation() == QPageLayout::Landscape ? QLatin1String("landscape") : QLatin1String("portrait")); qCDebug(XdgDesktopPortalKdePrint) << "Settings: "; qCDebug(XdgDesktopPortalKdePrint) << "---------------------------"; qCDebug(XdgDesktopPortalKdePrint) << resultingSettings; qCDebug(XdgDesktopPortalKdePrint) << "Page setup: "; qCDebug(XdgDesktopPortalKdePrint) << "---------------------------"; qCDebug(XdgDesktopPortalKdePrint) << resultingPageSetup; uint token = QDateTime::currentDateTime().toTime_t(); results.insert(QLatin1String("settings"), resultingSettings); results.insert(QLatin1String("page-setup"), resultingPageSetup); results.insert(QLatin1String("token"), token); m_printers.insert(token, printer); printDialog->deleteLater(); return 0; } else { printDialog->deleteLater(); return 1; } return 0; } -QStringList Print::destination(const QPrinter *printer, const QString &version) +QStringList PrintPortal::destination(const QPrinter *printer, const QString &version) { if (version == QLatin1String("lp")) { return QStringList(QStringLiteral("-d")) << printer->printerName(); } if (version.startsWith(QLatin1String("lpr"))) { return QStringList(QStringLiteral("-P")) << printer->printerName(); } return QStringList(); } -QStringList Print::copies(const QPrinter *printer, const QString &version) +QStringList PrintPortal::copies(const QPrinter *printer, const QString &version) { int cp = printer->actualNumCopies(); if (version == QLatin1String("lp")) { return QStringList(QStringLiteral("-n")) << QStringLiteral("%1").arg(cp); } if (version.startsWith(QLatin1String("lpr"))) { return QStringList() << QStringLiteral("-#%1").arg(cp); } return QStringList(); } -QStringList Print::jobname(const QPrinter *printer, const QString &version) +QStringList PrintPortal::jobname(const QPrinter *printer, const QString &version) { if (!printer->docName().isEmpty()) { if (version == QLatin1String("lp")) { return QStringList(QStringLiteral("-t")) << printer->docName(); } if (version.startsWith(QLatin1String("lpr"))) { const QString shortenedDocName = QString::fromUtf8(printer->docName().toUtf8().left(255)); return QStringList(QStringLiteral("-J")) << shortenedDocName; } } return QStringList(); } // What about Upper and MultiPurpose? And others in PPD??? -QString Print::mediaPaperSource(const QPrinter *printer) +QString PrintPortal::mediaPaperSource(const QPrinter *printer) { switch (printer->paperSource()) { case QPrinter::Auto: return QString(); case QPrinter::Cassette: return QStringLiteral("Cassette"); case QPrinter::Envelope: return QStringLiteral("Envelope"); case QPrinter::EnvelopeManual: return QStringLiteral("EnvelopeManual"); case QPrinter::FormSource: return QStringLiteral("FormSource"); case QPrinter::LargeCapacity: return QStringLiteral("LargeCapacity"); case QPrinter::LargeFormat: return QStringLiteral("LargeFormat"); case QPrinter::Lower: return QStringLiteral("Lower"); case QPrinter::MaxPageSource: return QStringLiteral("MaxPageSource"); case QPrinter::Middle: return QStringLiteral("Middle"); case QPrinter::Manual: return QStringLiteral("Manual"); case QPrinter::OnlyOne: return QStringLiteral("OnlyOne"); case QPrinter::Tractor: return QStringLiteral("Tractor"); case QPrinter::SmallFormat: return QStringLiteral("SmallFormat"); default: return QString(); } } -QStringList Print::optionOrientation(const QPrinter *printer, QPrinter::Orientation documentOrientation) +QStringList PrintPortal::optionOrientation(const QPrinter *printer, QPrinter::Orientation documentOrientation) { // portrait and landscape options rotate the document according to the document orientation // If we want to print a landscape document as one would expect it, we have to pass the // portrait option so that the document is not rotated additionally if (printer->orientation() == documentOrientation) { // the user wants the document printed as is return QStringList(QStringLiteral("-o")) << QStringLiteral("portrait"); } else { // the user expects the document being rotated by 90 degrees return QStringList(QStringLiteral("-o")) << QStringLiteral("landscape"); } } -QStringList Print::optionDoubleSidedPrinting(const QPrinter *printer) +QStringList PrintPortal::optionDoubleSidedPrinting(const QPrinter *printer) { switch (printer->duplex()) { case QPrinter::DuplexNone: return QStringList(QStringLiteral("-o")) << QStringLiteral("sides=one-sided"); case QPrinter::DuplexAuto: if (printer->orientation() == QPrinter::Landscape) { return QStringList(QStringLiteral("-o")) << QStringLiteral("sides=two-sided-short-edge"); } else { return QStringList(QStringLiteral("-o")) << QStringLiteral("sides=two-sided-long-edge"); } case QPrinter::DuplexLongSide: return QStringList(QStringLiteral("-o")) << QStringLiteral("sides=two-sided-long-edge"); case QPrinter::DuplexShortSide: return QStringList(QStringLiteral("-o")) << QStringLiteral("sides=two-sided-short-edge"); default: return QStringList(); //Use printer default } } -QStringList Print::optionPageOrder(const QPrinter *printer) +QStringList PrintPortal::optionPageOrder(const QPrinter *printer) { if (printer->pageOrder() == QPrinter::LastPageFirst) { return QStringList(QStringLiteral("-o")) << QStringLiteral("outputorder=reverse"); } return QStringList(QStringLiteral("-o")) << QStringLiteral("outputorder=normal"); } -QStringList Print::optionCollateCopies(const QPrinter *printer) +QStringList PrintPortal::optionCollateCopies(const QPrinter *printer) { if (printer->collateCopies()) { return QStringList(QStringLiteral("-o")) << QStringLiteral("Collate=True"); } return QStringList(QStringLiteral("-o")) << QStringLiteral("Collate=False"); } -QStringList Print::optionPageMargins(const QPrinter *printer) +QStringList PrintPortal::optionPageMargins(const QPrinter *printer) { if (printer->printEngine()->property(QPrintEngine::PPK_PageMargins).isNull()) { return QStringList(); } else { qreal l, t, r, b; printer->getPageMargins(&l, &t, &r, &b, QPrinter::Point); return QStringList(QStringLiteral("-o")) << QStringLiteral("page-left=%1").arg(l) << QStringLiteral("-o") << QStringLiteral("page-top=%1").arg(t) << QStringLiteral("-o") << QStringLiteral("page-right=%1").arg(r) << QStringLiteral("-o") << QStringLiteral("page-bottom=%1").arg(b) << QStringLiteral("-o") << QStringLiteral("fit-to-page"); } } -QStringList Print::optionCupsProperties(const QPrinter *printer) +QStringList PrintPortal::optionCupsProperties(const QPrinter *printer) { QStringList dialogOptions = printer->printEngine()->property(QPrintEngine::PrintEnginePropertyKey(0xfe00)).toStringList(); QStringList cupsOptions; for (int i = 0; i < dialogOptions.count(); i = i + 2) { // Ignore some cups properties as the pdf we get is already formatted using these if (dialogOptions[i] == QLatin1String("number-up") || dialogOptions[i] == QLatin1String("number-up-layout")) { continue; } if (dialogOptions[i + 1].isEmpty()) { cupsOptions << QStringLiteral("-o") << dialogOptions[i]; } else { cupsOptions << QStringLiteral("-o") << dialogOptions[i] + QLatin1Char('=') + dialogOptions[i + 1]; } } return cupsOptions; } -QStringList Print::optionMedia(const QPrinter *printer) +QStringList PrintPortal::optionMedia(const QPrinter *printer) { if (!qt_keyForPageSizeId(printer->pageLayout().pageSize().id()).isEmpty() && !mediaPaperSource(printer).isEmpty()) { return QStringList(QStringLiteral("-o")) << QStringLiteral("media=%1,%2").arg(qt_keyForPageSizeId(printer->pageLayout().pageSize().id()), mediaPaperSource(printer)); } if (!qt_keyForPageSizeId(printer->pageLayout().pageSize().id()).isEmpty()) { return QStringList(QStringLiteral("-o")) << QStringLiteral("media=%1").arg(qt_keyForPageSizeId(printer->pageLayout().pageSize().id())); } if (!mediaPaperSource(printer).isEmpty()) { return QStringList(QStringLiteral("-o")) << QStringLiteral("media=%1").arg(mediaPaperSource(printer)); } return QStringList(); } -QStringList Print::pages(const QPrinter *printer, bool useCupsOptions, const QString &version) +QStringList PrintPortal::pages(const QPrinter *printer, bool useCupsOptions, const QString &version) { if (printer->printRange() == QPrinter::PageRange) { if (version == QLatin1String("lp")) { return QStringList(QStringLiteral("-P")) << QStringLiteral("%1-%2").arg(printer->fromPage()) .arg(printer->toPage()); } if (version.startsWith(QLatin1String("lpr")) && useCupsOptions) { return QStringList(QStringLiteral("-o")) << QStringLiteral("page-ranges=%1-%2").arg(printer->fromPage()) .arg(printer->toPage()); } } return QStringList(); // AllPages } -QStringList Print::cupsOptions(const QPrinter *printer, QPrinter::Orientation documentOrientation) +QStringList PrintPortal::cupsOptions(const QPrinter *printer, QPrinter::Orientation documentOrientation) { QStringList optionList; // if (!optionMedia(printer).isEmpty()) { // optionList << optionMedia(printer); // } // if (!optionOrientation(printer, documentOrientation).isEmpty()) { // optionList << optionOrientation(printer, documentOrientation); // } if (!optionDoubleSidedPrinting(printer).isEmpty()) { optionList << optionDoubleSidedPrinting(printer); } if (!optionPageOrder(printer).isEmpty()) { optionList << optionPageOrder(printer); } if (!optionCollateCopies(printer).isEmpty()) { optionList << optionCollateCopies(printer); } // if (!optionPageMargins(printer).isEmpty()) { // optionList << optionPageMargins(printer); // } optionList << optionCupsProperties(printer); return optionList; } -QStringList Print::printArguments(const QPrinter *printer, bool useCupsOptions, +QStringList PrintPortal::printArguments(const QPrinter *printer, bool useCupsOptions, const QString &version, QPrinter::Orientation documentOrientation) { QStringList argList; if (!destination(printer, version).isEmpty()) { argList << destination(printer, version); } // if (!copies(printer, version).isEmpty()) { // argList << copies(printer, version); // } if (!jobname(printer, version).isEmpty()) { argList << jobname(printer, version); } // if (!pages(printer, useCupsOptions, version).isEmpty()) { // argList << pages(printer, useCupsOptions, version); // } if (useCupsOptions && !cupsOptions(printer, documentOrientation).isEmpty()) { argList << cupsOptions(printer, documentOrientation); } if (version == QLatin1String("lp")) { argList << QStringLiteral("--"); } return argList; } -bool Print::cupsAvailable() +bool PrintPortal::cupsAvailable() { // Ideally we would have access to the private Qt method // QCUPSSupport::cupsAvailable() to do this as it is very complex routine. // However, if CUPS is available then QPrinter::numCopies() will always return 1 // whereas if CUPS is not available it will return the real number of copies. // This behaviour is guaranteed never to change, so we can use it as a reliable substitute. QPrinter testPrinter; testPrinter.setNumCopies(2); return (testPrinter.numCopies() == 1); } diff --git a/src/print.h b/src/print.h index ff823c7..9718167 100644 --- a/src/print.h +++ b/src/print.h @@ -1,77 +1,77 @@ /* * Copyright © 2016 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #ifndef XDG_DESKTOP_PORTAL_KDE_PRINT_H #define XDG_DESKTOP_PORTAL_KDE_PRINT_H -#include +#include #include #include #include #include -class Print : public QObject +class PrintPortal : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.Print") public: - Print(QObject *parent = nullptr); - ~Print(); + PrintPortal(QObject *parent); + ~PrintPortal(); public Q_SLOTS: - uint print(const QDBusObjectPath &handle, + uint Print(const QDBusObjectPath &handle, const QString &app_id, const QString &parent_window, const QString &title, const QDBusUnixFileDescriptor &fd, const QVariantMap &options, QVariantMap &results); - uint preparePrint(const QDBusObjectPath &handle, + uint PreparePrint(const QDBusObjectPath &handle, const QString &app_id, const QString &parent_window, const QString &title, const QVariantMap &settings, const QVariantMap &page_setup, const QVariantMap &options, QVariantMap &results); private: QMap m_printers; bool cupsAvailable(); QStringList printArguments(const QPrinter *printer, bool useCupsOptions, const QString &version, QPrinter::Orientation documentOrientation); QStringList destination(const QPrinter *printer, const QString &version); QStringList copies(const QPrinter *printer, const QString &version); QStringList jobname(const QPrinter *printer, const QString &version); QStringList cupsOptions(const QPrinter *printer, QPrinter::Orientation documentOrientation); QStringList pages(const QPrinter *printer, bool useCupsOptions, const QString &version); QStringList optionMedia(const QPrinter *printer); QString mediaPaperSource(const QPrinter *printer); QStringList optionOrientation(const QPrinter *printer, QPrinter::Orientation documentOrientation); QStringList optionDoubleSidedPrinting(const QPrinter *printer); QStringList optionPageOrder(const QPrinter *printer); QStringList optionCollateCopies(const QPrinter *printer); QStringList optionPageMargins(const QPrinter *printer); QStringList optionCupsProperties(const QPrinter *printer); }; #endif // XDG_DESKTOP_PORTAL_KDE_PRINT_H diff --git a/src/xdg-desktop-portal-kde.cpp b/src/xdg-desktop-portal-kde.cpp index ad48e79..98f3039 100644 --- a/src/xdg-desktop-portal-kde.cpp +++ b/src/xdg-desktop-portal-kde.cpp @@ -1,48 +1,48 @@ /* * Copyright © 2016 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #include #include #include #include "desktopportal.h" Q_LOGGING_CATEGORY(XdgDesktopPortalKde, "xdg-desktop-portal-kde") int main(int argc, char *argv[]) { QApplication a(argc, argv); a.setQuitOnLastWindowClosed(false); QDBusConnection sessionBus = QDBusConnection::sessionBus(); if (sessionBus.registerService(QLatin1String("org.freedesktop.impl.portal.desktop.kde"))) { DesktopPortal *desktopPortal = new DesktopPortal(&a); - if (sessionBus.registerVirtualObject(QLatin1String("/org/freedesktop/portal/desktop"), desktopPortal, QDBusConnection::VirtualObjectRegisterOption::SingleNode)) { + if (sessionBus.registerObject(QLatin1String("/org/freedesktop/portal/desktop"), desktopPortal, QDBusConnection::ExportAdaptors)) { qCDebug(XdgDesktopPortalKde) << "Desktop portal registered successfuly"; } else { qCDebug(XdgDesktopPortalKde) << "Failed to register desktop portal"; } } else { qCDebug(XdgDesktopPortalKde) << "Failed to register org.freedesktop.impl.portal.desktop.kde service"; } return a.exec(); }