File indexing completed on 2024-11-10 04:56:59
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2007 Rivo Laks <rivolaks@hot.ee> 0006 SPDX-FileCopyrightText: 2008 Lucas Murray <lmurray@undefinedfire.com> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "invert.h" 0012 0013 #include "effect/effecthandler.h" 0014 #include "opengl/glplatform.h" 0015 #include "opengl/glutils.h" 0016 #include <KGlobalAccel> 0017 #include <KLocalizedString> 0018 #include <QAction> 0019 #include <QFile> 0020 #include <QStandardPaths> 0021 0022 #include <QMatrix4x4> 0023 0024 Q_LOGGING_CATEGORY(KWIN_INVERT, "kwin_effect_invert", QtWarningMsg) 0025 0026 static void ensureResources() 0027 { 0028 // Must initialize resources manually because the effect is a static lib. 0029 Q_INIT_RESOURCE(invert); 0030 } 0031 0032 namespace KWin 0033 { 0034 0035 InvertEffect::InvertEffect() 0036 : m_inited(false) 0037 , m_valid(true) 0038 , m_shader(nullptr) 0039 , m_allWindows(false) 0040 { 0041 QAction *a = new QAction(this); 0042 a->setObjectName(QStringLiteral("Invert")); 0043 a->setText(i18n("Toggle Invert Effect")); 0044 KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>() << (Qt::CTRL | Qt::META | Qt::Key_I)); 0045 KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>() << (Qt::CTRL | Qt::META | Qt::Key_I)); 0046 connect(a, &QAction::triggered, this, &InvertEffect::toggleScreenInversion); 0047 0048 QAction *b = new QAction(this); 0049 b->setObjectName(QStringLiteral("InvertWindow")); 0050 b->setText(i18n("Toggle Invert Effect on Window")); 0051 KGlobalAccel::self()->setDefaultShortcut(b, QList<QKeySequence>() << (Qt::CTRL | Qt::META | Qt::Key_U)); 0052 KGlobalAccel::self()->setShortcut(b, QList<QKeySequence>() << (Qt::CTRL | Qt::META | Qt::Key_U)); 0053 connect(b, &QAction::triggered, this, &InvertEffect::toggleWindow); 0054 0055 QAction *c = new QAction(this); 0056 c->setObjectName(QStringLiteral("Invert Screen Colors")); 0057 c->setText(i18n("Invert Screen Colors")); 0058 KGlobalAccel::self()->setDefaultShortcut(c, QList<QKeySequence>()); 0059 KGlobalAccel::self()->setShortcut(c, QList<QKeySequence>()); 0060 connect(c, &QAction::triggered, this, &InvertEffect::toggleScreenInversion); 0061 0062 connect(effects, &EffectsHandler::windowAdded, this, &InvertEffect::slotWindowAdded); 0063 connect(effects, &EffectsHandler::windowClosed, this, &InvertEffect::slotWindowClosed); 0064 } 0065 0066 InvertEffect::~InvertEffect() = default; 0067 0068 bool InvertEffect::supported() 0069 { 0070 return effects->compositingType() == OpenGLCompositing; 0071 } 0072 0073 bool InvertEffect::isInvertable(EffectWindow *window) const 0074 { 0075 return m_allWindows != m_windows.contains(window); 0076 } 0077 0078 void InvertEffect::invert(EffectWindow *window) 0079 { 0080 if (m_valid && !m_inited) { 0081 m_valid = loadData(); 0082 } 0083 0084 redirect(window); 0085 setShader(window, m_shader.get()); 0086 } 0087 0088 void InvertEffect::uninvert(EffectWindow *window) 0089 { 0090 unredirect(window); 0091 } 0092 0093 bool InvertEffect::loadData() 0094 { 0095 ensureResources(); 0096 m_inited = true; 0097 0098 m_shader = ShaderManager::instance()->generateShaderFromFile(ShaderTrait::MapTexture, QString(), QStringLiteral(":/effects/invert/shaders/invert.frag")); 0099 if (!m_shader->isValid()) { 0100 qCCritical(KWIN_INVERT) << "The shader failed to load!"; 0101 return false; 0102 } 0103 0104 return true; 0105 } 0106 0107 void InvertEffect::slotWindowAdded(KWin::EffectWindow *w) 0108 { 0109 if (isInvertable(w)) { 0110 invert(w); 0111 } 0112 } 0113 0114 void InvertEffect::slotWindowClosed(EffectWindow *w) 0115 { 0116 m_windows.removeOne(w); 0117 } 0118 0119 void InvertEffect::toggleScreenInversion() 0120 { 0121 m_allWindows = !m_allWindows; 0122 0123 const auto windows = effects->stackingOrder(); 0124 for (EffectWindow *window : windows) { 0125 if (isInvertable(window)) { 0126 invert(window); 0127 } else { 0128 uninvert(window); 0129 } 0130 } 0131 0132 effects->addRepaintFull(); 0133 } 0134 0135 void InvertEffect::toggleWindow() 0136 { 0137 if (!effects->activeWindow()) { 0138 return; 0139 } 0140 if (!m_windows.contains(effects->activeWindow())) { 0141 m_windows.append(effects->activeWindow()); 0142 } else { 0143 m_windows.removeOne(effects->activeWindow()); 0144 } 0145 if (isInvertable(effects->activeWindow())) { 0146 invert(effects->activeWindow()); 0147 } else { 0148 uninvert(effects->activeWindow()); 0149 } 0150 effects->activeWindow()->addRepaintFull(); 0151 } 0152 0153 bool InvertEffect::isActive() const 0154 { 0155 return m_valid && (m_allWindows || !m_windows.isEmpty()); 0156 } 0157 0158 bool InvertEffect::provides(Feature f) 0159 { 0160 return f == ScreenInversion; 0161 } 0162 0163 } // namespace 0164 0165 #include "moc_invert.cpp"