diff --git a/CMakeLists.txt b/CMakeLists.txt
index 329b594..7d19ce8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,79 +1,80 @@
cmake_minimum_required(VERSION 3.0)
project(xdg-desktop-portal-kde)
set(PROJECT_VERSION "5.14.80")
set(PROJECT_VERSION_MAJOR 5)
set(QT_MIN_VERSION "5.11.0")
set(KF5_MIN_VERSION "5.48.0")
################# set KDE specific information #################
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
include(FeatureSummary)
find_package(GLIB2)
set_package_properties(GLIB2 PROPERTIES
TYPE OPTIONAL
PURPOSE "Required for screencast portal"
)
find_package(PipeWire)
set_package_properties(PipeWire PROPERTIES
TYPE OPTIONAL
PURPOSE "Required for screencast portal"
)
find_package(GBM)
set_package_properties(GBM PROPERTIES
TYPE OPTIONAL
PURPOSE "Required for screencast portal"
)
find_package(Epoxy)
set_package_properties(Epoxy PROPERTIES DESCRIPTION "libepoxy"
URL "http://github.com/anholt/libepoxy"
TYPE OPTIONAL
PURPOSE "Required for screencast portal"
)
if (PipeWire_FOUND AND GLIB2_FOUND AND GBM_FOUND AND Epoxy_FOUND)
set (SCREENCAST_ENABLED true)
else()
set (SCREENCAST_ENABLED false)
endif()
add_definitions(-DSCREENCAST_ENABLED=${SCREENCAST_ENABLED})
add_feature_info ("Screencast portal" ${SCREENCAST_ENABLED} "Support for screen sharing")
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
Core
Concurrent
DBus
PrintSupport
Widgets
)
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED
CoreAddons
Config
I18n
KIO
Notifications
Wayland
WidgetsAddons
+ WindowSystem
)
add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0)
add_subdirectory(data)
add_subdirectory(src)
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 38fd2ce..c5167c8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,71 +1,73 @@
add_definitions(-DTRANSLATION_DOMAIN="xdg-desktop-portal-kde")
include_directories(${Qt5PrintSupport_PRIVATE_INCLUDE_DIRS})
set(xdg_desktop_portal_kde_SRCS
xdg-desktop-portal-kde.cpp
access.cpp
accessdialog.cpp
appchooser.cpp
appchooserdialog.cpp
appchooserdialogitem.cpp
desktopportal.cpp
email.cpp
filechooser.cpp
inhibit.cpp
notification.cpp
print.cpp
request.cpp
session.cpp
screenshot.cpp
screenshotdialog.cpp
settings.cpp
+ utils.cpp
)
if (SCREENCAST_ENABLED)
set (xdg_desktop_portal_kde_SRCS
${xdg_desktop_portal_kde_SRCS}
screencast.cpp
screencaststream.cpp
screencastwidget.cpp
screenchooserdialog.cpp
remotedesktop.cpp
remotedesktopdialog.cpp
waylandintegration.cpp)
ki18n_wrap_ui(xdg_desktop_portal_kde_SRCS
screenchooserdialog.ui
remotedesktopdialog.ui)
endif()
ki18n_wrap_ui(xdg_desktop_portal_kde_SRCS
accessdialog.ui
screenshotdialog.ui
)
add_executable(xdg-desktop-portal-kde ${xdg_desktop_portal_kde_SRCS})
target_link_libraries(xdg-desktop-portal-kde
Qt5::Core
Qt5::DBus
Qt5::Concurrent
Qt5::PrintSupport
Qt5::Widgets
KF5::CoreAddons
KF5::ConfigCore
KF5::I18n
KF5::KIOFileWidgets
KF5::Notifications
KF5::WaylandClient
KF5::WidgetsAddons
+ KF5::WindowSystem
)
if (SCREENCAST_ENABLED)
target_link_libraries(xdg-desktop-portal-kde
PipeWire::PipeWire
GLIB2::GLIB2
${Epoxy_LIBRARIES}
GBM::GBM)
endif()
install(TARGETS xdg-desktop-portal-kde DESTINATION ${KDE_INSTALL_LIBEXECDIR})
diff --git a/src/access.cpp b/src/access.cpp
index 70359b9..272a854 100644
--- a/src/access.cpp
+++ b/src/access.cpp
@@ -1,86 +1,88 @@
/*
* 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 "utils.h"
#include
#include
Q_LOGGING_CATEGORY(XdgDesktopPortalKdeAccess, "xdp-kde-access")
AccessPortal::AccessPortal(QObject *parent)
: QDBusAbstractAdaptor(parent)
{
}
AccessPortal::~AccessPortal()
{
}
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;
auto accessDialog = new ::AccessDialog();
+ Utils::setParentWindow(accessDialog, parent_window);
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/appchooser.cpp b/src/appchooser.cpp
index 41cde8f..280146f 100644
--- a/src/appchooser.cpp
+++ b/src/appchooser.cpp
@@ -1,82 +1,84 @@
/*
* Copyright © 2016-2018 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 "utils.h"
#include
#include
Q_LOGGING_CATEGORY(XdgDesktopPortalKdeAppChooser, "xdp-kde-app-chooser")
AppChooserPortal::AppChooserPortal(QObject *parent)
: QDBusAbstractAdaptor(parent)
{
}
AppChooserPortal::~AppChooserPortal()
{
}
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, latestChoice, options.value(QLatin1String("filename")).toString());
m_appChooserDialogs.insert(handle.path(), appDialog);
+ Utils::setParentWindow(appDialog, parent_window);
int result = appDialog->exec();
if (result) {
results.insert(QLatin1String("choice"), appDialog->selectedApplication());
}
m_appChooserDialogs.remove(handle.path());
appDialog->deleteLater();
return !result;
}
void AppChooserPortal::UpdateChoices(const QDBusObjectPath &handle, const QStringList &choices)
{
qCDebug(XdgDesktopPortalKdeAppChooser) << "UpdateChoices called with parameters:";
qCDebug(XdgDesktopPortalKdeAppChooser) << " handle: " << handle.path();
qCDebug(XdgDesktopPortalKdeAppChooser) << " choices: " << choices;
if (m_appChooserDialogs.contains(handle.path())) {
m_appChooserDialogs.value(handle.path())->updateChoices(choices);
}
}
diff --git a/src/filechooser.cpp b/src/filechooser.cpp
index 23c663b..f8838f2 100644
--- a/src/filechooser.cpp
+++ b/src/filechooser.cpp
@@ -1,312 +1,315 @@
/*
* Copyright © 2016-2018 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 "utils.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
Q_LOGGING_CATEGORY(XdgDesktopPortalKdeFileChooser, "xdp-kde-file-chooser")
// Keep in sync with qflatpakfiledialog from flatpak-platform-plugin
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 FileChooserPortal::Filter &filter)
{
arg.beginStructure();
arg << filter.type << filter.filterString;
arg.endStructure();
return arg;
}
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 FileChooserPortal::FilterList &filterList)
{
arg.beginStructure();
arg << filterList.userVisibleName << filterList.filters;
arg.endStructure();
return arg;
}
const QDBusArgument &operator >> (const QDBusArgument &arg, FileChooserPortal::FilterList &filterList)
{
QString userVisibleName;
FileChooserPortal::Filters filters;
arg.beginStructure();
arg >> userVisibleName >> filters;
filterList.userVisibleName = userVisibleName;
filterList.filters = filters;
arg.endStructure();
return arg;
}
FileDialog::FileDialog(QDialog *parent, Qt::WindowFlags flags)
: QDialog(parent, flags)
, m_fileWidget(new KFileWidget(QUrl(), this))
{
setLayout(new QVBoxLayout);
layout()->addWidget(m_fileWidget);
m_buttons = new QDialogButtonBox(this);
m_buttons->addButton(m_fileWidget->okButton(), QDialogButtonBox::AcceptRole);
m_buttons->addButton(m_fileWidget->cancelButton(), QDialogButtonBox::RejectRole);
connect(m_buttons, SIGNAL(rejected()), m_fileWidget, SLOT(slotCancel()));
connect(m_fileWidget->okButton(), SIGNAL(clicked(bool)), m_fileWidget, SLOT(slotOk()));
connect(m_fileWidget, SIGNAL(accepted()), m_fileWidget, SLOT(accept()));
connect(m_fileWidget, SIGNAL(accepted()), SLOT(accept()));
connect(m_fileWidget->cancelButton(), SIGNAL(clicked(bool)), SLOT(reject()));
layout()->addWidget(m_buttons);
}
FileDialog::~FileDialog()
{
}
FileChooserPortal::FileChooserPortal(QObject *parent)
: QDBusAbstractAdaptor(parent)
{
qDBusRegisterMetaType();
qDBusRegisterMetaType();
qDBusRegisterMetaType();
qDBusRegisterMetaType();
}
FileChooserPortal::~FileChooserPortal()
{
}
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")));
for (const FilterList &filterList : filterListList) {
QStringList filterStrings;
for (const Filter &filterStruct : filterList.filters) {
if (filterStruct.type == 0) {
filterStrings << filterStruct.filterString;
} else {
mimeTypeFilters << filterStruct.filterString;
}
}
if (!filterStrings.isEmpty()) {
nameFilters << QStringLiteral("%1|%2").arg(filterStrings.join(QLatin1Char(' '))).arg(filterList.userVisibleName);
}
}
}
QScopedPointer fileDialog(new FileDialog());
+ Utils::setParentWindow(fileDialog.data(), parent_window);
fileDialog->setWindowTitle(title);
fileDialog->setModal(modalDialog);
fileDialog->m_fileWidget->setMode(multipleFiles ? KFile::Mode::File | KFile::Mode::ExistingOnly : KFile::Mode::Files | KFile::Mode::ExistingOnly);
fileDialog->m_fileWidget->okButton()->setText(!acceptLabel.isEmpty() ? acceptLabel : i18n("Open"));
if (!nameFilters.isEmpty()) {
fileDialog->m_fileWidget->setFilter(nameFilters.join(QLatin1Char('\n')));
}
if (!mimeTypeFilters.isEmpty()) {
fileDialog->m_fileWidget->setMimeFilter(mimeTypeFilters);
}
if (fileDialog->exec() == QDialog::Accepted) {
QStringList files;
for (const QString &filename : fileDialog->m_fileWidget->selectedFiles()) {
QUrl url = QUrl::fromLocalFile(filename);
files << url.toDisplayString();
}
results.insert(QLatin1String("uris"), files);
return 0;
}
return 1;
}
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 = QString::fromUtf8(options.value(QLatin1String("current_folder")).toByteArray());
}
if (options.contains(QLatin1String("current_file"))) {
currentFile = QString::fromUtf8(options.value(QLatin1String("current_file")).toByteArray());
}
if (options.contains(QLatin1String("filters"))) {
FilterListList filterListList = qdbus_cast(options.value(QLatin1String("filters")));
for (const FilterList &filterList : filterListList) {
QStringList filterStrings;
for (const Filter &filterStruct : filterList.filters) {
if (filterStruct.type == 0) {
filterStrings << filterStruct.filterString;
} else {
mimeTypeFilters << filterStruct.filterString;
}
}
if (!filterStrings.isEmpty()) {
nameFilters << QStringLiteral("%1|%2").arg(filterStrings.join(QLatin1Char(' '))).arg(filterList.userVisibleName);
}
}
}
QScopedPointer fileDialog(new FileDialog());
+ Utils::setParentWindow(fileDialog.data(), parent_window);
fileDialog->setWindowTitle(title);
fileDialog->setModal(modalDialog);
fileDialog->m_fileWidget->setOperationMode(KFileWidget::Saving);
if (!currentFolder.isEmpty()) {
fileDialog->m_fileWidget->setUrl(QUrl::fromLocalFile(currentFolder));
}
if (!currentFile.isEmpty()) {
fileDialog->m_fileWidget->setSelectedUrl(QUrl::fromLocalFile(currentFile));
}
if (!currentName.isEmpty()) {
const QUrl url = fileDialog->m_fileWidget->baseUrl();
fileDialog->m_fileWidget->setSelectedUrl(QUrl::fromLocalFile(QStringLiteral("%1/%2").arg(url.toDisplayString(QUrl::StripTrailingSlash), currentName)));
}
if (!acceptLabel.isEmpty()) {
fileDialog->m_fileWidget->okButton()->setText(acceptLabel);
}
if (!nameFilters.isEmpty()) {
fileDialog->m_fileWidget->setFilter(nameFilters.join(QLatin1Char('\n')));
}
if (!mimeTypeFilters.isEmpty()) {
fileDialog->m_fileWidget->setMimeFilter(mimeTypeFilters);
}
if (fileDialog->exec() == QDialog::Accepted) {
QStringList files;
QUrl url = QUrl::fromLocalFile(fileDialog->m_fileWidget->selectedFile());
files << url.toDisplayString();
results.insert(QLatin1String("uris"), files);
return 0;
}
return 1;
}
diff --git a/src/print.cpp b/src/print.cpp
index 3132578..cdefc17 100644
--- a/src/print.cpp
+++ b/src/print.cpp
@@ -1,977 +1,979 @@
/*
* 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 "utils.h"
#include
#include
#include
#include
#include
#include
#include
// #include
#include
#include
#include
Q_LOGGING_CATEGORY(XdgDesktopPortalKdePrint, "xdp-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;
}
PrintPortal::PrintPortal(QObject *parent)
: QDBusAbstractAdaptor(parent)
{
}
PrintPortal::~PrintPortal()
{
}
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 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 properties, 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 properties, 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 properties, 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);
+ Utils::setParentWindow(printDialog, parent_window);
// 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"), QStringLiteral("%1-%2").arg(printer->fromPage()).arg(printer->toPage()));
}
// Set cups specific properties
const QStringList cupsOptions = printer->printEngine()->property(PPK_CupsOptions).toStringList();
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 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 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 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 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 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 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 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 PrintPortal::optionCollateCopies(const QPrinter *printer)
{
if (printer->collateCopies()) {
return QStringList(QStringLiteral("-o")) << QStringLiteral("Collate=True");
}
return QStringList(QStringLiteral("-o")) << QStringLiteral("Collate=False");
}
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 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 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 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 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 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 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/screencast.cpp b/src/screencast.cpp
index 7e5ee33..a0566cf 100644
--- a/src/screencast.cpp
+++ b/src/screencast.cpp
@@ -1,168 +1,170 @@
/*
* Copyright © 2018 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 "screencast.h"
#include "screenchooserdialog.h"
#include "session.h"
#include "waylandintegration.h"
+#include "utils.h"
#include
Q_LOGGING_CATEGORY(XdgDesktopPortalKdeScreenCast, "xdp-kde-screencast")
ScreenCastPortal::ScreenCastPortal(QObject *parent)
: QDBusAbstractAdaptor(parent)
{
}
ScreenCastPortal::~ScreenCastPortal()
{
}
uint ScreenCastPortal::CreateSession(const QDBusObjectPath &handle,
const QDBusObjectPath &session_handle,
const QString &app_id,
const QVariantMap &options,
QVariantMap &results)
{
Q_UNUSED(results)
qCDebug(XdgDesktopPortalKdeScreenCast) << "CreateSession called with parameters:";
qCDebug(XdgDesktopPortalKdeScreenCast) << " handle: " << handle.path();
qCDebug(XdgDesktopPortalKdeScreenCast) << " session_handle: " << session_handle.path();
qCDebug(XdgDesktopPortalKdeScreenCast) << " app_id: " << app_id;
qCDebug(XdgDesktopPortalKdeScreenCast) << " options: " << options;
Session *session = Session::createSession(this, Session::ScreenCast, app_id, session_handle.path());
if (!session) {
return 2;
}
connect(session, &Session::closed, [this] () {
WaylandIntegration::stopStreaming();
});
return 0;
}
uint ScreenCastPortal::SelectSources(const QDBusObjectPath &handle,
const QDBusObjectPath &session_handle,
const QString &app_id,
const QVariantMap &options,
QVariantMap &results)
{
Q_UNUSED(results)
qCDebug(XdgDesktopPortalKdeScreenCast) << "SelectSource called with parameters:";
qCDebug(XdgDesktopPortalKdeScreenCast) << " handle: " << handle.path();
qCDebug(XdgDesktopPortalKdeScreenCast) << " session_handle: " << session_handle.path();
qCDebug(XdgDesktopPortalKdeScreenCast) << " app_id: " << app_id;
qCDebug(XdgDesktopPortalKdeScreenCast) << " options: " << options;
uint types = Monitor;
ScreenCastSession *session = qobject_cast(Session::getSession(session_handle.path()));
if (!session) {
qCWarning(XdgDesktopPortalKdeScreenCast) << "Tried to select sources on non-existing session " << session_handle.path();
return 2;
}
if (options.contains(QLatin1String("multiple"))) {
session->setMultipleSources(options.value(QLatin1String("multiple")).toBool());
}
if (options.contains(QLatin1String("types"))) {
types = (SourceType)(options.value(QLatin1String("types")).toUInt());
}
if (types == Window) {
qCWarning(XdgDesktopPortalKdeScreenCast) << "Screen cast of a window is not implemented";
return 2;
}
// Might be also a RemoteDesktopSession
if (session->type() == Session::RemoteDesktop) {
RemoteDesktopSession *remoteDesktopSession = qobject_cast(session);
if (remoteDesktopSession) {
remoteDesktopSession->setScreenSharingEnabled(true);
}
}
return 0;
}
uint ScreenCastPortal::Start(const QDBusObjectPath &handle,
const QDBusObjectPath &session_handle,
const QString &app_id,
const QString &parent_window,
const QVariantMap &options,
QVariantMap &results)
{
Q_UNUSED(results)
qCDebug(XdgDesktopPortalKdeScreenCast) << "Start called with parameters:";
qCDebug(XdgDesktopPortalKdeScreenCast) << " handle: " << handle.path();
qCDebug(XdgDesktopPortalKdeScreenCast) << " session_handle: " << session_handle.path();
qCDebug(XdgDesktopPortalKdeScreenCast) << " app_id: " << app_id;
qCDebug(XdgDesktopPortalKdeScreenCast) << " parent_window: " << parent_window;
qCDebug(XdgDesktopPortalKdeScreenCast) << " options: " << options;
ScreenCastSession *session = qobject_cast(Session::getSession(session_handle.path()));
if (!session) {
qCWarning(XdgDesktopPortalKdeScreenCast) << "Tried to call start on non-existing session " << session_handle.path();
return 2;
}
if (WaylandIntegration::screens().isEmpty()) {
qCWarning(XdgDesktopPortalKdeScreenCast) << "Failed to show dialog as there is no screen to select";
return 2;
}
if (!WaylandIntegration::isEGLInitialized()) {
qCWarning(XdgDesktopPortalKdeScreenCast) << "EGL is not properly initialized";
return 2;
}
QScopedPointer screenDialog(new ScreenChooserDialog(app_id, session->multipleSources()));
+ Utils::setParentWindow(screenDialog.data(), parent_window);
if (screenDialog->exec()) {
WaylandIntegration::WaylandOutput selectedOutput = WaylandIntegration::screens().value(screenDialog->selectedScreens().first());
if (!WaylandIntegration::startStreaming(selectedOutput)) {
return 2;
}
QVariant streams = WaylandIntegration::streams();
if (!streams.isValid()) {
qCWarning(XdgDesktopPortalKdeScreenCast) << "Pipewire stream is not ready to be streamed";
return 2;
}
results.insert(QLatin1String("streams"), streams);
return 0;
}
return 1;
}
diff --git a/src/screenshot.cpp b/src/screenshot.cpp
index ab5de3f..ac9d48a 100644
--- a/src/screenshot.cpp
+++ b/src/screenshot.cpp
@@ -1,163 +1,165 @@
/*
* Copyright © 2018 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 "screenshot.h"
#include "screenshotdialog.h"
+#include "utils.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
Q_LOGGING_CATEGORY(XdgDesktopPortalKdeScreenshot, "xdp-kde-screenshot")
// Keep in sync with qflatpakcolordialog from Qt flatpak platform theme
Q_DECLARE_METATYPE(ScreenshotPortal::ColorRGB)
QDBusArgument &operator <<(QDBusArgument &arg, const ScreenshotPortal::ColorRGB &color)
{
arg.beginStructure();
arg << color.red << color.green << color.blue;
arg.endStructure();
return arg;
}
const QDBusArgument &operator >>(const QDBusArgument &arg, ScreenshotPortal::ColorRGB &color)
{
double red, green, blue;
arg.beginStructure();
arg >> red >> green >> blue;
color.red = red;
color.green = green;
color.blue = blue;
arg.endStructure();
return arg;
}
QDBusArgument &operator<< (QDBusArgument &argument, const QColor &color)
{
argument.beginStructure();
argument << color.rgba();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, QColor &color)
{
argument.beginStructure();
QRgb rgba;
argument >> rgba;
argument.endStructure();
color = QColor::fromRgba(rgba);
return argument;
}
ScreenshotPortal::ScreenshotPortal(QObject *parent)
: QDBusAbstractAdaptor(parent)
{
qDBusRegisterMetaType();
qDBusRegisterMetaType();
}
ScreenshotPortal::~ScreenshotPortal()
{
}
uint ScreenshotPortal::Screenshot(const QDBusObjectPath &handle,
const QString &app_id,
const QString &parent_window,
const QVariantMap &options,
QVariantMap &results)
{
qCDebug(XdgDesktopPortalKdeScreenshot) << "Screenshot called with parameters:";
qCDebug(XdgDesktopPortalKdeScreenshot) << " handle: " << handle.path();
qCDebug(XdgDesktopPortalKdeScreenshot) << " app_id: " << app_id;
qCDebug(XdgDesktopPortalKdeScreenshot) << " parent_window: " << parent_window;
qCDebug(XdgDesktopPortalKdeScreenshot) << " options: " << options;
QPointer screenshotDialog = new ScreenshotDialog;
+ Utils::setParentWindow(screenshotDialog, parent_window);
const bool modal = options.value(QLatin1String("modal"), false).toBool();
screenshotDialog->setModal(modal);
const bool interactive = options.value(QLatin1String("interactive"), false).toBool();
if (!interactive) {
screenshotDialog->takeScreenshot();
}
QImage screenshot = screenshotDialog->exec() ? screenshotDialog->image() : QImage();
if (screenshotDialog) {
screenshotDialog->deleteLater();
}
if (screenshot.isNull()) {
return 1;
}
const QString filename = QStringLiteral("%1/Screenshot_%2.png").arg(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation))
.arg(QDateTime::currentDateTime().toString(QLatin1String("yyyyMMdd_hhmmss")));
if (!screenshot.save(filename, "PNG")) {
return 1;
}
const QString resultFileName = QStringLiteral("file://") + filename;
results.insert(QLatin1String("uri"), resultFileName);
return 0;
}
uint ScreenshotPortal::PickColor(const QDBusObjectPath &handle,
const QString &app_id,
const QString &parent_window,
const QVariantMap &options,
QVariantMap &results)
{
qCDebug(XdgDesktopPortalKdeScreenshot) << "PickColor called with parameters:";
qCDebug(XdgDesktopPortalKdeScreenshot) << " handle: " << handle.path();
qCDebug(XdgDesktopPortalKdeScreenshot) << " app_id: " << app_id;
qCDebug(XdgDesktopPortalKdeScreenshot) << " parent_window: " << parent_window;
qCDebug(XdgDesktopPortalKdeScreenshot) << " options: " << options;
QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KWin"),
QStringLiteral("/ColorPicker"),
QStringLiteral("org.kde.kwin.ColorPicker"),
QStringLiteral("pick"));
QDBusReply reply = QDBusConnection::sessionBus().call(msg);
if (reply.isValid() && !reply.error().isValid()) {
QColor selectedColor = reply.value();
ColorRGB color;
color.red = selectedColor.redF();
color.green = selectedColor.greenF();
color.blue = selectedColor.blueF();
results.insert(QLatin1String("color"), QVariant::fromValue(color));
return 0;
}
return 1;
}
diff --git a/src/utils.cpp b/src/utils.cpp
new file mode 100644
index 0000000..64c0f5e
--- /dev/null
+++ b/src/utils.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright © 2018 Alexander Volkov
+ *
+ * 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 "utils.h"
+
+#include
+
+#include
+#include
+#include
+
+void Utils::setParentWindow(QWidget *w, const QString &parent_window)
+{
+ if (parent_window.startsWith(QLatin1String("x11:"))) {
+ KWindowSystem::setMainWindow(w, parent_window.midRef(4).toULongLong(nullptr, 16));
+ }
+}
diff --git a/src/utils.h b/src/utils.h
new file mode 100644
index 0000000..e623513
--- /dev/null
+++ b/src/utils.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright © 2018 Alexander Volkov
+ *
+ * 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 .
+ */
+
+#ifndef XDG_DESKTOP_PORTAL_KDE_UTILS_H
+#define XDG_DESKTOP_PORTAL_KDE_UTILS_H
+
+class QString;
+class QWidget;
+
+class Utils
+{
+public:
+ static void setParentWindow(QWidget *w, const QString &parent_window);
+};
+
+#endif // XDG_DESKTOP_PORTAL_KDE_UTILS_H