File indexing completed on 2024-11-10 04:56:58

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "colorpicker.h"
0010 #include "core/rendertarget.h"
0011 #include "core/renderviewport.h"
0012 #include "effect/effecthandler.h"
0013 #include "opengl/glutils.h"
0014 #include "opengl/glutils_funcs.h"
0015 #include <KLocalizedString>
0016 #include <QDBusConnection>
0017 #include <QDBusMetaType>
0018 
0019 Q_DECLARE_METATYPE(QColor)
0020 
0021 QDBusArgument &operator<<(QDBusArgument &argument, const QColor &color)
0022 {
0023     argument.beginStructure();
0024     argument << color.rgba();
0025     argument.endStructure();
0026     return argument;
0027 }
0028 
0029 const QDBusArgument &operator>>(const QDBusArgument &argument, QColor &color)
0030 {
0031     argument.beginStructure();
0032     QRgb rgba;
0033     argument >> rgba;
0034     argument.endStructure();
0035     color = QColor::fromRgba(rgba);
0036     return argument;
0037 }
0038 
0039 namespace KWin
0040 {
0041 
0042 bool ColorPickerEffect::supported()
0043 {
0044     return effects->isOpenGLCompositing();
0045 }
0046 
0047 ColorPickerEffect::ColorPickerEffect()
0048     : m_scheduledPosition(QPoint(-1, -1))
0049 {
0050     qDBusRegisterMetaType<QColor>();
0051     QDBusConnection::sessionBus().registerObject(QStringLiteral("/ColorPicker"), this, QDBusConnection::ExportScriptableContents);
0052 }
0053 
0054 ColorPickerEffect::~ColorPickerEffect() = default;
0055 
0056 void ColorPickerEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion &region, Output *screen)
0057 {
0058     effects->paintScreen(renderTarget, viewport, mask, region, screen);
0059 
0060     const QRectF geo = viewport.renderRect();
0061     if (m_scheduledPosition != QPoint(-1, -1) && exclusiveContains(geo, m_scheduledPosition)) {
0062         std::array<float, 4> data;
0063         constexpr GLsizei PIXEL_SIZE = 1;
0064         const QPoint texturePosition = viewport.mapToRenderTarget(m_scheduledPosition).toPoint();
0065 
0066         glReadPixels(texturePosition.x(), renderTarget.size().height() - texturePosition.y() - PIXEL_SIZE, PIXEL_SIZE, PIXEL_SIZE, GL_RGBA, GL_FLOAT, data.data());
0067         QVector3D sRGB = 255 * renderTarget.colorDescription().mapTo(QVector3D(data[0], data[1], data[2]), ColorDescription::sRGB);
0068         QDBusConnection::sessionBus().send(m_replyMessage.createReply(QColor(sRGB.x(), sRGB.y(), sRGB.z())));
0069         m_picking = false;
0070         m_scheduledPosition = QPoint(-1, -1);
0071     }
0072 }
0073 
0074 QColor ColorPickerEffect::pick()
0075 {
0076     if (!calledFromDBus()) {
0077         return QColor();
0078     }
0079     if (m_picking) {
0080         sendErrorReply(QDBusError::Failed, "Color picking is already in progress");
0081         return QColor();
0082     }
0083     m_picking = true;
0084     m_replyMessage = message();
0085     setDelayedReply(true);
0086     showInfoMessage();
0087     effects->startInteractivePositionSelection(
0088         [this](const QPointF &p) {
0089             hideInfoMessage();
0090             if (p == QPointF(-1, -1)) {
0091                 // error condition
0092                 QDBusConnection::sessionBus().send(m_replyMessage.createErrorReply(QStringLiteral("org.kde.kwin.ColorPicker.Error.Cancelled"), "Color picking got cancelled"));
0093                 m_picking = false;
0094             } else {
0095                 m_scheduledPosition = p;
0096                 effects->addRepaintFull();
0097             }
0098         });
0099     return QColor();
0100 }
0101 
0102 void ColorPickerEffect::showInfoMessage()
0103 {
0104     effects->showOnScreenMessage(i18n("Select a position for color picking with left click or enter.\nEscape or right click to cancel."), QStringLiteral("color-picker"));
0105 }
0106 
0107 void ColorPickerEffect::hideInfoMessage()
0108 {
0109     effects->hideOnScreenMessage();
0110 }
0111 
0112 bool ColorPickerEffect::isActive() const
0113 {
0114     return m_picking && ((m_scheduledPosition != QPoint(-1, -1))) && !effects->isScreenLocked();
0115 }
0116 
0117 } // namespace
0118 
0119 #include "moc_colorpicker.cpp"