/******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2007 Rivo Laks Copyright (C) 2008 Lucas Murray This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "invert.h" #include #include #include #include #include #include #include #include namespace KWin { InvertEffect::InvertEffect() : m_inited(false), m_valid(true), m_shader(NULL), m_allWindows(false) { QAction* a = new QAction(this); a->setObjectName(QStringLiteral("Invert")); a->setText(i18n("Toggle Invert Effect")); KGlobalAccel::self()->setDefaultShortcut(a, QList() << Qt::CTRL + Qt::META + Qt::Key_I); KGlobalAccel::self()->setShortcut(a, QList() << Qt::CTRL + Qt::META + Qt::Key_I); effects->registerGlobalShortcut(Qt::CTRL + Qt::META + Qt::Key_I, a); connect(a, SIGNAL(triggered(bool)), this, SLOT(toggleScreenInversion())); QAction* b = new QAction(this); b->setObjectName(QStringLiteral("InvertWindow")); b->setText(i18n("Toggle Invert Effect on Window")); KGlobalAccel::self()->setDefaultShortcut(b, QList() << Qt::CTRL + Qt::META + Qt::Key_U); KGlobalAccel::self()->setShortcut(b, QList() << Qt::CTRL + Qt::META + Qt::Key_U); effects->registerGlobalShortcut(Qt::CTRL + Qt::META + Qt::Key_U, b); connect(b, SIGNAL(triggered(bool)), this, SLOT(toggleWindow())); connect(effects, SIGNAL(windowClosed(KWin::EffectWindow*)), this, SLOT(slotWindowClosed(KWin::EffectWindow*))); } InvertEffect::~InvertEffect() { delete m_shader; } bool InvertEffect::supported() { return effects->compositingType() == OpenGL2Compositing; } bool InvertEffect::loadData() { m_inited = true; QString shadersDir = QStringLiteral("kwin/shaders/1.10/"); const qint64 coreVersionNumber = GLPlatform::instance()->isGLES() ? kVersionNumber(3, 0) : kVersionNumber(1, 40); if (GLPlatform::instance()->glslVersion() >= coreVersionNumber) shadersDir = QStringLiteral("kwin/shaders/1.40/"); const QString fragmentshader = QStandardPaths::locate(QStandardPaths::GenericDataLocation, shadersDir + QStringLiteral("invert.frag")); QFile ff(fragmentshader); if (!ff.open(QIODevice::ReadOnly)) { qCCritical(KWINEFFECTS) << "Couldn't open" << fragmentshader << "for reading!"; return false; } m_shader = ShaderManager::instance()->generateCustomShader(ShaderTrait::MapTexture, QByteArray(), ff.readAll()); if (!m_shader->isValid()) { qCCritical(KWINEFFECTS) << "The shader failed to load!"; return false; } return true; } void InvertEffect::prePaintScreen(ScreenPrePaintData &data, int time) { effects->prePaintScreen(data, time); } void InvertEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) { if (m_valid && (m_allWindows != m_windows.contains(w))) { data.mask |= PAINT_WINDOW_TRANSFORMED; } effects->prePaintWindow(w, data, time); } void InvertEffect::drawWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) { // Load if we haven't already if (m_valid && !m_inited) m_valid = loadData(); bool useShader = m_valid && (m_allWindows != m_windows.contains(w)); if (useShader) { ShaderManager *shaderManager = ShaderManager::instance(); shaderManager->pushShader(m_shader); data.shader = m_shader; } effects->drawWindow(w, mask, region, data); if (useShader) { ShaderManager::instance()->popShader(); } } void InvertEffect::paintEffectFrame(KWin::EffectFrame* frame, QRegion region, double opacity, double frameOpacity) { if (m_valid && m_allWindows) { frame->setShader(m_shader); ShaderBinder binder(m_shader); effects->paintEffectFrame(frame, region, opacity, frameOpacity); } else { effects->paintEffectFrame(frame, region, opacity, frameOpacity); } } void InvertEffect::slotWindowClosed(EffectWindow* w) { m_windows.removeOne(w); } void InvertEffect::toggleScreenInversion() { m_allWindows = !m_allWindows; effects->addRepaintFull(); } void InvertEffect::toggleWindow() { if (!effects->activeWindow()) { return; } if (!m_windows.contains(effects->activeWindow())) m_windows.append(effects->activeWindow()); else m_windows.removeOne(effects->activeWindow()); effects->activeWindow()->addRepaintFull(); } bool InvertEffect::isActive() const { return m_valid && (m_allWindows || !m_windows.isEmpty()); } bool InvertEffect::provides(Feature f) { return f == ScreenInversion; } } // namespace #include "invert.moc"