Commit b93e0b21 authored by Julius Künzel's avatar Julius Künzel 💬
Browse files

Fix color picker on wayland

Fixes #1417

On wayland the features are limited by the portal. Preview and dragging
a rectangle for avarage color does not work.
parent 25edf681
Pipeline #271609 passed with stage
in 7 minutes and 41 seconds
......@@ -5,9 +5,19 @@ SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "colorpickerwidget.h"
#include "core.h"
#include "mainwindow.h"
#include <KLocalizedString>
#include <QApplication>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusMetaType>
#include <QDBusObjectPath>
#include <QDBusPendingCall>
#include <QDBusPendingCallWatcher>
#include <QDBusPendingReply>
#include <QDebug>
#include <QHBoxLayout>
#include <QMouseEvent>
#include <QScreen>
......@@ -21,6 +31,27 @@ SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include <fixx11h.h>
#endif
QDBusArgument &operator<<(QDBusArgument &arg, const QColor &color)
{
arg.beginStructure();
arg << color.redF() << color.greenF() << color.blueF();
arg.endStructure();
return arg;
}
const QDBusArgument &operator>>(const QDBusArgument &arg, QColor &color)
{
double red, green, blue;
arg.beginStructure();
arg >> red >> green >> blue;
color.setRedF(red);
color.setGreenF(green);
color.setBlueF(blue);
arg.endStructure();
return arg;
}
MyFrame::MyFrame(QWidget *parent)
: QFrame(parent)
{
......@@ -50,19 +81,36 @@ ColorPickerWidget::ColorPickerWidget(QWidget *parent)
auto *layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
// Check wether grabWindow() works. On some systems like with Wayland it does.
// We fallback to the Freedesktop portal with DBus which has less features than
// our custom implementation (eg. preview and avarage color are missing)
QPoint p(pCore->window()->geometry().center());
foreach (QScreen *screen, QGuiApplication::screens()) {
QRect screenRect = screen->geometry();
if (screenRect.contains(p)) {
QPixmap pm = screen->grabWindow(pCore->window()->winId(), p.x(), p.y(), 1, 1);
qDebug() << "got pixmap that is not null";
m_useDBus = pm.isNull();
break;
}
}
auto *button = new QToolButton(this);
button->setIcon(QIcon::fromTheme(QStringLiteral("color-picker")));
button->setToolTip(i18n("Pick a color on the screen."));
button->setWhatsThis(xi18nc("@info:whatsthis", "Pick a color on the screen. By pressing the mouse button and then moving your mouse you can select a "
"section of the screen from which to get an average color."));
button->setAutoRaise(true);
connect(button, &QAbstractButton::clicked, this, &ColorPickerWidget::slotSetupEventFilter);
if (!m_useDBus) {
button->setWhatsThis(xi18nc("@info:whatsthis", "Pick a color on the screen. By pressing the mouse button and then moving your mouse you can select a "
"section of the screen from which to get an average color."));
connect(button, &QAbstractButton::clicked, this, &ColorPickerWidget::slotSetupEventFilter);
setFocusPolicy(Qt::StrongFocus);
setMouseTracking(true);
} else {
qDBusRegisterMetaType<QColor>();
connect(button, &QAbstractButton::clicked, this, &ColorPickerWidget::grabColorDBus);
}
layout->addWidget(button);
setFocusPolicy(Qt::StrongFocus);
setMouseTracking(true);
m_grabRectFrame = new MyFrame();
m_grabRectFrame->hide();
}
......@@ -266,3 +314,37 @@ QColor ColorPickerWidget::grabColor(const QPoint &p, bool destroyImage)
#endif
}
void ColorPickerWidget::grabColorDBus()
{
QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"), QLatin1String("/org/freedesktop/portal/desktop"),
QLatin1String("org.freedesktop.portal.Screenshot"), QLatin1String("PickColor"));
message << QLatin1String("x11:") << QVariantMap{};
QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall);
connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
QDBusPendingReply<QDBusObjectPath> reply = *watcher;
if (reply.isError()) {
qWarning() << "Couldn't get reply";
qWarning() << "Error: " << reply.error().message();
} else {
qDebug() << reply.value() << reply.value().path() << reply.error();
QDBusConnection::sessionBus().connect(QString(), reply.value().path(), QLatin1String("org.freedesktop.portal.Request"), QLatin1String("Response"),
this, SLOT(gotColorResponse(uint, QVariantMap)));
}
});
}
void ColorPickerWidget::gotColorResponse(uint response, const QVariantMap &results)
{
if (!response) {
if (results.contains(QLatin1String("color"))) {
const QColor color = qdbus_cast<QColor>(results.value(QLatin1String("color")));
qDebug() << "picked" << color;
m_mouseColor = color;
emit colorPicked(m_mouseColor);
}
} else {
qWarning() << "Failed to take screenshot" << response << results;
}
}
......@@ -61,6 +61,7 @@ private:
QColor grabColor(const QPoint &p, bool destroyImage = true);
bool m_filterActive{false};
bool m_useDBus{true};
QRect m_grabRect;
QPoint m_clickPoint;
QFrame *m_grabRectFrame;
......@@ -78,6 +79,11 @@ private slots:
/** @brief Calculates the average color for the pixels in the rect m_grabRect and emits colorPicked. */
void slotGetAverageColor();
/** @brief Send a DBus message to the Freedesktop portal to request a color picker operation */
void grabColorDBus();
/** @brief To be called by the DBus connection when a response comes in */
void gotColorResponse(uint response, const QVariantMap &results);
signals:
/** @brief Signal fired when a new color has been picked */
void colorPicked(const QColor &);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment