diff --git a/applets/colorpicker/CMakeLists.txt b/applets/colorpicker/CMakeLists.txt --- a/applets/colorpicker/CMakeLists.txt +++ b/applets/colorpicker/CMakeLists.txt @@ -10,5 +10,5 @@ install(FILES plugin/qmldir DESTINATION ${QML_INSTALL_DIR}/org/kde/plasma/private/colorpicker) add_library(colorpickerplugin SHARED ${colorpickerplugin_SRCS}) -target_link_libraries(colorpickerplugin Qt5::Gui Qt5::Qml Qt5::Widgets) +target_link_libraries(colorpickerplugin Qt5::DBus Qt5::Gui Qt5::Qml Qt5::Widgets KF5::WindowSystem) install(TARGETS colorpickerplugin DESTINATION ${QML_INSTALL_DIR}/org/kde/plasma/private/colorpicker) diff --git a/applets/colorpicker/plugin/grabwidget.h b/applets/colorpicker/plugin/grabwidget.h --- a/applets/colorpicker/plugin/grabwidget.h +++ b/applets/colorpicker/plugin/grabwidget.h @@ -26,6 +26,55 @@ class QWidget; +class Grabber : public QObject +{ + Q_OBJECT +public: + virtual ~Grabber(); + + virtual void pick() = 0; + + QColor color() const { + return m_color; + } + +Q_SIGNALS: + void colorChanged(); + +protected: + void setColor(const QColor &color); + explicit Grabber(QObject *parent = nullptr); + +private: + QColor m_color; +}; + +class X11Grabber : public Grabber +{ + Q_OBJECT +public: + explicit X11Grabber(QObject *parent = nullptr); + virtual ~X11Grabber(); + + void pick() override; + +protected: + virtual bool eventFilter(QObject *watched, QEvent *event) override; + +private: + QWidget *m_grabWidget; +}; + +class KWinWaylandGrabber : public Grabber +{ + Q_OBJECT +public: + explicit KWinWaylandGrabber(QObject *parent = nullptr); + virtual ~KWinWaylandGrabber(); + + void pick() override; +}; + class GrabWidget : public QObject { Q_OBJECT @@ -44,13 +93,8 @@ signals: void currentColorChanged(); -protected: - virtual bool eventFilter(QObject *watched, QEvent *event) override; - private: - QWidget *m_grabWidget; - - QColor m_currentColor; + Grabber *m_grabber = nullptr; }; diff --git a/applets/colorpicker/plugin/grabwidget.cpp b/applets/colorpicker/plugin/grabwidget.cpp --- a/applets/colorpicker/plugin/grabwidget.cpp +++ b/applets/colorpicker/plugin/grabwidget.cpp @@ -21,45 +21,79 @@ #include "grabwidget.h" #include +#include +#include +#include +#include +#include +#include #include #include #include #include #include #include -GrabWidget::GrabWidget(QObject *parent) +#include + +Q_DECLARE_METATYPE(QColor) + +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; +} + +Grabber::Grabber(QObject *parent) : QObject(parent) - , m_grabWidget(new QWidget(nullptr, Qt::BypassWindowManagerHint)) { - m_grabWidget->move(-5000, -5000); } -GrabWidget::~GrabWidget() +Grabber::~Grabber() = default; + +void Grabber::setColor(const QColor &color) { - delete m_grabWidget; + if (m_color == color) { + return; + } + m_color = color; + emit colorChanged(); } -QColor GrabWidget::currentColor() const +X11Grabber::X11Grabber(QObject *parent) + : Grabber(parent) + , m_grabWidget(new QWidget(nullptr, Qt::BypassWindowManagerHint)) { - return m_currentColor; + m_grabWidget->move(-5000, -5000); } -void GrabWidget::pick() +X11Grabber::~X11Grabber() +{ + delete m_grabWidget; +} + +void X11Grabber::pick() { // TODO pretend the mouse went somewhere else to prevent the tooltip from spawning m_grabWidget->show(); m_grabWidget->installEventFilter(this); m_grabWidget->grabMouse(Qt::CrossCursor); } -void GrabWidget::copyToClipboard(const QString &text) -{ - QApplication::clipboard()->setText(text); -} - -bool GrabWidget::eventFilter(QObject *watched, QEvent *event) +bool X11Grabber::eventFilter(QObject *watched, QEvent *event) { if (watched == m_grabWidget && event->type() == QEvent::MouseButtonRelease) { m_grabWidget->removeEventFilter(this); @@ -75,9 +109,67 @@ const QPixmap pixmap = qApp->primaryScreen()->grabWindow(0); const QPoint localPos = pos * qApp->devicePixelRatio(); - m_currentColor = QColor(pixmap.toImage().pixel(localPos)); - emit currentColorChanged(); + setColor(QColor(pixmap.toImage().pixel(localPos))); } return QObject::eventFilter(watched, event); } + +KWinWaylandGrabber::KWinWaylandGrabber(QObject *parent) + : Grabber(parent) +{ + qDBusRegisterMetaType(); +} + +KWinWaylandGrabber::~KWinWaylandGrabber() = default; + +void KWinWaylandGrabber::pick() +{ + QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KWin"), + QStringLiteral("/ColorPicker"), + QStringLiteral("org.kde.kwin.ColorPicker"), + QStringLiteral("pick")); + auto call = QDBusConnection::sessionBus().asyncCall(msg); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); + connect(watcher, &QDBusPendingCallWatcher::finished, this, + [this] (QDBusPendingCallWatcher *watcher) { + watcher->deleteLater(); + QDBusPendingReply reply = *watcher; + if (!reply.isError()) { + setColor(reply.value()); + } + } + ); +} + +GrabWidget::GrabWidget(QObject *parent) + : QObject(parent) +{ + if (KWindowSystem::isPlatformX11()) { + m_grabber = new X11Grabber(this); + } else if (KWindowSystem::isPlatformWayland()) { + m_grabber = new KWinWaylandGrabber(this); + } + if (m_grabber) { + connect(m_grabber, &Grabber::colorChanged, this, &GrabWidget::currentColorChanged); + } +} + +GrabWidget::~GrabWidget() = default; + +QColor GrabWidget::currentColor() const +{ + return m_grabber ? m_grabber->color() : QColor(); +} + +void GrabWidget::pick() +{ + if (m_grabber) { + m_grabber->pick(); + } +} + +void GrabWidget::copyToClipboard(const QString &text) +{ + QApplication::clipboard()->setText(text); +}