1 /***************************************************************************
2 * Copyright (C) 2010 by Till Theato (root@ttill.de) *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
21 #include "colorpickerwidget.h"
23 #include <QMouseEvent>
24 #include <QHBoxLayout>
25 #include <QPushButton>
28 #include <QDesktopWidget>
30 #include <KApplication>
32 #include <KLocalizedString>
35 #include <X11/Xutil.h>
38 class KCDPickerFilter: public QWidget
41 KCDPickerFilter(QWidget* parent): QWidget(parent) {}
43 virtual bool x11Event(XEvent* event) {
44 if (event->type == ButtonRelease) {
45 QMouseEvent e(QEvent::MouseButtonRelease, QPoint(),
46 QPoint(event->xmotion.x_root, event->xmotion.y_root) , Qt::NoButton, Qt::NoButton, Qt::NoModifier);
47 QApplication::sendEvent(parentWidget(), &e);
56 ColorPickerWidget::ColorPickerWidget(QWidget *parent) :
64 QHBoxLayout *layout = new QHBoxLayout(this);
66 QPushButton *button = new QPushButton(this);
67 button->setIcon(KIcon("color-picker"));
68 button->setToolTip(i18n("Pick a color on the screen"));
69 connect(button, SIGNAL(clicked()), this, SLOT(slotSetupEventFilter()));
71 m_size = new QSpinBox(this);
72 m_size->setMinimum(1);
73 // Use qMin here, as we might run into troubles with the cursor otherwise.
74 m_size->setMaximum(qMin(qApp->desktop()->geometry().width(), qApp->desktop()->geometry().height()));
77 layout->addWidget(button);
78 layout->addStretch(1);
79 layout->addWidget(new QLabel(i18n("Width of square to pick color from:")));
80 layout->addWidget(m_size);
83 ColorPickerWidget::~ColorPickerWidget()
86 if (m_filterActive && kapp)
87 kapp->removeX11EventFilter(m_filter);
91 QColor ColorPickerWidget::averagePickedColor(const QPoint pos)
93 int size = m_size->value();
94 int x0 = qMax(0, pos.x() - size / 2);
95 int y0 = qMax(0, pos.y() - size / 2);
96 int x1 = qMin(qApp->desktop()->geometry().width(), pos.x() + size / 2);
97 int y1 = qMin(qApp->desktop()->geometry().height(), pos.y() + size / 2);
99 // take care of loss when dividing odd sizes
101 if (x1 < qApp->desktop()->geometry().width()) ++x1;
102 if (y1 < qApp->desktop()->geometry().height()) ++y1;
105 int numPixel = (x1 - x0) * (y1 - y0);
111 // only show message for size > 200 because for smaller values it slows down to much
113 emit displayMessage(i18n("Requesting color information..."), 0);
116 Only getting the image once for the whole rect
117 results in a vast speed improvement.
120 Window root = RootWindow(QX11Info::display(), QX11Info::appScreen());
121 m_image = XGetImage(QX11Info::display(), root, x0, y0, x1 - x0, y1 - y0, -1, ZPixmap);
123 QWidget *desktop = QApplication::desktop();
124 m_image = QPixmap::grabWindow(desktop->winId(), x0, y0, x1 - x0, y1 - y0).toImage();
127 for (int i = x0; i < x1; ++i) {
128 for (int j = y0; j < y1; ++j) {
130 color = grabColor(QPoint(i - x0, j - y0), false);
132 sumG += color.green();
133 sumB += color.blue();
136 // Warning: slows things down, so don't do it for every pixel (the inner for loop)
138 emit displayMessage(i18n("Requesting color information..."), (int)(((i - x0) * (y1 - y0)) / (qreal)numPixel * 100));
142 XDestroyImage(m_image);
146 emit displayMessage(i18n("Calculated average color for rectangle."), -1);
148 return QColor(sumR / numPixel, sumG / numPixel, sumB / numPixel);
151 void ColorPickerWidget::mousePressEvent(QMouseEvent* event)
153 if (event->button() != Qt::LeftButton) {
158 QWidget::mousePressEvent(event);
161 void ColorPickerWidget::mouseReleaseEvent(QMouseEvent *event)
163 if (m_filterActive) {
166 if (m_size->value() == 1)
167 emit colorPicked(grabColor(event->globalPos()));
169 emit colorPicked(averagePickedColor(event->globalPos()));
173 QWidget::mouseReleaseEvent(event);
176 void ColorPickerWidget::keyPressEvent(QKeyEvent *event)
178 if (m_filterActive) {
179 // "special keys" (non letter, numeral) do not work, so close for every key
180 //if (event->key() == Qt::Key_Escape)
185 QWidget::keyPressEvent(event);
188 void ColorPickerWidget::slotSetupEventFilter()
190 m_filterActive = true;
192 m_filter = new KCDPickerFilter(this);
193 kapp->installX11EventFilter(m_filter);
195 if (m_size->value() < 10)
196 grabMouse(QCursor(KIcon("color-picker").pixmap(22, 22), 0, 21));
198 grabMouse(QCursor(KIcon("kdenlive-select-all").pixmap(m_size->value(), m_size->value())));
202 void ColorPickerWidget::closeEventFilter()
204 m_filterActive = false;
206 kapp->removeX11EventFilter(m_filter);
214 QColor ColorPickerWidget::grabColor(const QPoint &p, bool destroyImage)
218 we use the X11 API directly in this case as we are not getting back a valid
219 return from QPixmap::grabWindow in the case where the application is using
222 if( !qApp->desktop()->geometry().contains( p ))
224 unsigned long xpixel;
226 Window root = RootWindow(QX11Info::display(), QX11Info::appScreen());
227 m_image = XGetImage(QX11Info::display(), root, p.x(), p.y(), 1, 1, -1, ZPixmap);
228 xpixel = XGetPixel(m_image, 0, 0);
230 xpixel = XGetPixel(m_image, p.x(), p.y());
233 XDestroyImage(m_image);
238 xcol.flags = DoRed | DoGreen | DoBlue;
239 XQueryColor(QX11Info::display(),
240 DefaultColormap(QX11Info::display(), QX11Info::appScreen()),
242 return QColor::fromRgbF(xcol.red / 65535.0, xcol.green / 65535.0, xcol.blue / 65535.0);
244 if (m_image.isNull()) {
245 QWidget *desktop = QApplication::desktop();
246 QPixmap pm = QPixmap::grabWindow(desktop->winId(), p.x(), p.y(), 1, 1);
247 QImage i = pm.toImage();
248 return i.pixel(0, 0);
250 return m_image.pixel(p.x(), p.y());
255 #include "colorpickerwidget.moc"