From 47ef0b5a3cfdad3fa895748ff87a52a889351b32 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Mon, 31 May 2021 13:48:20 +0300 Subject: [PATCH] effects: Remove Desktop Cube effect With the ongoing scene redesign, it needs to be rewritten. However, given that it is not used widely based on support information from various bug reports and our available man power is sparse, the most reasonable thing is to drop the effect, unfortunately. --- autotests/test_builtin_effectloader.cpp | 7 - autotests/test_plugin_effectloader.cpp | 1 - autotests/test_scripted_effectloader.cpp | 1 - src/effects/CMakeLists.txt | 4 - src/effects/cube/CMakeLists.txt | 32 - src/effects/cube/cube.cpp | 1747 ----------------- src/effects/cube/cube.h | 253 --- src/effects/cube/cube.kcfg | 68 - src/effects/cube/cube_config.cpp | 110 -- src/effects/cube/cube_config.desktop | 83 - src/effects/cube/cube_config.h | 46 - src/effects/cube/cube_config.ui | 569 ------ src/effects/cube/cube_inside.h | 29 - src/effects/cube/cube_proxy.cpp | 36 - src/effects/cube/cube_proxy.h | 34 - src/effects/cube/cubeconfig.kcfgc | 6 - src/effects/cube/data/1.10/cube-cap.glsl | 29 - .../cube/data/1.10/cube-reflection.glsl | 8 - src/effects/cube/data/1.10/cylinder.vert | 35 - src/effects/cube/data/1.10/sphere.vert | 41 - src/effects/cube/data/1.40/cube-cap.glsl | 32 - .../cube/data/1.40/cube-reflection.glsl | 11 - src/effects/cube/data/1.40/cylinder.vert | 36 - src/effects/cube/data/1.40/sphere.vert | 42 - src/effects/cube/data/cubecap.png | Bin 48777 -> 0 bytes src/effects/effect_builtins.cpp | 17 - src/effects/effect_builtins.h | 1 - src/effects/shaders.qrc | 8 - .../kwinscreenedgesettings.kcfg | 11 - .../kwintouchscreensettings.kcfg | 11 - src/kcmkwin/kwinscreenedges/main.cpp | 25 - src/kcmkwin/kwinscreenedges/main.h | 3 - src/kcmkwin/kwinscreenedges/touch.cpp | 29 - src/kcmkwin/kwinscreenedges/touch.h | 3 - 34 files changed, 3368 deletions(-) delete mode 100644 src/effects/cube/CMakeLists.txt delete mode 100644 src/effects/cube/cube.cpp delete mode 100644 src/effects/cube/cube.h delete mode 100644 src/effects/cube/cube.kcfg delete mode 100644 src/effects/cube/cube_config.cpp delete mode 100644 src/effects/cube/cube_config.desktop delete mode 100644 src/effects/cube/cube_config.h delete mode 100644 src/effects/cube/cube_config.ui delete mode 100644 src/effects/cube/cube_inside.h delete mode 100644 src/effects/cube/cube_proxy.cpp delete mode 100644 src/effects/cube/cube_proxy.h delete mode 100644 src/effects/cube/cubeconfig.kcfgc delete mode 100644 src/effects/cube/data/1.10/cube-cap.glsl delete mode 100644 src/effects/cube/data/1.10/cube-reflection.glsl delete mode 100644 src/effects/cube/data/1.10/cylinder.vert delete mode 100644 src/effects/cube/data/1.10/sphere.vert delete mode 100644 src/effects/cube/data/1.40/cube-cap.glsl delete mode 100644 src/effects/cube/data/1.40/cube-reflection.glsl delete mode 100644 src/effects/cube/data/1.40/cylinder.vert delete mode 100644 src/effects/cube/data/1.40/sphere.vert delete mode 100644 src/effects/cube/data/cubecap.png diff --git a/autotests/test_builtin_effectloader.cpp b/autotests/test_builtin_effectloader.cpp index 8253285aed..01503011a3 100644 --- a/autotests/test_builtin_effectloader.cpp +++ b/autotests/test_builtin_effectloader.cpp @@ -73,7 +73,6 @@ void TestBuiltInEffectLoader::testHasEffect_data() QTest::newRow("case sensitive") << QStringLiteral("BlUR") << true; QTest::newRow("Colorpicker") << QStringLiteral("colorpicker") << true; QTest::newRow("Contrast") << QStringLiteral("contrast") << true; - QTest::newRow("Cube") << QStringLiteral("cube") << true; QTest::newRow("CubeSlide") << QStringLiteral("cubeslide") << true; QTest::newRow("DesktopGrid") << QStringLiteral("desktopgrid") << true; QTest::newRow("DimInactive") << QStringLiteral("diminactive") << true; @@ -125,7 +124,6 @@ void TestBuiltInEffectLoader::testKnownEffects() expectedEffects << QStringLiteral("blur") << QStringLiteral("colorpicker") << QStringLiteral("contrast") - << QStringLiteral("cube") << QStringLiteral("cubeslide") << QStringLiteral("desktopgrid") << QStringLiteral("diminactive") @@ -185,8 +183,6 @@ void TestBuiltInEffectLoader::testSupported_data() QTest::newRow("Contrast") << QStringLiteral("contrast") << false << xc << true; // fails for GL as it does proper tests on what's supported and doesn't just check whether it's GL QTest::newRow("Contrast-GL") << QStringLiteral("contrast") << false << oc << true; - QTest::newRow("Cube") << QStringLiteral("cube") << false << xc << true; - QTest::newRow("Cube-GL") << QStringLiteral("cube") << true << oc << true; QTest::newRow("CubeSlide") << QStringLiteral("cubeslide") << false << xc << true; QTest::newRow("CubeSlide-GL") << QStringLiteral("cubeslide") << true << oc << true; QTest::newRow("CubeSlide-GL-no-anim") << QStringLiteral("cubeslide") << false << oc << false; @@ -268,9 +264,6 @@ void TestBuiltInEffectLoader::testLoadEffect_data() QTest::newRow("Contrast") << QStringLiteral("contrast") << false << xc; // fails for GL as it does proper tests on what's supported and doesn't just check whether it's GL QTest::newRow("Contrast-GL") << QStringLiteral("contrast") << false << oc; - QTest::newRow("Cube") << QStringLiteral("cube") << false << xc; - // TODO: needs GL mocking -// QTest::newRow("Cube-GL") << QStringLiteral("cube") << true << oc; QTest::newRow("CubeSlide") << QStringLiteral("cubeslide") << false << xc; QTest::newRow("CubeSlide-GL") << QStringLiteral("cubeslide") << true << oc; QTest::newRow("DesktopGrid") << QStringLiteral("desktopgrid") << true << xc; diff --git a/autotests/test_plugin_effectloader.cpp b/autotests/test_plugin_effectloader.cpp index 186a7f84b0..9c39a821dc 100644 --- a/autotests/test_plugin_effectloader.cpp +++ b/autotests/test_plugin_effectloader.cpp @@ -64,7 +64,6 @@ void TestPluginEffectLoader::testHasEffect_data() QTest::newRow("blur") << QStringLiteral("blur") << false; QTest::newRow("ColorPicker") << QStringLiteral("colorpicker") << false; QTest::newRow("Contrast") << QStringLiteral("contrast") << false; - QTest::newRow("Cube") << QStringLiteral("cube") << false; QTest::newRow("CubeSlide") << QStringLiteral("cubeslide") << false; QTest::newRow("DesktopGrid") << QStringLiteral("desktopgrid") << false; QTest::newRow("DimInactive") << QStringLiteral("diminactive") << false; diff --git a/autotests/test_scripted_effectloader.cpp b/autotests/test_scripted_effectloader.cpp index 54a26484c2..f7497b1f64 100644 --- a/autotests/test_scripted_effectloader.cpp +++ b/autotests/test_scripted_effectloader.cpp @@ -85,7 +85,6 @@ void TestScriptedEffectLoader::testHasEffect_data() QTest::newRow("blur") << QStringLiteral("blur") << false; QTest::newRow("Colorpicker") << QStringLiteral("colorpicker") << false; QTest::newRow("Contrast") << QStringLiteral("contrast") << false; - QTest::newRow("Cube") << QStringLiteral("cube") << false; QTest::newRow("CubeSlide") << QStringLiteral("cubeslide") << false; QTest::newRow("DesktopGrid") << QStringLiteral("desktopgrid") << false; QTest::newRow("DimInactive") << QStringLiteral("diminactive") << false; diff --git a/src/effects/CMakeLists.txt b/src/effects/CMakeLists.txt index 7ec9eef6fe..716ea500b8 100644 --- a/src/effects/CMakeLists.txt +++ b/src/effects/CMakeLists.txt @@ -83,8 +83,6 @@ set(kwin4_effect_builtins_sources blur/blur.cpp blur/blurshader.cpp colorpicker/colorpicker.cpp - cube/cube.cpp - cube/cube_proxy.cpp cubeslide/cubeslide.cpp desktopgrid/desktopgrid.cpp diminactive/diminactive.cpp @@ -123,7 +121,6 @@ qt5_add_resources(kwin4_effect_builtins_sources shaders.qrc) kconfig_add_kcfg_files(kwin4_effect_builtins_sources blur/blurconfig.kcfgc - cube/cubeconfig.kcfgc cubeslide/cubeslideconfig.kcfgc desktopgrid/desktopgridconfig.kcfgc diminactive/diminactiveconfig.kcfgc @@ -196,7 +193,6 @@ add_subdirectory(zoom) # OpenGL-specific effects add_subdirectory(blur) include(backgroundcontrast/CMakeLists.txt) -add_subdirectory(cube) add_subdirectory(cubeslide) add_subdirectory(glide) add_subdirectory(invert) diff --git a/src/effects/cube/CMakeLists.txt b/src/effects/cube/CMakeLists.txt deleted file mode 100644 index 58b6664897..0000000000 --- a/src/effects/cube/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -####################################### -# Effect - -# Data files -install(FILES data/cubecap.png DESTINATION ${KDE_INSTALL_DATADIR}/kwin) - -####################################### -# Config - -set(kwin_cube_config_SRCS cube_config.cpp) -ki18n_wrap_ui(kwin_cube_config_SRCS cube_config.ui) -kconfig_add_kcfg_files(kwin_cube_config_SRCS cubeconfig.kcfgc) - -add_library(kwin_cube_config MODULE ${kwin_cube_config_SRCS}) - -target_link_libraries(kwin_cube_config - KF5::ConfigWidgets - KF5::GlobalAccel - KF5::I18n - KF5::XmlGui - KF5::KIOWidgets - KWinEffectsInterface -) - -kcoreaddons_desktop_to_json(kwin_cube_config cube_config.desktop SERVICE_TYPES kcmodule.desktop) - -install( - TARGETS - kwin_cube_config - DESTINATION - ${KDE_INSTALL_PLUGINDIR}/kwin/effects/configs -) diff --git a/src/effects/cube/cube.cpp b/src/effects/cube/cube.cpp deleted file mode 100644 index 9f73a2adf5..0000000000 --- a/src/effects/cube/cube.cpp +++ /dev/null @@ -1,1747 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2008 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "cube.h" -// KConfigSkeleton -#include "cubeconfig.h" - - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -namespace KWin -{ - -CubeEffect::CubeEffect() - : activated(false) - , cube_painting(false) - , keyboard_grab(false) - , painting_desktop(1) - , frontDesktop(0) - , cubeOpacity(1.0) - , opacityDesktopOnly(true) - , displayDesktopName(false) - , desktopNameFrame(nullptr) - , reflection(true) - , desktopChangedWhileRotating(false) - , paintCaps(true) - , wallpaper(nullptr) - , texturedCaps(true) - , capTexture(nullptr) - , lastPresentTime(std::chrono::milliseconds::zero()) - , reflectionPainting(false) - , activeScreen(0) - , bottomCap(false) - , closeOnMouseRelease(false) - , zoom(0.0) - , zPosition(0.0) - , useForTabBox(false) - , tabBoxMode(false) - , shortcutsRegistered(false) - , mode(Cube) - , useShaders(false) - , cylinderShader(nullptr) - , sphereShader(nullptr) - , zOrderingFactor(0.0f) - , mAddedHeightCoeff1(0.0f) - , mAddedHeightCoeff2(0.0f) - , m_cubeCapBuffer(nullptr) - , m_proxy(this) - , m_cubeAction(new QAction(this)) - , m_cylinderAction(new QAction(this)) - , m_sphereAction(new QAction(this)) -{ - initConfig(); - desktopNameFont.setBold(true); - desktopNameFont.setPointSize(14); - - if (effects->compositingType() == OpenGL2Compositing) { - m_reflectionShader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral("cube-reflection.glsl")); - m_capShader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral("cube-cap.glsl")); - } else { - m_reflectionShader = nullptr; - m_capShader = nullptr; - } - m_textureMirrorMatrix.scale(1.0, -1.0, 1.0); - m_textureMirrorMatrix.translate(0.0, -1.0, 0.0); - connect(effects, &EffectsHandler::tabBoxAdded, this, &CubeEffect::slotTabBoxAdded); - connect(effects, &EffectsHandler::tabBoxClosed, this, &CubeEffect::slotTabBoxClosed); - connect(effects, &EffectsHandler::tabBoxUpdated, this, &CubeEffect::slotTabBoxUpdated); - connect(effects, &EffectsHandler::screenAboutToLock, this, [this]() { - // Set active(false) does not release key grabs until the animation completes - // As we know the lockscreen is trying to grab them, release them early - // all other grabs are released in the normal way - setActive(false); - if (keyboard_grab) { - effects->ungrabKeyboard(); - keyboard_grab = false; - } - }); - - reconfigure(ReconfigureAll); -} - -bool CubeEffect::supported() -{ - return effects->isOpenGLCompositing(); -} - -void CubeEffect::reconfigure(ReconfigureFlags) -{ - CubeConfig::self()->read(); - Q_FOREACH (ElectricBorder border, borderActivate) { - effects->unreserveElectricBorder(border, this); - } - Q_FOREACH (ElectricBorder border, borderActivateCylinder) { - effects->unreserveElectricBorder(border, this); - } - Q_FOREACH (ElectricBorder border, borderActivateSphere) { - effects->unreserveElectricBorder(border, this); - } - borderActivate.clear(); - borderActivateCylinder.clear(); - borderActivateSphere.clear(); - QList borderList = QList(); - borderList.append(int(ElectricNone)); - borderList = CubeConfig::borderActivate(); - Q_FOREACH (int i, borderList) { - borderActivate.append(ElectricBorder(i)); - effects->reserveElectricBorder(ElectricBorder(i), this); - } - borderList.clear(); - borderList.append(int(ElectricNone)); - borderList = CubeConfig::borderActivateCylinder(); - Q_FOREACH (int i, borderList) { - borderActivateCylinder.append(ElectricBorder(i)); - effects->reserveElectricBorder(ElectricBorder(i), this); - } - borderList.clear(); - borderList.append(int(ElectricNone)); - borderList = CubeConfig::borderActivateSphere(); - Q_FOREACH (int i, borderList) { - borderActivateSphere.append(ElectricBorder(i)); - effects->reserveElectricBorder(ElectricBorder(i), this); - } - - cubeOpacity = (float)CubeConfig::opacity() / 100.0f; - opacityDesktopOnly = CubeConfig::opacityDesktopOnly(); - displayDesktopName = CubeConfig::displayDesktopName(); - reflection = CubeConfig::reflection(); - // TODO: Rename rotationDuration to duration so we - // can use animationTime(500). - const int d = CubeConfig::rotationDuration() != 0 - ? CubeConfig::rotationDuration() - : 500; - rotationDuration = std::chrono::milliseconds(static_cast(animationTime(d))); - backgroundColor = CubeConfig::backgroundColor(); - capColor = CubeConfig::capColor(); - paintCaps = CubeConfig::caps(); - closeOnMouseRelease = CubeConfig::closeOnMouseRelease(); - zPosition = CubeConfig::zPosition(); - - useForTabBox = CubeConfig::tabBox(); - invertKeys = CubeConfig::invertKeys(); - invertMouse = CubeConfig::invertMouse(); - capDeformationFactor = (float)CubeConfig::capDeformation() / 100.0f; - useZOrdering = CubeConfig::zOrdering(); - delete wallpaper; - wallpaper = nullptr; - delete capTexture; - capTexture = nullptr; - texturedCaps = CubeConfig::texturedCaps(); - - timeLine.setEasingCurve(QEasingCurve::InOutSine); - timeLine.setDuration(rotationDuration); - - verticalTimeLine.setEasingCurve(QEasingCurve::InOutSine); - verticalTimeLine.setDuration(rotationDuration); - - // do not connect the shortcut if we use cylinder or sphere - if (!shortcutsRegistered) { - QAction* cubeAction = m_cubeAction; - cubeAction->setObjectName(QStringLiteral("Cube")); - cubeAction->setText(i18n("Desktop Cube")); - KGlobalAccel::self()->setDefaultShortcut(cubeAction, QList() << Qt::CTRL + Qt::Key_F11); - KGlobalAccel::self()->setShortcut(cubeAction, QList() << Qt::CTRL + Qt::Key_F11); - effects->registerGlobalShortcut(Qt::CTRL + Qt::Key_F11, cubeAction); - effects->registerPointerShortcut(Qt::ControlModifier | Qt::AltModifier, Qt::LeftButton, cubeAction); - cubeShortcut = KGlobalAccel::self()->shortcut(cubeAction); - QAction* cylinderAction = m_cylinderAction; - cylinderAction->setObjectName(QStringLiteral("Cylinder")); - cylinderAction->setText(i18n("Desktop Cylinder")); - KGlobalAccel::self()->setShortcut(cylinderAction, QList()); - effects->registerGlobalShortcut(QKeySequence(), cylinderAction); - cylinderShortcut = KGlobalAccel::self()->shortcut(cylinderAction); - QAction* sphereAction = m_sphereAction; - sphereAction->setObjectName(QStringLiteral("Sphere")); - sphereAction->setText(i18n("Desktop Sphere")); - KGlobalAccel::self()->setShortcut(sphereAction, QList()); - sphereShortcut = KGlobalAccel::self()->shortcut(sphereAction); - effects->registerGlobalShortcut(QKeySequence(), sphereAction); - connect(cubeAction, &QAction::triggered, this, &CubeEffect::toggleCube); - connect(cylinderAction, &QAction::triggered, this, &CubeEffect::toggleCylinder); - connect(sphereAction, &QAction::triggered, this, &CubeEffect::toggleSphere); - connect(KGlobalAccel::self(), &KGlobalAccel::globalShortcutChanged, this, &CubeEffect::globalShortcutChanged); - shortcutsRegistered = true; - } - - // set the cap color on the shader - if (m_capShader && m_capShader->isValid()) { - ShaderBinder binder(m_capShader); - m_capShader->setUniform(GLShader::Color, capColor); - } - - // touch borders - const QVector relevantBorders{ElectricLeft, ElectricTop, ElectricRight, ElectricBottom}; - for (auto e : relevantBorders) { - effects->unregisterTouchBorder(e, m_cubeAction); - effects->unregisterTouchBorder(e, m_sphereAction); - effects->unregisterTouchBorder(e, m_cylinderAction); - } - auto touchEdge = [&relevantBorders] (const QList touchBorders, QAction *action) { - for (int i : touchBorders) { - if (!relevantBorders.contains(ElectricBorder(i))) { - continue; - } - effects->registerTouchBorder(ElectricBorder(i), action); - } - }; - touchEdge(CubeConfig::touchBorderActivate(), m_cubeAction); - touchEdge(CubeConfig::touchBorderActivateCylinder(), m_cylinderAction); - touchEdge(CubeConfig::touchBorderActivateSphere(), m_sphereAction); -} - -CubeEffect::~CubeEffect() -{ - delete wallpaper; - delete capTexture; - delete cylinderShader; - delete sphereShader; - delete desktopNameFrame; - delete m_reflectionShader; - delete m_capShader; - delete m_cubeCapBuffer; -} - -QImage CubeEffect::loadCubeCap(const QString &capPath) -{ - if (!texturedCaps) { - return QImage(); - } - return QImage(capPath); -} - -void CubeEffect::slotCubeCapLoaded() -{ - QFutureWatcher *watcher = dynamic_cast*>(sender()); - if (!watcher) { - // not invoked from future watcher - return; - } - QImage img = watcher->result(); - if (!img.isNull()) { - effects->makeOpenGLContextCurrent(); - capTexture = new GLTexture(img); - capTexture->setFilter(GL_LINEAR); - if (!GLPlatform::instance()->isGLES()) { - capTexture->setWrapMode(GL_CLAMP_TO_BORDER); - } - // need to recreate the VBO for the cube cap - delete m_cubeCapBuffer; - m_cubeCapBuffer = nullptr; - effects->addRepaintFull(); - } - watcher->deleteLater(); -} - -QImage CubeEffect::loadWallPaper(const QString &file) -{ - return QImage(file); -} - -void CubeEffect::slotWallPaperLoaded() -{ - QFutureWatcher *watcher = dynamic_cast*>(sender()); - if (!watcher) { - // not invoked from future watcher - return; - } - QImage img = watcher->result(); - if (!img.isNull()) { - effects->makeOpenGLContextCurrent(); - wallpaper = new GLTexture(img); - effects->addRepaintFull(); - } - watcher->deleteLater(); -} - -bool CubeEffect::loadShader() -{ - effects->makeOpenGLContextCurrent(); - if (!(GLPlatform::instance()->supports(GLSL) && - (effects->compositingType() == OpenGL2Compositing))) - return false; - - cylinderShader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture | ShaderTrait::AdjustSaturation | ShaderTrait::Modulate, QStringLiteral("cylinder.vert"), QString()); - if (!cylinderShader->isValid()) { - qCCritical(KWINEFFECTS) << "The cylinder shader failed to load!"; - return false; - } else { - ShaderBinder binder(cylinderShader); - cylinderShader->setUniform("sampler", 0); - QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop()); - cylinderShader->setUniform("width", (float)rect.width() * 0.5f); - } - - sphereShader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture | ShaderTrait::AdjustSaturation | ShaderTrait::Modulate, QStringLiteral("sphere.vert"), QString()); - if (!sphereShader->isValid()) { - qCCritical(KWINEFFECTS) << "The sphere shader failed to load!"; - return false; - } else { - ShaderBinder binder(sphereShader); - sphereShader->setUniform("sampler", 0); - QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop()); - sphereShader->setUniform("width", (float)rect.width() * 0.5f); - sphereShader->setUniform("height", (float)rect.height() * 0.5f); - sphereShader->setUniform("u_offset", QVector2D(0, 0)); - } - return true; -} - -void CubeEffect::startAnimation(AnimationState state) -{ - QEasingCurve curve; - /* If this is first and only animation -> EaseInOut - * there is more -> EaseIn - * If there was an animation before, and this is the last one -> EaseOut - * there is more -> Linear */ - if (animationState == AnimationState::None) { - curve.setType(animations.empty() ? QEasingCurve::InOutSine : QEasingCurve::InCurve); - } else { - curve.setType(animations.empty() ? QEasingCurve::OutCurve : QEasingCurve::Linear); - } - timeLine.reset(); - timeLine.setEasingCurve(curve); - startAngle = currentAngle; - startFrontDesktop = frontDesktop; - animationState = state; -} - -void CubeEffect::startVerticalAnimation(VerticalAnimationState state) -{ - /* Ignore if there is nowhere to rotate */ - if ((qFuzzyIsNull(verticalCurrentAngle - 90.0f) && state == VerticalAnimationState::Upwards) || - (qFuzzyIsNull(verticalCurrentAngle + 90.0f) && state == VerticalAnimationState::Downwards)) { - return; - } - verticalTimeLine.reset(); - verticalStartAngle = verticalCurrentAngle; - verticalAnimationState = state; -} - -void CubeEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) -{ - std::chrono::milliseconds delta = std::chrono::milliseconds::zero(); - if (lastPresentTime.count()) { - delta = presentTime - lastPresentTime; - } - lastPresentTime = presentTime; - - if (activated) { - data.mask |= PAINT_SCREEN_TRANSFORMED | Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS | PAINT_SCREEN_BACKGROUND_FIRST; - if (animationState == AnimationState::None && !animations.empty()) { - startAnimation(animations.dequeue()); - } - if (verticalAnimationState == VerticalAnimationState::None && !verticalAnimations.empty()) { - startVerticalAnimation(verticalAnimations.dequeue()); - } - - if (animationState != AnimationState::None || verticalAnimationState != VerticalAnimationState::None) { - if (animationState != AnimationState::None) { - timeLine.update(delta); - } - if (verticalAnimationState != VerticalAnimationState::None) { - verticalTimeLine.update(delta); - } - rotateCube(); - } - } - effects->prePaintScreen(data, presentTime); -} - -void CubeEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) -{ - if (activated) { - QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop()); - - // background - float clearColor[4]; - glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor); - glClearColor(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF(), 1.0); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); - - // wallpaper - if (wallpaper) { - ShaderBinder binder(ShaderTrait::MapTexture); - binder.shader()->setUniform(GLShader::ModelViewProjectionMatrix, data.projectionMatrix()); - wallpaper->bind(); - wallpaper->render(region, rect); - wallpaper->unbind(); - } - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - // some veriables needed for painting the caps - float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f); - float point = rect.width() / 2 * tan(cubeAngle * 0.5f * M_PI / 180.0f); - float zTranslate = zPosition + zoom; - if (animationState == AnimationState::Start) { - zTranslate *= timeLine.value(); - } else if (animationState == AnimationState::Stop) { - zTranslate *= (1.0 - timeLine.value()); - } - // reflection - if (reflection) { - // we can use a huge scale factor (needed to calculate the rearground vertices) - float scaleFactor = 1000000 * tan(60.0 * M_PI / 360.0f) / rect.height(); - m_reflectionMatrix.setToIdentity(); - m_reflectionMatrix.scale(1.0, -1.0, 1.0); - - double translate = 0.0; - if (mode == Cube) { - double addedHeight1 = -rect.height() * cos(verticalCurrentAngle*M_PI/180.0f) - rect.width() * sin(fabs(verticalCurrentAngle)*M_PI/180.0f)/tan(M_PI/effects->numberOfDesktops()); - double addedHeight2 = -rect.width() * sin(fabs(verticalCurrentAngle)*M_PI/180.0f)*tan(M_PI*0.5f/effects->numberOfDesktops()); - if (verticalCurrentAngle > 0.0f && effects->numberOfDesktops() & 1) - translate = cos(fabs(currentAngle)*effects->numberOfDesktops()*M_PI/360.0f) * addedHeight2 + addedHeight1 - float(rect.height()); - else - translate = sin(fabs(currentAngle)*effects->numberOfDesktops()*M_PI/360.0f) * addedHeight2 + addedHeight1 - float(rect.height()); - } else if (mode == Cylinder) { - double addedHeight1 = -rect.height() * cos(verticalCurrentAngle*M_PI/180.0f) - rect.width() * sin(fabs(verticalCurrentAngle)*M_PI/180.0f)/tan(M_PI/effects->numberOfDesktops()); - translate = addedHeight1 - float(rect.height()); - } else { - float radius = (rect.width() * 0.5) / cos(cubeAngle * 0.5 * M_PI / 180.0); - translate = -rect.height()-2*radius; - } - m_reflectionMatrix.translate(0.0f, translate, 0.0f); - - reflectionPainting = true; - glEnable(GL_CULL_FACE); - paintCap(true, -point - zTranslate, data.projectionMatrix()); - - // cube - glCullFace(GL_BACK); - paintCube(mask, region, data); - - glCullFace(GL_FRONT); - paintCube(mask, region, data); - - paintCap(false, -point - zTranslate, data.projectionMatrix()); - glDisable(GL_CULL_FACE); - reflectionPainting = false; - - const float width = rect.width(); - const float height = rect.height(); - float vertices[] = { - -width * 0.5f, height, 0.0, - width * 0.5f, height, 0.0, - width * scaleFactor, height, -5000, - -width * scaleFactor, height, -5000 - }; - // foreground - float alpha = 0.7; - if (animationState == AnimationState::Start) { - alpha = 0.3 + 0.4 * timeLine.value(); - } else if (animationState == AnimationState::Stop) { - alpha = 0.3 + 0.4 * (1.0 - timeLine.value()); - } - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - if (m_reflectionShader && m_reflectionShader->isValid()) { - // ensure blending is enabled - no attribute stack - ShaderBinder binder(m_reflectionShader); - QMatrix4x4 windowTransformation = data.projectionMatrix(); - windowTransformation.translate(rect.x() + rect.width() * 0.5f, 0.0, 0.0); - m_reflectionShader->setUniform(GLShader::ModelViewProjectionMatrix, windowTransformation); - m_reflectionShader->setUniform("u_alpha", alpha); - QVector verts; - QVector texcoords; - verts.reserve(18); - texcoords.reserve(12); - texcoords << 0.0 << 0.0; - verts << vertices[6] << vertices[7] << vertices[8]; - texcoords << 0.0 << 0.0; - verts << vertices[9] << vertices[10] << vertices[11]; - texcoords << 1.0 << 0.0; - verts << vertices[0] << vertices[1] << vertices[2]; - texcoords << 1.0 << 0.0; - verts << vertices[0] << vertices[1] << vertices[2]; - texcoords << 1.0 << 0.0; - verts << vertices[3] << vertices[4] << vertices[5]; - texcoords << 0.0 << 0.0; - verts << vertices[6] << vertices[7] << vertices[8]; - GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer(); - vbo->reset(); - vbo->setData(6, 3, verts.data(), texcoords.data()); - vbo->render(GL_TRIANGLES); - } - glDisable(GL_BLEND); - } - glEnable(GL_CULL_FACE); - // caps - paintCap(false, -point - zTranslate, data.projectionMatrix()); - - // cube - glCullFace(GL_FRONT); - paintCube(mask, region, data); - - glCullFace(GL_BACK); - paintCube(mask, region, data); - - // cap - paintCap(true, -point - zTranslate, data.projectionMatrix()); - glDisable(GL_CULL_FACE); - - glDisable(GL_BLEND); - - // desktop name box - inspired from coverswitch - if (displayDesktopName) { - double opacity = 1.0; - if (animationState == AnimationState::Start) { - opacity = timeLine.value(); - } else if (animationState == AnimationState::Stop) { - opacity = 1.0 - timeLine.value(); - } - QRect screenRect = effects->clientArea(ScreenArea, activeScreen, frontDesktop); - QRect frameRect = QRect(screenRect.width() * 0.33f + screenRect.x(), screenRect.height() * 0.95f + screenRect.y(), - screenRect.width() * 0.34f, QFontMetrics(desktopNameFont).height()); - if (!desktopNameFrame) { - desktopNameFrame = effects->effectFrame(EffectFrameStyled); - desktopNameFrame->setFont(desktopNameFont); - } - desktopNameFrame->setGeometry(frameRect); - desktopNameFrame->setText(effects->desktopName(frontDesktop)); - desktopNameFrame->render(region, opacity); - } - } else { - effects->paintScreen(mask, region, data); - } -} - -void CubeEffect::rotateCube() -{ - QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop()); - m_rotationMatrix.setToIdentity(); - float internalCubeAngle = 360.0f / effects->numberOfDesktops(); - float zTranslate = zPosition + zoom; - float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f); - float point = rect.width() / 2 * tan(cubeAngle * 0.5f * M_PI / 180.0f); - /* Animations */ - if (animationState == AnimationState::Start) { - zTranslate *= timeLine.value(); - } else if (animationState == AnimationState::Stop) { - currentAngle = startAngle * (1.0 - timeLine.value()); - zTranslate *= (1.0 - timeLine.value()); - } else if (animationState != AnimationState::None) { - /* Left or right */ - float endAngle = animationState == AnimationState::Right ? internalCubeAngle : -internalCubeAngle; - currentAngle = startAngle + timeLine.value() * (endAngle - startAngle); - frontDesktop = startFrontDesktop; - } - /* Switching to next desktop: either by mouse or due to animation */ - if (currentAngle > internalCubeAngle * 0.5f) { - currentAngle -= internalCubeAngle; - frontDesktop--; - if (frontDesktop < 1) { - frontDesktop = effects->numberOfDesktops(); - } - } - if (currentAngle < -internalCubeAngle * 0.5f) { - currentAngle += internalCubeAngle; - frontDesktop++; - if (frontDesktop > effects->numberOfDesktops()) { - frontDesktop = 1; - } - } - /* Vertical animations */ - if (verticalAnimationState != VerticalAnimationState::None) { - float verticalEndAngle = 0.0; - if (verticalAnimationState == VerticalAnimationState::Upwards && verticalStartAngle >= 0.0) { - verticalEndAngle = 90.0; - } - if (verticalAnimationState == VerticalAnimationState::Downwards && verticalStartAngle <= 0.0) { - verticalEndAngle = -90.0; - } - // This also handles the "VerticalAnimationState::Stop" correctly, since it has endAngle = 0.0 - verticalCurrentAngle = verticalStartAngle + verticalTimeLine.value() * (verticalEndAngle - verticalStartAngle); - } - /* Updating rotation matrix */ - if (verticalAnimationState != VerticalAnimationState::None || verticalCurrentAngle != 0.0f) { - m_rotationMatrix.translate(rect.width() / 2, rect.height() / 2, -point - zTranslate); - m_rotationMatrix.rotate(verticalCurrentAngle, 1.0, 0.0, 0.0); - m_rotationMatrix.translate(-rect.width() / 2, -rect.height() / 2, point + zTranslate); - } - if (animationState != AnimationState::None || currentAngle != 0.0f) { - m_rotationMatrix.translate(rect.width() / 2, rect.height() / 2, -point - zTranslate); - m_rotationMatrix.rotate(currentAngle, 0.0, 1.0, 0.0); - m_rotationMatrix.translate(-rect.width() / 2, -rect.height() / 2, point + zTranslate); - } -} - -void CubeEffect::paintCube(int mask, QRegion region, ScreenPaintData& data) -{ - QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop()); - float internalCubeAngle = 360.0f / effects->numberOfDesktops(); - cube_painting = true; - float zTranslate = zPosition + zoom; - if (animationState == AnimationState::Start) { - zTranslate *= timeLine.value(); - } else if (animationState == AnimationState::Stop) { - zTranslate *= (1.0 - timeLine.value()); - } - - // Rotation of the cube - float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f); - float point = rect.width() / 2 * tan(cubeAngle * 0.5f * M_PI / 180.0f); - - for (int i = 0; i < effects->numberOfDesktops(); i++) { - // start painting the cube - painting_desktop = (i + frontDesktop) % effects->numberOfDesktops(); - if (painting_desktop == 0) { - painting_desktop = effects->numberOfDesktops(); - } - QMatrix4x4 matrix; - matrix.translate(0, 0, -zTranslate); - const QVector3D origin(rect.width() / 2, 0.0, -point); - matrix.translate(origin); - matrix.rotate(internalCubeAngle * i, 0, 1, 0); - matrix.translate(-origin); - m_currentFaceMatrix = matrix; - effects->paintScreen(mask, region, data); - } - cube_painting = false; - painting_desktop = effects->currentDesktop(); -} - -void CubeEffect::paintCap(bool frontFirst, float zOffset, const QMatrix4x4 &projection) -{ - if ((!paintCaps) || effects->numberOfDesktops() <= 2) - return; - GLenum firstCull = frontFirst ? GL_FRONT : GL_BACK; - GLenum secondCull = frontFirst ? GL_BACK : GL_FRONT; - const QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop()); - - // create the VBO if not yet created - if (!m_cubeCapBuffer) { - switch(mode) { - case Cube: - paintCubeCap(); - break; - case Cylinder: - paintCylinderCap(); - break; - case Sphere: - paintSphereCap(); - break; - default: - // impossible - break; - } - } - - QMatrix4x4 capMvp; - QMatrix4x4 capMatrix; - capMatrix.translate(rect.width() / 2, 0.0, zOffset); - capMatrix.rotate((1 - frontDesktop) * 360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0); - capMatrix.translate(0.0, rect.height(), 0.0); - if (mode == Sphere) { - capMatrix.scale(1.0, -1.0, 1.0); - } - - bool capShader = false; - if (effects->compositingType() == OpenGL2Compositing && m_capShader && m_capShader->isValid()) { - capShader = true; - ShaderManager::instance()->pushShader(m_capShader); - float opacity = cubeOpacity; - if (animationState == AnimationState::Start) { - opacity *= timeLine.value(); - } else if (animationState == AnimationState::Stop) { - opacity *= (1.0 - timeLine.value()); - } - m_capShader->setUniform("u_opacity", opacity); - m_capShader->setUniform("u_mirror", 1); - if (reflectionPainting) { - capMvp = projection * m_reflectionMatrix * m_rotationMatrix; - } else { - capMvp = projection * m_rotationMatrix; - } - m_capShader->setUniform(GLShader::ModelViewProjectionMatrix, capMvp * capMatrix); - m_capShader->setUniform("u_untextured", texturedCaps ? 0 : 1); - if (texturedCaps && effects->numberOfDesktops() > 3 && capTexture) { - capTexture->bind(); - } - } - - glEnable(GL_BLEND); - glCullFace(firstCull); - m_cubeCapBuffer->render(GL_TRIANGLES); - - if (mode == Sphere) { - capMatrix.scale(1.0, -1.0, 1.0); - } - capMatrix.translate(0.0, -rect.height(), 0.0); - if (capShader) { - m_capShader->setUniform(GLShader::ModelViewProjectionMatrix, capMvp * capMatrix); - m_capShader->setUniform("u_mirror", 0); - } - glCullFace(secondCull); - m_cubeCapBuffer->render(GL_TRIANGLES); - glDisable(GL_BLEND); - - if (capShader) { - ShaderManager::instance()->popShader(); - if (texturedCaps && effects->numberOfDesktops() > 3 && capTexture) { - capTexture->unbind(); - } - } -} - -void CubeEffect::paintCubeCap() -{ - QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop()); - float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f); - float z = rect.width() / 2 * tan(cubeAngle * 0.5f * M_PI / 180.0f); - float zTexture = rect.width() / 2 * tan(45.0f * M_PI / 180.0f); - float angle = 360.0f / effects->numberOfDesktops(); - bool texture = texturedCaps && effects->numberOfDesktops() > 3 && capTexture; - QVector verts; - QVector texCoords; - for (int i = 0; i < effects->numberOfDesktops(); i++) { - int triangleRows = effects->numberOfDesktops() * 5; - float zTriangleDistance = z / (float)triangleRows; - float widthTriangle = tan(angle * 0.5 * M_PI / 180.0) * zTriangleDistance; - float currentWidth = 0.0; - float cosValue = cos(i * angle * M_PI / 180.0); - float sinValue = sin(i * angle * M_PI / 180.0); - for (int j = 0; j < triangleRows; j++) { - float previousWidth = currentWidth; - currentWidth = tan(angle * 0.5 * M_PI / 180.0) * zTriangleDistance * (j + 1); - int evenTriangles = 0; - int oddTriangles = 0; - for (int k = 0; k < floor(currentWidth / widthTriangle * 2 - 1 + 0.5f); k++) { - float x1 = -previousWidth; - float x2 = -currentWidth; - float x3 = 0.0; - float z1 = 0.0; - float z2 = 0.0; - float z3 = 0.0; - if (k % 2 == 0) { - x1 += evenTriangles * widthTriangle * 2; - x2 += evenTriangles * widthTriangle * 2; - x3 = x2 + widthTriangle * 2; - z1 = j * zTriangleDistance; - z2 = (j + 1) * zTriangleDistance; - z3 = (j + 1) * zTriangleDistance; - float xRot = cosValue * x1 - sinValue * z1; - float zRot = sinValue * x1 + cosValue * z1; - x1 = xRot; - z1 = zRot; - xRot = cosValue * x2 - sinValue * z2; - zRot = sinValue * x2 + cosValue * z2; - x2 = xRot; - z2 = zRot; - xRot = cosValue * x3 - sinValue * z3; - zRot = sinValue * x3 + cosValue * z3; - x3 = xRot; - z3 = zRot; - evenTriangles++; - } else { - x1 += oddTriangles * widthTriangle * 2; - x2 += (oddTriangles + 1) * widthTriangle * 2; - x3 = x1 + widthTriangle * 2; - z1 = j * zTriangleDistance; - z2 = (j + 1) * zTriangleDistance; - z3 = j * zTriangleDistance; - float xRot = cosValue * x1 - sinValue * z1; - float zRot = sinValue * x1 + cosValue * z1; - x1 = xRot; - z1 = zRot; - xRot = cosValue * x2 - sinValue * z2; - zRot = sinValue * x2 + cosValue * z2; - x2 = xRot; - z2 = zRot; - xRot = cosValue * x3 - sinValue * z3; - zRot = sinValue * x3 + cosValue * z3; - x3 = xRot; - z3 = zRot; - oddTriangles++; - } - float texX1 = 0.0; - float texX2 = 0.0; - float texX3 = 0.0; - float texY1 = 0.0; - float texY2 = 0.0; - float texY3 = 0.0; - if (texture) { - if (capTexture->isYInverted()) { - texX1 = x1 / (rect.width()) + 0.5; - texY1 = 0.5 + z1 / zTexture * 0.5; - texX2 = x2 / (rect.width()) + 0.5; - texY2 = 0.5 + z2 / zTexture * 0.5; - texX3 = x3 / (rect.width()) + 0.5; - texY3 = 0.5 + z3 / zTexture * 0.5; - texCoords << texX1 << texY1; - } else { - texX1 = x1 / (rect.width()) + 0.5; - texY1 = 0.5 - z1 / zTexture * 0.5; - texX2 = x2 / (rect.width()) + 0.5; - texY2 = 0.5 - z2 / zTexture * 0.5; - texX3 = x3 / (rect.width()) + 0.5; - texY3 = 0.5 - z3 / zTexture * 0.5; - texCoords << texX1 << texY1; - } - } - verts << x1 << 0.0 << z1; - if (texture) { - texCoords << texX2 << texY2; - } - verts << x2 << 0.0 << z2; - if (texture) { - texCoords << texX3 << texY3; - } - verts << x3 << 0.0 << z3; - } - } - } - delete m_cubeCapBuffer; - m_cubeCapBuffer = new GLVertexBuffer(GLVertexBuffer::Static); - m_cubeCapBuffer->setData(verts.count() / 3, 3, verts.constData(), texture ? texCoords.constData() : nullptr); -} - -void CubeEffect::paintCylinderCap() -{ - QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop()); - float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f); - - float radian = (cubeAngle * 0.5) * M_PI / 180; - float radius = (rect.width() * 0.5) * tan(radian); - float segment = radius / 30.0f; - - bool texture = texturedCaps && effects->numberOfDesktops() > 3 && capTexture; - QVector verts; - QVector texCoords; - for (int i = 1; i <= 30; i++) { - int steps = 72; - for (int j = 0; j <= steps; j++) { - const float azimuthAngle = (j * (360.0f / steps)) * M_PI / 180.0f; - const float azimuthAngle2 = ((j + 1) * (360.0f / steps)) * M_PI / 180.0f; - const float x1 = segment * (i - 1) * sin(azimuthAngle); - const float x2 = segment * i * sin(azimuthAngle); - const float x3 = segment * (i - 1) * sin(azimuthAngle2); - const float x4 = segment * i * sin(azimuthAngle2); - const float z1 = segment * (i - 1) * cos(azimuthAngle); - const float z2 = segment * i * cos(azimuthAngle); - const float z3 = segment * (i - 1) * cos(azimuthAngle2); - const float z4 = segment * i * cos(azimuthAngle2); - if (texture) { - if (capTexture->isYInverted()) { - texCoords << (radius + x1) / (radius * 2.0f) << (z1 + radius) / (radius * 2.0f); - texCoords << (radius + x2) / (radius * 2.0f) << (z2 + radius) / (radius * 2.0f); - texCoords << (radius + x3) / (radius * 2.0f) << (z3 + radius) / (radius * 2.0f); - texCoords << (radius + x4) / (radius * 2.0f) << (z4 + radius) / (radius * 2.0f); - texCoords << (radius + x3) / (radius * 2.0f) << (z3 + radius) / (radius * 2.0f); - texCoords << (radius + x2) / (radius * 2.0f) << (z2 + radius) / (radius * 2.0f); - } else { - texCoords << (radius + x1) / (radius * 2.0f) << 1.0f - (z1 + radius) / (radius * 2.0f); - texCoords << (radius + x2) / (radius * 2.0f) << 1.0f - (z2 + radius) / (radius * 2.0f); - texCoords << (radius + x3) / (radius * 2.0f) << 1.0f - (z3 + radius) / (radius * 2.0f); - texCoords << (radius + x4) / (radius * 2.0f) << 1.0f - (z4 + radius) / (radius * 2.0f); - texCoords << (radius + x3) / (radius * 2.0f) << 1.0f - (z3 + radius) / (radius * 2.0f); - texCoords << (radius + x2) / (radius * 2.0f) << 1.0f - (z2 + radius) / (radius * 2.0f); - } - } - verts << x1 << 0.0 << z1; - verts << x2 << 0.0 << z2; - verts << x3 << 0.0 << z3; - verts << x4 << 0.0 << z4; - verts << x3 << 0.0 << z3; - verts << x2 << 0.0 << z2; - } - } - delete m_cubeCapBuffer; - m_cubeCapBuffer = new GLVertexBuffer(GLVertexBuffer::Static); - m_cubeCapBuffer->setData(verts.count() / 3, 3, verts.constData(), texture ? texCoords.constData() : nullptr); -} - -void CubeEffect::paintSphereCap() -{ - QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop()); - float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f); - float zTexture = rect.width() / 2 * tan(45.0f * M_PI / 180.0f); - float radius = (rect.width() * 0.5) / cos(cubeAngle * 0.5 * M_PI / 180.0); - float angle = acos((rect.height() * 0.5) / radius) * 180.0 / M_PI; - angle /= 30; - bool texture = texturedCaps && effects->numberOfDesktops() > 3 && capTexture; - QVector verts; - QVector texCoords; - for (int i = 0; i < 30; i++) { - float topAngle = angle * i * M_PI / 180.0; - float bottomAngle = angle * (i + 1) * M_PI / 180.0; - float yTop = (rect.height() * 0.5 - radius * cos(topAngle)); - yTop *= (1.0f-capDeformationFactor); - float yBottom = rect.height() * 0.5 - radius * cos(bottomAngle); - yBottom *= (1.0f - capDeformationFactor); - for (int j = 0; j < 36; j++) { - const float x1 = radius * sin(topAngle) * sin((90.0 + j * 10.0) * M_PI / 180.0); - const float z1 = radius * sin(topAngle) * cos((90.0 + j * 10.0) * M_PI / 180.0); - const float x2 = radius * sin(bottomAngle) * sin((90.0 + j * 10.0) * M_PI / 180.00); - const float z2 = radius * sin(bottomAngle) * cos((90.0 + j * 10.0) * M_PI / 180.0); - const float x3 = radius * sin(bottomAngle) * sin((90.0 + (j + 1) * 10.0) * M_PI / 180.0); - const float z3 = radius * sin(bottomAngle) * cos((90.0 + (j + 1) * 10.0) * M_PI / 180.0); - const float x4 = radius * sin(topAngle) * sin((90.0 + (j + 1) * 10.0) * M_PI / 180.0); - const float z4 = radius * sin(topAngle) * cos((90.0 + (j + 1) * 10.0) * M_PI / 180.0); - if (texture) { - if (capTexture->isYInverted()) { - texCoords << x4 / (rect.width()) + 0.5 << 0.5 + z4 / zTexture * 0.5; - texCoords << x1 / (rect.width()) + 0.5 << 0.5 + z1 / zTexture * 0.5; - texCoords << x2 / (rect.width()) + 0.5 << 0.5 + z2 / zTexture * 0.5; - texCoords << x2 / (rect.width()) + 0.5 << 0.5 + z2 / zTexture * 0.5; - texCoords << x3 / (rect.width()) + 0.5 << 0.5 + z3 / zTexture * 0.5; - texCoords << x4 / (rect.width()) + 0.5 << 0.5 + z4 / zTexture * 0.5; - } else { - texCoords << x4 / (rect.width()) + 0.5 << 0.5 - z4 / zTexture * 0.5; - texCoords << x1 / (rect.width()) + 0.5 << 0.5 - z1 / zTexture * 0.5; - texCoords << x2 / (rect.width()) + 0.5 << 0.5 - z2 / zTexture * 0.5; - texCoords << x2 / (rect.width()) + 0.5 << 0.5 - z2 / zTexture * 0.5; - texCoords << x3 / (rect.width()) + 0.5 << 0.5 - z3 / zTexture * 0.5; - texCoords << x4 / (rect.width()) + 0.5 << 0.5 - z4 / zTexture * 0.5; - } - } - verts << x4 << yTop << z4; - verts << x1 << yTop << z1; - verts << x2 << yBottom << z2; - verts << x2 << yBottom << z2; - verts << x3 << yBottom << z3; - verts << x4 << yTop << z4; - } - } - delete m_cubeCapBuffer; - m_cubeCapBuffer = new GLVertexBuffer(GLVertexBuffer::Static); - m_cubeCapBuffer->setData(verts.count() / 3, 3, verts.constData(), texture ? texCoords.constData() : nullptr); -} - -void CubeEffect::postPaintScreen() -{ - effects->postPaintScreen(); - if (!activated) - return; - - bool animation = (animationState != AnimationState::None || verticalAnimationState != VerticalAnimationState::None); - if (animationState != AnimationState::None && timeLine.done()) { - /* An animation have just finished! */ - if (animationState == AnimationState::Stop) { - /* If the stop animation is finished, we're done */ - if (keyboard_grab) - effects->ungrabKeyboard(); - keyboard_grab = false; - effects->stopMouseInterception(this); - effects->setCurrentDesktop(frontDesktop); - effects->setActiveFullScreenEffect(nullptr); - delete m_cubeCapBuffer; - m_cubeCapBuffer = nullptr; - if (desktopNameFrame) - desktopNameFrame->free(); - activated = false; - // User can press Esc several times, and several Stop animations can be added to queue. We don't want it - animationState = AnimationState::None; - animations.clear(); - verticalAnimationState = VerticalAnimationState::None; - verticalAnimations.clear(); - lastPresentTime = std::chrono::milliseconds::zero(); - } else { - if (!animations.empty()) - startAnimation(animations.dequeue()); - else - animationState = AnimationState::None; - } - } - /* Vertical animation have finished */ - if (verticalAnimationState != VerticalAnimationState::None && verticalTimeLine.done()) { - if (!verticalAnimations.empty()) { - startVerticalAnimation(verticalAnimations.dequeue()); - } else { - verticalAnimationState = VerticalAnimationState::None; - } - } - /* Repaint if there is any animation */ - if (animation) { - effects->addRepaintFull(); - } else { - lastPresentTime = std::chrono::milliseconds::zero(); - } -} - -void CubeEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) -{ - if (activated) { - if (cube_painting) { - if (mode == Cylinder || mode == Sphere) { - int leftDesktop = frontDesktop - 1; - int rightDesktop = frontDesktop + 1; - if (leftDesktop == 0) - leftDesktop = effects->numberOfDesktops(); - if (rightDesktop > effects->numberOfDesktops()) - rightDesktop = 1; - if (painting_desktop == frontDesktop) - data.quads = data.quads.makeGrid(40); - else if (painting_desktop == leftDesktop || painting_desktop == rightDesktop) - data.quads = data.quads.makeGrid(100); - else - data.quads = data.quads.makeGrid(250); - } - if (w->isOnDesktop(painting_desktop)) { - QRect rect = effects->clientArea(FullArea, activeScreen, painting_desktop); - if (w->x() < rect.x()) { - data.quads = data.quads.splitAtX(-w->x()); - } - if (w->x() + w->width() > rect.x() + rect.width()) { - data.quads = data.quads.splitAtX(rect.width() - w->x()); - } - if (w->y() < rect.y()) { - data.quads = data.quads.splitAtY(-w->y()); - } - if (w->y() + w->height() > rect.y() + rect.height()) { - data.quads = data.quads.splitAtY(rect.height() - w->y()); - } - if (useZOrdering && !w->isDesktop() && !w->isDock() && !w->isOnAllDesktops()) - data.setTransformed(); - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); - } else { - // check for windows belonging to the previous desktop - int prev_desktop = painting_desktop - 1; - if (prev_desktop == 0) - prev_desktop = effects->numberOfDesktops(); - if (w->isOnDesktop(prev_desktop) && mode == Cube && !useZOrdering) { - QRect rect = effects->clientArea(FullArea, activeScreen, prev_desktop); - if (w->x() + w->width() > rect.x() + rect.width()) { - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); - data.quads = data.quads.splitAtX(rect.width() - w->x()); - if (w->y() < rect.y()) { - data.quads = data.quads.splitAtY(-w->y()); - } - if (w->y() + w->height() > rect.y() + rect.height()) { - data.quads = data.quads.splitAtY(rect.height() - w->y()); - } - data.setTransformed(); - effects->prePaintWindow(w, data, presentTime); - return; - } - } - // check for windows belonging to the next desktop - int next_desktop = painting_desktop + 1; - if (next_desktop > effects->numberOfDesktops()) - next_desktop = 1; - if (w->isOnDesktop(next_desktop) && mode == Cube && !useZOrdering) { - QRect rect = effects->clientArea(FullArea, activeScreen, next_desktop); - if (w->x() < rect.x()) { - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); - data.quads = data.quads.splitAtX(-w->x()); - if (w->y() < rect.y()) { - data.quads = data.quads.splitAtY(-w->y()); - } - if (w->y() + w->height() > rect.y() + rect.height()) { - data.quads = data.quads.splitAtY(rect.height() - w->y()); - } - data.setTransformed(); - effects->prePaintWindow(w, data, presentTime); - return; - } - } - w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); - } - } - } - effects->prePaintWindow(w, data, presentTime); -} - -void CubeEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) -{ - ShaderManager *shaderManager = ShaderManager::instance(); - if (activated && cube_painting) { - region= infiniteRegion(); // we need to explicitly prevent any clipping, bug #325432 - //qCDebug(KWINEFFECTS) << w->caption(); - float opacity = cubeOpacity; - if (animationState == AnimationState::Start) { - opacity = 1.0 - (1.0 - opacity) * timeLine.value(); - if (reflectionPainting) - opacity = 0.5 + (cubeOpacity - 0.5) * timeLine.value(); - // fade in windows belonging to different desktops - if (painting_desktop == effects->currentDesktop() && (!w->isOnDesktop(painting_desktop))) - opacity = timeLine.value() * cubeOpacity; - } else if (animationState == AnimationState::Stop) { - opacity = 1.0 - (1.0 - opacity) * (1.0 - timeLine.value()); - if (reflectionPainting) - opacity = 0.5 + (cubeOpacity - 0.5) * (1.0 - timeLine.value()); - // fade out windows belonging to different desktops - if (painting_desktop == effects->currentDesktop() && (!w->isOnDesktop(painting_desktop))) - opacity = cubeOpacity * (1.0 - timeLine.value()); - } - // z-Ordering - if (!w->isDesktop() && !w->isDock() && useZOrdering && !w->isOnAllDesktops()) { - float zOrdering = (effects->stackingOrder().indexOf(w) + 1) * zOrderingFactor; - if (animationState == AnimationState::Start) { - zOrdering *= timeLine.value(); - } else if (animationState == AnimationState::Stop) { - zOrdering *= (1.0 - timeLine.value()); - } - data.translate(0.0, 0.0, zOrdering); - } - // check for windows belonging to the previous desktop - int prev_desktop = painting_desktop - 1; - if (prev_desktop == 0) - prev_desktop = effects->numberOfDesktops(); - int next_desktop = painting_desktop + 1; - if (next_desktop > effects->numberOfDesktops()) - next_desktop = 1; - if (w->isOnDesktop(prev_desktop) && (mask & PAINT_WINDOW_TRANSFORMED)) { - QRect rect = effects->clientArea(FullArea, activeScreen, prev_desktop); - WindowQuadList new_quads; - Q_FOREACH (const WindowQuad & quad, data.quads) { - if (quad.right() > rect.width() - w->x()) { - new_quads.append(quad); - } - } - data.quads = new_quads; - data.setXTranslation(-rect.width()); - } - if (w->isOnDesktop(next_desktop) && (mask & PAINT_WINDOW_TRANSFORMED)) { - QRect rect = effects->clientArea(FullArea, activeScreen, next_desktop); - WindowQuadList new_quads; - Q_FOREACH (const WindowQuad & quad, data.quads) { - if (w->x() + quad.right() <= rect.x()) { - new_quads.append(quad); - } - } - data.quads = new_quads; - data.setXTranslation(rect.width()); - } - QRect rect = effects->clientArea(FullArea, activeScreen, painting_desktop); - - if (animationState == AnimationState::Start || animationState == AnimationState::Stop) { - // we have to change opacity values for fade in/out of windows which are shown on front-desktop - if (prev_desktop == effects->currentDesktop() && w->x() < rect.x()) { - if (animationState == AnimationState::Start) { - opacity = timeLine.value() * cubeOpacity; - } else if (animationState == AnimationState::Stop) { - opacity = cubeOpacity * (1.0 - timeLine.value()); - } - } - if (next_desktop == effects->currentDesktop() && w->x() + w->width() > rect.x() + rect.width()) { - if (animationState == AnimationState::Start) { - opacity = timeLine.value() * cubeOpacity; - } else if (animationState == AnimationState::Stop) { - opacity = cubeOpacity * (1.0 - timeLine.value()); - } - } - } - // HACK set opacity to 0.99 in case of fully opaque to ensure that windows are painted in correct sequence - // bug #173214 - if (opacity > 0.99f) - opacity = 0.99f; - if (opacityDesktopOnly && !w->isDesktop()) - opacity = 0.99f; - data.multiplyOpacity(opacity); - - if (w->isOnDesktop(painting_desktop) && w->x() < rect.x()) { - WindowQuadList new_quads; - Q_FOREACH (const WindowQuad & quad, data.quads) { - if (quad.right() > -w->x()) { - new_quads.append(quad); - } - } - data.quads = new_quads; - } - if (w->isOnDesktop(painting_desktop) && w->x() + w->width() > rect.x() + rect.width()) { - WindowQuadList new_quads; - Q_FOREACH (const WindowQuad & quad, data.quads) { - if (quad.right() <= rect.width() - w->x()) { - new_quads.append(quad); - } - } - data.quads = new_quads; - } - if (w->y() < rect.y()) { - WindowQuadList new_quads; - Q_FOREACH (const WindowQuad & quad, data.quads) { - if (quad.bottom() > -w->y()) { - new_quads.append(quad); - } - } - data.quads = new_quads; - } - if (w->y() + w->height() > rect.y() + rect.height()) { - WindowQuadList new_quads; - Q_FOREACH (const WindowQuad & quad, data.quads) { - if (quad.bottom() <= rect.height() - w->y()) { - new_quads.append(quad); - } - } - data.quads = new_quads; - } - GLShader *currentShader = nullptr; - if (mode == Cylinder) { - shaderManager->pushShader(cylinderShader); - cylinderShader->setUniform("xCoord", (float)w->x()); - cylinderShader->setUniform("cubeAngle", (effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 90.0f); - float factor = 0.0f; - if (animationState == AnimationState::Start) { - factor = 1.0f - timeLine.value(); - } else if (animationState == AnimationState::Stop) { - factor = timeLine.value(); - } - cylinderShader->setUniform("timeLine", factor); - currentShader = cylinderShader; - } - if (mode == Sphere) { - shaderManager->pushShader(sphereShader); - sphereShader->setUniform("u_offset", QVector2D(w->x(), w->y())); - sphereShader->setUniform("cubeAngle", (effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 90.0f); - float factor = 0.0f; - if (animationState == AnimationState::Start) { - factor = 1.0f - timeLine.value(); - } else if (animationState == AnimationState::Stop) { - factor = timeLine.value(); - } - sphereShader->setUniform("timeLine", factor); - currentShader = sphereShader; - } - if (currentShader) { - data.shader = currentShader; - } - data.setProjectionMatrix(data.screenProjectionMatrix()); - if (reflectionPainting) { - data.setModelViewMatrix(m_reflectionMatrix * m_rotationMatrix * m_currentFaceMatrix); - } else { - data.setModelViewMatrix(m_rotationMatrix * m_currentFaceMatrix); - } - } - effects->paintWindow(w, mask, region, data); - if (activated && cube_painting) { - if (mode == Cylinder || mode == Sphere) { - shaderManager->popShader(); - } - if (w->isDesktop() && effects->numScreens() > 1 && paintCaps) { - QRect rect = effects->clientArea(FullArea, activeScreen, painting_desktop); - QRegion paint = QRegion(rect); - for (int i = 0; i < effects->numScreens(); i++) { - if (i == w->screen()) - continue; - paint = paint.subtracted(QRegion(effects->clientArea(ScreenArea, i, painting_desktop))); - } - paint = paint.subtracted(QRegion(w->frameGeometry())); - // in case of free area in multiscreen setup fill it with cap color - if (!paint.isEmpty()) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - QVector verts; - float quadSize = 0.0f; - int leftDesktop = frontDesktop - 1; - int rightDesktop = frontDesktop + 1; - if (leftDesktop == 0) - leftDesktop = effects->numberOfDesktops(); - if (rightDesktop > effects->numberOfDesktops()) - rightDesktop = 1; - if (painting_desktop == frontDesktop) - quadSize = 100.0f; - else if (painting_desktop == leftDesktop || painting_desktop == rightDesktop) - quadSize = 150.0f; - else - quadSize = 250.0f; - for (const QRect &paintRect : paint) { - for (int i = 0; i <= (paintRect.height() / quadSize); i++) { - for (int j = 0; j <= (paintRect.width() / quadSize); j++) { - verts << qMin(paintRect.x() + (j + 1)*quadSize, (float)paintRect.x() + paintRect.width()) << paintRect.y() + i*quadSize; - verts << paintRect.x() + j*quadSize << paintRect.y() + i*quadSize; - verts << paintRect.x() + j*quadSize << qMin(paintRect.y() + (i + 1)*quadSize, (float)paintRect.y() + paintRect.height()); - verts << paintRect.x() + j*quadSize << qMin(paintRect.y() + (i + 1)*quadSize, (float)paintRect.y() + paintRect.height()); - verts << qMin(paintRect.x() + (j + 1)*quadSize, (float)paintRect.x() + paintRect.width()) << qMin(paintRect.y() + (i + 1)*quadSize, (float)paintRect.y() + paintRect.height()); - verts << qMin(paintRect.x() + (j + 1)*quadSize, (float)paintRect.x() + paintRect.width()) << paintRect.y() + i*quadSize; - } - } - } - bool capShader = false; - if (effects->compositingType() == OpenGL2Compositing && m_capShader && m_capShader->isValid()) { - capShader = true; - ShaderManager::instance()->pushShader(m_capShader); - m_capShader->setUniform("u_mirror", 0); - m_capShader->setUniform("u_untextured", 1); - QMatrix4x4 mvp = data.screenProjectionMatrix(); - if (reflectionPainting) { - mvp = mvp * m_reflectionMatrix * m_rotationMatrix * m_currentFaceMatrix; - } else { - mvp = mvp * m_rotationMatrix * m_currentFaceMatrix; - } - m_capShader->setUniform(GLShader::ModelViewProjectionMatrix, mvp); - } - GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer(); - vbo->reset(); - QColor color = capColor; - capColor.setAlphaF(cubeOpacity); - vbo->setColor(color); - vbo->setData(verts.size() / 2, 2, verts.constData(), nullptr); - if (!capShader || mode == Cube) { - // TODO: use sphere and cylinder shaders - vbo->render(GL_TRIANGLES); - } - if (capShader) { - ShaderManager::instance()->popShader(); - } - glDisable(GL_BLEND); - } - } - } -} - -bool CubeEffect::borderActivated(ElectricBorder border) -{ - if (!borderActivate.contains(border) && - !borderActivateCylinder.contains(border) && - !borderActivateSphere.contains(border)) - return false; - if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this) - return false; - if (borderActivate.contains(border)) { - if (!activated || (activated && mode == Cube)) - toggleCube(); - else - return false; - } - if (borderActivateCylinder.contains(border)) { - if (!activated || (activated && mode == Cylinder)) - toggleCylinder(); - else - return false; - } - if (borderActivateSphere.contains(border)) { - if (!activated || (activated && mode == Sphere)) - toggleSphere(); - else - return false; - } - return true; -} - -void CubeEffect::toggleCube() -{ - qCDebug(KWINEFFECTS) << "toggle cube"; - toggle(Cube); -} - -void CubeEffect::toggleCylinder() -{ - qCDebug(KWINEFFECTS) << "toggle cylinder"; - if (!useShaders) - useShaders = loadShader(); - if (useShaders) - toggle(Cylinder); -} - -void CubeEffect::toggleSphere() -{ - qCDebug(KWINEFFECTS) << "toggle sphere"; - if (!useShaders) - useShaders = loadShader(); - if (useShaders) - toggle(Sphere); -} - -void CubeEffect::toggle(CubeMode newMode) -{ - if ((effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this) || - effects->numberOfDesktops() < 2) - return; - if (!activated) { - mode = newMode; - setActive(true); - } else { - setActive(false); - } -} - -void CubeEffect::grabbedKeyboardEvent(QKeyEvent* e) -{ - // If either stop is running or is scheduled - ignore all events - if ((!animations.isEmpty() && animations.last() == AnimationState::Stop) || animationState == AnimationState::Stop) { - return; - } - // taken from desktopgrid.cpp - if (e->type() == QEvent::KeyPress) { - // check for global shortcuts - // HACK: keyboard grab disables the global shortcuts so we have to check for global shortcut (bug 156155) - if (mode == Cube && cubeShortcut.contains(e->key() + e->modifiers())) { - toggleCube(); - return; - } - if (mode == Cylinder && cylinderShortcut.contains(e->key() + e->modifiers())) { - toggleCylinder(); - return; - } - if (mode == Sphere && sphereShortcut.contains(e->key() + e->modifiers())) { - toggleSphere(); - return; - } - - int desktop = -1; - // switch by F or just - if (e->key() >= Qt::Key_F1 && e->key() <= Qt::Key_F35) - desktop = e->key() - Qt::Key_F1 + 1; - else if (e->key() >= Qt::Key_0 && e->key() <= Qt::Key_9) - desktop = e->key() == Qt::Key_0 ? 10 : e->key() - Qt::Key_0; - if (desktop != -1) { - if (desktop <= effects->numberOfDesktops()) { - // we have to rotate to chosen desktop - // and end effect when rotation finished - rotateToDesktop(desktop); - setActive(false); - } - return; - } - - int key = e->key(); - if (invertKeys) { - if (key == Qt::Key_Left) - key = Qt::Key_Right; - else if (key == Qt::Key_Right) - key = Qt::Key_Left; - else if (key == Qt::Key_Up) - key = Qt::Key_Down; - else if (key == Qt::Key_Down) - key = Qt::Key_Up; - } - - switch(key) { - // wrap only on autorepeat - case Qt::Key_Left: - qCDebug(KWINEFFECTS) << "left"; - if (animations.count() < effects->numberOfDesktops()) - animations.enqueue(AnimationState::Left); - break; - case Qt::Key_Right: - qCDebug(KWINEFFECTS) << "right"; - if (animations.count() < effects->numberOfDesktops()) - animations.enqueue(AnimationState::Right); - break; - case Qt::Key_Up: - qCDebug(KWINEFFECTS) << "up"; - verticalAnimations.enqueue(VerticalAnimationState::Upwards); - break; - case Qt::Key_Down: - qCDebug(KWINEFFECTS) << "down"; - verticalAnimations.enqueue(VerticalAnimationState::Downwards); - break; - case Qt::Key_Escape: - rotateToDesktop(effects->currentDesktop()); - setActive(false); - return; - case Qt::Key_Enter: - case Qt::Key_Return: - case Qt::Key_Space: - setActive(false); - return; - case Qt::Key_Plus: - case Qt::Key_Equal: - zoom -= 10.0; - zoom = qMax(-zPosition, zoom); - rotateCube(); - break; - case Qt::Key_Minus: - zoom += 10.0f; - rotateCube(); - break; - default: - break; - } - } - effects->addRepaintFull(); -} - -void CubeEffect::rotateToDesktop(int desktop) -{ - // all scheduled animations will be removed as a speed up - animations.clear(); - verticalAnimations.clear(); - // we want only startAnimation to finish gracefully - // all the others can be interrupted - if (animationState != AnimationState::Start) { - animationState = AnimationState::None; - } - verticalAnimationState = VerticalAnimationState::None; - // find the fastest rotation path from frontDesktop to desktop - int rightRotations = frontDesktop - desktop; - if (rightRotations < 0) { - rightRotations += effects->numberOfDesktops(); - } - int leftRotations = desktop - frontDesktop; - if (leftRotations < 0) { - leftRotations += effects->numberOfDesktops(); - } - if (leftRotations <= rightRotations) { - for (int i = 0; i < leftRotations; i++) { - animations.enqueue(AnimationState::Left); - } - } else { - for (int i = 0; i < rightRotations; i++) { - animations.enqueue(AnimationState::Right); - } - } - // we want the face of desktop to appear, it might need also vertical animation - if (verticalCurrentAngle > 0.0f) { - verticalAnimations.enqueue(VerticalAnimationState::Downwards); - } - if (verticalCurrentAngle < 0.0f) { - verticalAnimations.enqueue(VerticalAnimationState::Upwards); - } - /* Start immediately, so there is no pause: - * during that pause, actual frontDesktop might change - * if user moves his mouse fast, leading to incorrect desktop */ - if (animationState == AnimationState::None && !animations.empty()) { - startAnimation(animations.dequeue()); - } - if (verticalAnimationState == VerticalAnimationState::None && !verticalAnimations.empty()) { - startVerticalAnimation(verticalAnimations.dequeue()); - } -} - -void CubeEffect::setActive(bool active) -{ - Q_FOREACH (CubeInsideEffect * inside, m_cubeInsideEffects) { - inside->setActive(true); - } - if (active) { - QString capPath = CubeConfig::capPath(); - if (texturedCaps && !capTexture && !capPath.isEmpty()) { - QFutureWatcher *watcher = new QFutureWatcher(this); - connect(watcher, &QFutureWatcher::finished, this, &CubeEffect::slotCubeCapLoaded); - watcher->setFuture(QtConcurrent::run(this, &CubeEffect::loadCubeCap, capPath)); - } - QString wallpaperPath = CubeConfig::wallpaper().toLocalFile(); - if (!wallpaper && !wallpaperPath.isEmpty()) { - QFutureWatcher *watcher = new QFutureWatcher(this); - connect(watcher, &QFutureWatcher::finished, this, &CubeEffect::slotWallPaperLoaded); - watcher->setFuture(QtConcurrent::run(this, &CubeEffect::loadWallPaper, wallpaperPath)); - } - activated = true; - activeScreen = effects->activeScreen(); - keyboard_grab = effects->grabKeyboard(this); - effects->startMouseInterception(this, Qt::OpenHandCursor); - frontDesktop = effects->currentDesktop(); - zoom = 0.0; - zOrderingFactor = zPosition / (effects->stackingOrder().count() - 1); - animations.enqueue(AnimationState::Start); - animationState = AnimationState::None; - verticalAnimationState = VerticalAnimationState::None; - effects->setActiveFullScreenEffect(this); - qCDebug(KWINEFFECTS) << "Cube is activated"; - currentAngle = 0.0; - verticalCurrentAngle = 0.0; - if (reflection) { - QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop()); - float temporaryCoeff = float(rect.width()) / tan(M_PI / float(effects->numberOfDesktops())); - mAddedHeightCoeff1 = sqrt(float(rect.height()) * float(rect.height()) + temporaryCoeff * temporaryCoeff); - mAddedHeightCoeff2 = sqrt(float(rect.height()) * float(rect.height()) + float(rect.width()) * float(rect.width()) + temporaryCoeff * temporaryCoeff); - } - m_rotationMatrix.setToIdentity(); - } else { - animations.enqueue(AnimationState::Stop); - } - effects->addRepaintFull(); -} - -void CubeEffect::windowInputMouseEvent(QEvent* e) -{ - if (!activated) - return; - if (tabBoxMode) - return; - if ((!animations.isEmpty() && animations.last() == AnimationState::Stop) || animationState == AnimationState::Stop) - return; - - QMouseEvent *mouse = dynamic_cast< QMouseEvent* >(e); - if (!mouse) - return; - - static QPoint oldpos; - static QElapsedTimer dblClckTime; - static int dblClckCounter(0); - if (mouse->type() == QEvent::MouseMove && mouse->buttons().testFlag(Qt::LeftButton)) { - const QPoint pos = mouse->pos(); - QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop()); - bool repaint = false; - // vertical movement only if there is not a rotation - if (verticalAnimationState == VerticalAnimationState::None) { - // display height corresponds to 180* - int deltaY = pos.y() - oldpos.y(); - float deltaVerticalDegrees = (float)deltaY / rect.height() * 180.0f; - if (invertMouse) - verticalCurrentAngle += deltaVerticalDegrees; - else - verticalCurrentAngle -= deltaVerticalDegrees; - // don't get too excited - verticalCurrentAngle = qBound(-90.0f, verticalCurrentAngle, 90.0f); - - if (deltaVerticalDegrees != 0.0) - repaint = true; - } - // horizontal movement only if there is not a rotation - if (animationState == AnimationState::None) { - // display width corresponds to sum of angles of the polyhedron - int deltaX = oldpos.x() - pos.x(); - float deltaDegrees = (float)deltaX / rect.width() * 360.0f; - if (deltaX == 0) { - if (pos.x() == 0) - deltaDegrees = 5.0f; - if (pos.x() == rect.width() - 1) - deltaDegrees = -5.0f; - } - if (invertMouse) - currentAngle += deltaDegrees; - else - currentAngle -= deltaDegrees; - if (deltaDegrees != 0.0) - repaint = true; - } - if (repaint) { - rotateCube(); - effects->addRepaintFull(); - } - oldpos = pos; - } - - else if (mouse->type() == QEvent::MouseButtonPress && mouse->button() == Qt::LeftButton) { - oldpos = mouse->pos(); - if (dblClckTime.elapsed() > QApplication::doubleClickInterval()) - dblClckCounter = 0; - if (!dblClckCounter) - dblClckTime.start(); - } - - else if (mouse->type() == QEvent::MouseButtonRelease) { - effects->defineCursor(Qt::OpenHandCursor); - if (mouse->button() == Qt::LeftButton && ++dblClckCounter == 2) { - dblClckCounter = 0; - if (dblClckTime.elapsed() < QApplication::doubleClickInterval()) { - setActive(false); - return; - } - } - else if (mouse->button() == Qt::XButton1) { - if (animations.count() < effects->numberOfDesktops()) { - if (invertMouse) - animations.enqueue(AnimationState::Right); - else - animations.enqueue(AnimationState::Left); - } - effects->addRepaintFull(); - } else if (mouse->button() == Qt::XButton2) { - if (animations.count() < effects->numberOfDesktops()) { - if (invertMouse) - animations.enqueue(AnimationState::Left); - else - animations.enqueue(AnimationState::Right); - } - effects->addRepaintFull(); - } else if (mouse->button() == Qt::RightButton || (mouse->button() == Qt::LeftButton && closeOnMouseRelease)) { - setActive(false); - } - } -} - -void CubeEffect::slotTabBoxAdded(int mode) -{ - if (activated) - return; - if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this) - return; - if (useForTabBox && mode == TabBoxDesktopListMode) { - effects->refTabBox(); - tabBoxMode = true; - setActive(true); - rotateToDesktop(effects->currentTabBoxDesktop()); - } -} - -void CubeEffect::slotTabBoxUpdated() -{ - if (activated) { - rotateToDesktop(effects->currentTabBoxDesktop()); - effects->addRepaintFull(); - } -} - -void CubeEffect::slotTabBoxClosed() -{ - if (activated) { - effects->unrefTabBox(); - tabBoxMode = false; - setActive(false); - } -} - -void CubeEffect::globalShortcutChanged(QAction *action, const QKeySequence &seq) -{ - if (action->objectName() == QStringLiteral("Cube")) { - cubeShortcut.clear(); - cubeShortcut.append(seq); - } else if (action->objectName() == QStringLiteral("Cylinder")) { - cylinderShortcut.clear(); - cylinderShortcut.append(seq); - } else if (action->objectName() == QStringLiteral("Sphere")) { - sphereShortcut.clear(); - sphereShortcut.append(seq); - } -} - -void* CubeEffect::proxy() -{ - return &m_proxy; -} - -void CubeEffect::registerCubeInsideEffect(CubeInsideEffect* effect) -{ - m_cubeInsideEffects.append(effect); -} - -void CubeEffect::unregisterCubeInsideEffect(CubeInsideEffect* effect) -{ - m_cubeInsideEffects.removeAll(effect); -} - -bool CubeEffect::isActive() const -{ - return activated && !effects->isScreenLocked(); -} - -} // namespace diff --git a/src/effects/cube/cube.h b/src/effects/cube/cube.h deleted file mode 100644 index 5388bc3d3b..0000000000 --- a/src/effects/cube/cube.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2008 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef KWIN_CUBE_H -#define KWIN_CUBE_H - -#include -#include -#include -#include -#include -#include -#include "cube_inside.h" -#include "cube_proxy.h" - -namespace KWin -{ - -class CubeEffect - : public Effect -{ - Q_OBJECT - Q_PROPERTY(qreal cubeOpacity READ configuredCubeOpacity) - Q_PROPERTY(bool opacityDesktopOnly READ isOpacityDesktopOnly) - Q_PROPERTY(bool displayDesktopName READ isDisplayDesktopName) - Q_PROPERTY(bool reflection READ isReflection) - Q_PROPERTY(int rotationDuration READ configuredRotationDuration) - Q_PROPERTY(QColor backgroundColor READ configuredBackgroundColor) - Q_PROPERTY(QColor capColor READ configuredCapColor) - Q_PROPERTY(bool paintCaps READ isPaintCaps) - Q_PROPERTY(bool closeOnMouseRelease READ isCloseOnMouseRelease) - Q_PROPERTY(qreal zPosition READ configuredZPosition) - Q_PROPERTY(bool useForTabBox READ isUseForTabBox) - Q_PROPERTY(bool invertKeys READ isInvertKeys) - Q_PROPERTY(bool invertMouse READ isInvertMouse) - Q_PROPERTY(qreal capDeformationFactor READ configuredCapDeformationFactor) - Q_PROPERTY(bool useZOrdering READ isUseZOrdering) - Q_PROPERTY(bool texturedCaps READ isTexturedCaps) - // TODO: electric borders: not a registered type -public: - CubeEffect(); - ~CubeEffect() override; - void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; - void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) override; - void postPaintScreen() override; - void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) override; - void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override; - bool borderActivated(ElectricBorder border) override; - void grabbedKeyboardEvent(QKeyEvent* e) override; - void windowInputMouseEvent(QEvent* e) override; - bool isActive() const override; - - int requestedEffectChainPosition() const override { - return 50; - } - - // proxy functions - void* proxy() override; - void registerCubeInsideEffect(CubeInsideEffect* effect); - void unregisterCubeInsideEffect(CubeInsideEffect* effect); - - static bool supported(); - - // for properties - qreal configuredCubeOpacity() const { - return cubeOpacity; - } - bool isOpacityDesktopOnly() const { - return opacityDesktopOnly; - } - bool isDisplayDesktopName() const { - return displayDesktopName; - } - bool isReflection() const { - return reflection; - } - int configuredRotationDuration() const { - return rotationDuration.count(); - } - QColor configuredBackgroundColor() const { - return backgroundColor; - } - QColor configuredCapColor() const { - return capColor; - } - bool isPaintCaps() const { - return paintCaps; - } - bool isCloseOnMouseRelease() const { - return closeOnMouseRelease; - } - qreal configuredZPosition() const { - return zPosition; - } - bool isUseForTabBox() const { - return useForTabBox; - } - bool isInvertKeys() const { - return invertKeys; - } - bool isInvertMouse() const { - return invertMouse; - } - qreal configuredCapDeformationFactor() const { - return capDeformationFactor; - } - bool isUseZOrdering() const { - return useZOrdering; - } - bool isTexturedCaps() const { - return texturedCaps; - } -private Q_SLOTS: - void toggleCube(); - void toggleCylinder(); - void toggleSphere(); - // slots for global shortcut changed - // needed to toggle the effect - void globalShortcutChanged(QAction *action, const QKeySequence &seq); - void slotTabBoxAdded(int mode); - void slotTabBoxUpdated(); - void slotTabBoxClosed(); - void slotCubeCapLoaded(); - void slotWallPaperLoaded(); -private: - enum class AnimationState { - None, - Start, - Stop, - Left, - Right - }; - enum class VerticalAnimationState { - None, - Upwards, - Downwards - }; - enum CubeMode { - Cube, - Cylinder, - Sphere - }; - void toggle(CubeMode newMode = Cube); - void paintCube(int mask, QRegion region, ScreenPaintData& data); - void paintCap(bool frontFirst, float zOffset, const QMatrix4x4 &projection); - void paintCubeCap(); - void paintCylinderCap(); - void paintSphereCap(); - bool loadShader(); - void rotateCube(); - void rotateToDesktop(int desktop); - void setActive(bool active); - QImage loadCubeCap(const QString &capPath); - QImage loadWallPaper(const QString &file); - void startAnimation(AnimationState state); - void startVerticalAnimation(VerticalAnimationState state); - - bool activated; - bool cube_painting; - bool keyboard_grab; - bool schedule_close; - QList borderActivate; - QList borderActivateCylinder; - QList borderActivateSphere; - int painting_desktop; - int frontDesktop; - float cubeOpacity; - bool opacityDesktopOnly; - bool displayDesktopName; - EffectFrame* desktopNameFrame; - QFont desktopNameFont; - bool reflection; - bool rotating; - bool verticalRotating; - bool desktopChangedWhileRotating; - bool paintCaps; - QColor backgroundColor; - QColor capColor; - GLTexture* wallpaper; - bool texturedCaps; - GLTexture* capTexture; - // animations - // Horizontal/start/stop - float startAngle; - float currentAngle; - int startFrontDesktop; - AnimationState animationState; - TimeLine timeLine; - QQueue animations; - // vertical - float verticalStartAngle; - float verticalCurrentAngle; - VerticalAnimationState verticalAnimationState; - TimeLine verticalTimeLine; - QQueue verticalAnimations; - std::chrono::milliseconds lastPresentTime; - - bool reflectionPainting; - std::chrono::milliseconds rotationDuration; - int activeScreen; - bool bottomCap; - bool closeOnMouseRelease; - float zoom; - float zPosition; - bool useForTabBox; - bool invertKeys; - bool invertMouse; - bool tabBoxMode; - bool shortcutsRegistered; - CubeMode mode; - bool useShaders; - GLShader* cylinderShader; - GLShader* sphereShader; - GLShader* m_reflectionShader; - GLShader* m_capShader; - float capDeformationFactor; - bool useZOrdering; - float zOrderingFactor; - bool useList; - // needed for reflection - float mAddedHeightCoeff1; - float mAddedHeightCoeff2; - - QMatrix4x4 m_rotationMatrix; - QMatrix4x4 m_reflectionMatrix; - QMatrix4x4 m_textureMirrorMatrix; - QMatrix4x4 m_currentFaceMatrix; - GLVertexBuffer *m_cubeCapBuffer; - - // Shortcuts - needed to toggle the effect - QList cubeShortcut; - QList cylinderShortcut; - QList sphereShortcut; - - // proxy - CubeEffectProxy m_proxy; - QList< CubeInsideEffect* > m_cubeInsideEffects; - - QAction *m_cubeAction; - QAction *m_cylinderAction; - QAction *m_sphereAction; -}; - -} // namespace - -#endif diff --git a/src/effects/cube/cube.kcfg b/src/effects/cube/cube.kcfg deleted file mode 100644 index ee9c5ec05a..0000000000 --- a/src/effects/cube/cube.kcfg +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - 0 - - - 80 - - - false - - - true - - - true - - - QColor(Qt::black) - - - QColor(KColorScheme(QPalette::Active, KColorScheme::Window).background().color()) - - - QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("cubecap.png")) - - - true - - - true - - - false - - - false - - - 100 - - - - 0 - - - false - - - false - - - false - - - diff --git a/src/effects/cube/cube_config.cpp b/src/effects/cube/cube_config.cpp deleted file mode 100644 index 62ad11b7bc..0000000000 --- a/src/effects/cube/cube_config.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2008 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "cube_config.h" -// KConfigSkeleton -#include "cubeconfig.h" -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -K_PLUGIN_FACTORY_WITH_JSON(CubeEffectConfigFactory, - "cube_config.json", - registerPlugin();) - -namespace KWin -{ - -CubeEffectConfigForm::CubeEffectConfigForm(QWidget* parent) : QWidget(parent) -{ - setupUi(this); -} - -CubeEffectConfig::CubeEffectConfig(QWidget* parent, const QVariantList& args) : - KCModule(parent, args) -{ - m_ui = new CubeEffectConfigForm(this); - - QVBoxLayout* layout = new QVBoxLayout(this); - - layout->addWidget(m_ui); - - m_ui->tabWidget->setTabText(0, i18nc("@title:tab Basic Settings", "Basic")); - m_ui->tabWidget->setTabText(1, i18nc("@title:tab Advanced Settings", "Advanced")); - - // Shortcut config. The shortcut belongs to the component "kwin"! - m_actionCollection = new KActionCollection(this, QStringLiteral("kwin")); - m_actionCollection->setComponentDisplayName(i18n("KWin")); - - m_actionCollection->setConfigGroup(QStringLiteral("Cube")); - m_actionCollection->setConfigGlobal(true); - - QAction* cubeAction = m_actionCollection->addAction(QStringLiteral("Cube")); - cubeAction->setText(i18n("Desktop Cube")); - cubeAction->setProperty("isConfigurationAction", true); - KGlobalAccel::self()->setDefaultShortcut(cubeAction, QList() << Qt::CTRL + Qt::Key_F11); - KGlobalAccel::self()->setShortcut(cubeAction, QList() << Qt::CTRL + Qt::Key_F11); - QAction* cylinderAction = m_actionCollection->addAction(QStringLiteral("Cylinder")); - cylinderAction->setText(i18n("Desktop Cylinder")); - cylinderAction->setProperty("isConfigurationAction", true); - KGlobalAccel::self()->setShortcut(cylinderAction, QList()); - QAction* sphereAction = m_actionCollection->addAction(QStringLiteral("Sphere")); - sphereAction->setText(i18n("Desktop Sphere")); - sphereAction->setProperty("isConfigurationAction", true); - KGlobalAccel::self()->setShortcut(sphereAction, QList()); - - m_ui->editor->addCollection(m_actionCollection); - - capsSelectionChanged(); - connect(m_ui->kcfg_Caps, &QCheckBox::stateChanged, this, &CubeEffectConfig::capsSelectionChanged); - m_ui->kcfg_Wallpaper->setFilter(QStringLiteral("*.png *.jpeg *.jpg ")); - CubeConfig::instance(KWIN_CONFIG); - addConfig(CubeConfig::self(), m_ui); - load(); -} - -void CubeEffectConfig::save() -{ - KCModule::save(); - m_ui->editor->save(); - OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), - QStringLiteral("/Effects"), - QDBusConnection::sessionBus()); - interface.reconfigureEffect(QStringLiteral("cube")); -} - -void CubeEffectConfig::capsSelectionChanged() -{ - if (m_ui->kcfg_Caps->checkState() == Qt::Checked) { - // activate cap color - m_ui->kcfg_CapColor->setEnabled(true); - m_ui->capColorLabel->setEnabled(true); - m_ui->kcfg_TexturedCaps->setEnabled(true); - } else { - // deactivate cap color - m_ui->kcfg_CapColor->setEnabled(false); - m_ui->capColorLabel->setEnabled(false); - m_ui->kcfg_TexturedCaps->setEnabled(false); - } -} - -} // namespace - -#include "cube_config.moc" diff --git a/src/effects/cube/cube_config.desktop b/src/effects/cube/cube_config.desktop deleted file mode 100644 index 09e6d5453e..0000000000 --- a/src/effects/cube/cube_config.desktop +++ /dev/null @@ -1,83 +0,0 @@ -[Desktop Entry] -Type=Service -X-KDE-ServiceTypes=KCModule - -X-KDE-Library=kwin_cube_config -X-KDE-ParentComponents=cube - -Name=Desktop Cube -Name[ar]=سطح مكتب مكعّب -Name[az]=İş Masası kubu -Name[be@latin]=Rabočy kub -Name[bg]=Кубичен работен плот -Name[bn]=ডেস্কটপ কিউব -Name[bs]=Kocka površi -Name[ca]=Cub de l'escriptori -Name[ca@valencia]=Cub d'escriptori -Name[cs]=Plochy na kostce -Name[csb]=Szescan pùltu -Name[da]=Skrivebordsterning -Name[de]=Arbeitsflächen-Würfel -Name[el]=Κύβος επιφάνειας εργασίας -Name[en_GB]=Desktop Cube -Name[eo]=Labortabla Kubo -Name[es]=Cubo de escritorio -Name[et]=Töölauakuubik -Name[eu]=Mahaigain kuboa -Name[fi]=Työpöytäkuutio -Name[fr]=Bureau en cube -Name[fy]=Buroblêdkubus -Name[ga]=Ciúb Deisce -Name[gl]=Cubo do escritorio -Name[gu]=ડેસ્કટોપ ટ્યુબ -Name[he]=שולחן עבודה בקובייה -Name[hi]=डेस्कटॉप घन -Name[hne]=डेस्कटाप घन -Name[hr]=Radna površina na kocki -Name[hsb]=Kóstka -Name[hu]=Asztalkocka -Name[ia]=Cubo de scriptorio -Name[id]=Kubus Desktop -Name[is]=Skjáborðskubbur -Name[it]=Cubo dei desktop -Name[ja]=デスクトップキューブ -Name[kk]=Үстел текшесі -Name[km]=គូប​ផ្ទៃតុ​ -Name[kn]=ಗಣಕತೆರೆ ಘನಾಕೃತಿ -Name[ko]=데스크톱 큐브 -Name[ku]=Sermaseya Mîkap -Name[lt]=Darbalaukio kubas -Name[lv]=Darbvirsmas kubs -Name[mai]=डेस्कटाप घन -Name[mk]=Работна коцка -Name[ml]=പണിയിടം ക്യൂബ് -Name[mr]=डेस्कटॉप क्यूब -Name[nb]=Skrivebordsterning -Name[nds]=Wörpel-Schriefdisch -Name[nl]=Bureaubladkubus -Name[nn]=Skrivebordskube -Name[pa]=ਡੈਸਕਟਾਪ ਘਣ -Name[pl]=Sześcian pulpitu -Name[pt]=Cubo de Ecrãs -Name[pt_BR]=Cubo de áreas de trabalho -Name[ro]=Cub de birou -Name[ru]=Куб рабочих столов -Name[si]=වැඩතල ඝනකය -Name[sk]=Plochy na kocke -Name[sl]=Kocka z namizji -Name[sr]=Коцка површи -Name[sr@ijekavian]=Коцка површи -Name[sr@ijekavianlatin]=Kocka površi -Name[sr@latin]=Kocka površi -Name[sv]=Skrivbordskub -Name[ta]=பணிமேசை க்யூப் -Name[te]=‍డెస్‍క్ టాప్ క్యూబ్ -Name[th]=พื้นที่ทำงานทรงลูกบาศก์ -Name[tr]=Masaüstü Küpü -Name[ug]=ئۈستەلئۈستى كۈپى -Name[uk]=Куб стільниць -Name[vi]=Khối vuông màn hình -Name[wa]=Cube di scribannes -Name[x-test]=xxDesktop Cubexx -Name[zh_CN]=3D 虚拟桌面切换 -Name[zh_TW]=桌面立方體 diff --git a/src/effects/cube/cube_config.h b/src/effects/cube/cube_config.h deleted file mode 100644 index 5bc13f69a2..0000000000 --- a/src/effects/cube/cube_config.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2008 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef KWIN_CUBE_CONFIG_H -#define KWIN_CUBE_CONFIG_H - -#include - -#include "ui_cube_config.h" - - -namespace KWin -{ - -class CubeEffectConfigForm : public QWidget, public Ui::CubeEffectConfigForm -{ - Q_OBJECT -public: - explicit CubeEffectConfigForm(QWidget* parent); -}; - -class CubeEffectConfig : public KCModule -{ - Q_OBJECT -public: - explicit CubeEffectConfig(QWidget* parent = nullptr, const QVariantList& args = QVariantList()); - -public Q_SLOTS: - void save() override; - -private Q_SLOTS: - void capsSelectionChanged(); -private: - CubeEffectConfigForm* m_ui; - KActionCollection* m_actionCollection; -}; - -} // namespace - -#endif diff --git a/src/effects/cube/cube_config.ui b/src/effects/cube/cube_config.ui deleted file mode 100644 index ec79f1c59d..0000000000 --- a/src/effects/cube/cube_config.ui +++ /dev/null @@ -1,569 +0,0 @@ - - - KWin::CubeEffectConfigForm - - - - 0 - 0 - 747 - 566 - - - - - - - 0 - - - - Tab 1 - - - - - - Background - - - - - - Background color: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - kcfg_BackgroundColor - - - - - - - - 0 - 0 - - - - - - - - Wallpaper: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - kcfg_Wallpaper - - - - - - - - 0 - 0 - - - - - - - - - - - Activation - - - - - - - 0 - 200 - - - - KShortcutsEditor::GlobalAction - - - - - - - - - - Appearance - - - - - - Display desktop name - - - - - - - Reflection - - - - - - - Rotation duration: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - kcfg_RotationDuration - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - Default - - - 5000 - - - 10 - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - Windows hover above cube - - - - - - - - - - Opacity - - - - - - - 200 - 0 - - - - 100 - - - 1 - - - 100 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - 10 - - - - - - - - 75 - 0 - - - - % - - - 100 - - - 100 - - - - - - - Transparent - - - - - - - Opaque - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Do not change opacity of windows - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - Tab 2 - - - - - - Caps - - - - - - Show caps - - - - - - - Cap color: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - kcfg_CapColor - - - - - - - - 0 - 0 - - - - - - - - Display image on caps - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - Zoom - - - - - - Near - - - - - - - Far - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Define how far away the object should appear - - - 3000 - - - 10 - - - 100 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - 100 - - - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - Additional Options - - - - - - If enabled the effect will be deactivated after rotating the cube with the mouse, -otherwise it will remain active - - - Close after mouse dragging - - - - - - - Use this effect for walking through the desktops - - - - - - - Invert cursor keys - - - - - - - Invert mouse - - - - - - - - - - Sphere Cap Deformation - - - - - - 100 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - 25 - - - - - - - Sphere - - - - - - - Plane - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - - - - KColorButton - QPushButton -
kcolorbutton.h
-
- - KUrlRequester - QFrame -
kurlrequester.h
- 1 -
- - KShortcutsEditor - QWidget -
KShortcutsEditor
- 1 -
-
- - tabWidget - kcfg_DisplayDesktopName - kcfg_Reflection - kcfg_ZOrdering - kcfg_RotationDuration - kcfg_Opacity - kcfg_OpacitySpin - kcfg_OpacityDesktopOnly - kcfg_BackgroundColor - kcfg_Wallpaper - kcfg_Caps - kcfg_CapColor - kcfg_TexturedCaps - kcfg_CloseOnMouseRelease - kcfg_TabBox - kcfg_InvertKeys - kcfg_InvertMouse - kcfg_ZPosition - kcfg_CapDeformation - - - - - kcfg_OpacitySpin - valueChanged(int) - kcfg_Opacity - setValue(int) - - - 727 - 85 - - - 611 - 88 - - - - - kcfg_Opacity - valueChanged(int) - kcfg_OpacitySpin - setValue(int) - - - 611 - 88 - - - 727 - 85 - - - - -
diff --git a/src/effects/cube/cube_inside.h b/src/effects/cube/cube_inside.h deleted file mode 100644 index fe96ab7183..0000000000 --- a/src/effects/cube/cube_inside.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2009 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef KWIN_CUBE_INSIDE_H -#define KWIN_CUBE_INSIDE_H -#include - -namespace KWin -{ - -class CubeInsideEffect : public Effect -{ -public: - CubeInsideEffect() {} - ~CubeInsideEffect() override {} - - virtual void paint() = 0; - virtual void setActive(bool active) = 0; -}; - -} // namespace - -#endif // KWIN_CUBE_INSIDE_H diff --git a/src/effects/cube/cube_proxy.cpp b/src/effects/cube/cube_proxy.cpp deleted file mode 100644 index d9221b3125..0000000000 --- a/src/effects/cube/cube_proxy.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2009 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include "cube_proxy.h" -#include "cube.h" -#include "cube_inside.h" - -namespace KWin -{ - -CubeEffectProxy::CubeEffectProxy(CubeEffect* effect) - : m_effect(effect) -{ -} - -CubeEffectProxy::~CubeEffectProxy() -{ -} - -void CubeEffectProxy::registerCubeInsideEffect(CubeInsideEffect* effect) -{ - m_effect->registerCubeInsideEffect(effect); -} - -void CubeEffectProxy::unregisterCubeInsideEffect(CubeInsideEffect* effect) -{ - m_effect->unregisterCubeInsideEffect(effect); -} - -} // namespace diff --git a/src/effects/cube/cube_proxy.h b/src/effects/cube/cube_proxy.h deleted file mode 100644 index 8084701502..0000000000 --- a/src/effects/cube/cube_proxy.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2009 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef KWIN_CUBE_PROXY_H -#define KWIN_CUBE_PROXY_H - -namespace KWin -{ - -class CubeEffect; -class CubeInsideEffect; - -class CubeEffectProxy -{ -public: - explicit CubeEffectProxy(CubeEffect* effect); - ~CubeEffectProxy(); - - void registerCubeInsideEffect(CubeInsideEffect* effect); - void unregisterCubeInsideEffect(CubeInsideEffect* effect); - -private: - CubeEffect* m_effect; -}; - -} // namespace - -#endif // KWIN_CUBE_PROXY_H diff --git a/src/effects/cube/cubeconfig.kcfgc b/src/effects/cube/cubeconfig.kcfgc deleted file mode 100644 index 4ee0f80307..0000000000 --- a/src/effects/cube/cubeconfig.kcfgc +++ /dev/null @@ -1,6 +0,0 @@ -File=cube.kcfg -ClassName=CubeConfig -NameSpace=KWin -Singleton=true -Mutators=true -IncludeFiles=kcolorscheme.h diff --git a/src/effects/cube/data/1.10/cube-cap.glsl b/src/effects/cube/data/1.10/cube-cap.glsl deleted file mode 100644 index 818905460d..0000000000 --- a/src/effects/cube/data/1.10/cube-cap.glsl +++ /dev/null @@ -1,29 +0,0 @@ -uniform sampler2D sampler; -uniform vec4 geometryColor; -uniform float u_opacity; -uniform int u_mirror; -uniform int u_untextured; - -varying vec2 texcoord0; - -vec2 mirrorTex(vec2 coords) { - vec2 mirrored = coords; - if (u_mirror != 0) { - mirrored.t = mirrored.t * (-1.0) + 1.0; - } - return mirrored; -} - -void main() { - vec4 color = geometryColor; - vec2 texCoord = mirrorTex(texcoord0); - vec4 tex = texture2D(sampler, texCoord); - if (texCoord.s < 0.0 || texCoord.s > 1.0 || - texCoord.t < 0.0 || texCoord.t > 1.0 || u_untextured != 0) { - tex = geometryColor; - } - color.rgb = tex.rgb*tex.a + color.rgb*(1.0-tex.a); - color.a = u_opacity; - - gl_FragColor = color; -} diff --git a/src/effects/cube/data/1.10/cube-reflection.glsl b/src/effects/cube/data/1.10/cube-reflection.glsl deleted file mode 100644 index d9335a2ce9..0000000000 --- a/src/effects/cube/data/1.10/cube-reflection.glsl +++ /dev/null @@ -1,8 +0,0 @@ -uniform float u_alpha; - -varying vec2 texcoord0; - -void main() -{ - gl_FragColor = vec4(0.0, 0.0, 0.0, u_alpha*texcoord0.s); -} diff --git a/src/effects/cube/data/1.10/cylinder.vert b/src/effects/cube/data/1.10/cylinder.vert deleted file mode 100644 index eeb250da86..0000000000 --- a/src/effects/cube/data/1.10/cylinder.vert +++ /dev/null @@ -1,35 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2008, 2011 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -uniform mat4 modelViewProjectionMatrix; -uniform float width; -uniform float cubeAngle; -uniform float xCoord; -uniform float timeLine; - -attribute vec4 position; -attribute vec4 texcoord; - -varying vec2 texcoord0; - -void main() -{ - texcoord0 = texcoord.st; - vec4 transformedVertex = vec4(position.x - ( width - xCoord ), position.yzw); - float radian = radians(cubeAngle); - float radius = (width)*tan(radian); - float azimuthAngle = radians(transformedVertex.x/(width)*(90.0 - cubeAngle)); - - transformedVertex.x = width - xCoord + radius * sin( azimuthAngle ); - transformedVertex.z = position.z + radius * cos( azimuthAngle ) - radius; - - vec3 diff = (position.xyz - transformedVertex.xyz)*timeLine; - transformedVertex.xyz += diff; - - gl_Position = modelViewProjectionMatrix*transformedVertex; -} diff --git a/src/effects/cube/data/1.10/sphere.vert b/src/effects/cube/data/1.10/sphere.vert deleted file mode 100644 index 844044423e..0000000000 --- a/src/effects/cube/data/1.10/sphere.vert +++ /dev/null @@ -1,41 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2008, 2011 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -uniform mat4 modelViewProjectionMatrix; -uniform float width; -uniform float height; -uniform float cubeAngle; -uniform vec2 u_offset; -uniform float timeLine; - -attribute vec4 position; -attribute vec4 texcoord; - -varying vec2 texcoord0; - -void main() -{ - texcoord0 = texcoord.st; - vec4 transformedVertex = position; - transformedVertex.x = transformedVertex.x - width; - transformedVertex.y = transformedVertex.y - height; - transformedVertex.xy = transformedVertex.xy + u_offset; - float radian = radians(cubeAngle); - float radius = (width)/cos(radian); - float zenithAngle = acos(transformedVertex.y/radius); - float azimuthAngle = asin(transformedVertex.x/radius); - transformedVertex.z = radius * sin( zenithAngle ) * cos( azimuthAngle ) - radius*cos( radians( 90.0 - cubeAngle ) ); - transformedVertex.x = radius * sin( zenithAngle ) * sin( azimuthAngle ); - - transformedVertex.xy += vec2( width - u_offset.x, height - u_offset.y ); - - vec3 diff = (position.xyz - transformedVertex.xyz)*timeLine; - transformedVertex.xyz += diff; - - gl_Position = modelViewProjectionMatrix*transformedVertex; -} diff --git a/src/effects/cube/data/1.40/cube-cap.glsl b/src/effects/cube/data/1.40/cube-cap.glsl deleted file mode 100644 index 20a830626e..0000000000 --- a/src/effects/cube/data/1.40/cube-cap.glsl +++ /dev/null @@ -1,32 +0,0 @@ -#version 140 -uniform sampler2D sampler; -uniform vec4 geometryColor; -uniform float u_opacity; -uniform int u_mirror; -uniform int u_untextured; - -in vec2 texcoord0; - -out vec4 fragColor; - -vec2 mirrorTex(vec2 coords) { - vec2 mirrored = coords; - if (u_mirror != 0) { - mirrored.t = mirrored.t * (-1.0) + 1.0; - } - return mirrored; -} - -void main() { - vec4 color = geometryColor; - vec2 texCoord = mirrorTex(texcoord0); - vec4 tex = texture(sampler, texCoord); - if (texCoord.s < 0.0 || texCoord.s > 1.0 || - texCoord.t < 0.0 || texCoord.t > 1.0 || u_untextured != 0) { - tex = geometryColor; - } - color.rgb = tex.rgb*tex.a + color.rgb*(1.0-tex.a); - color.a = u_opacity; - - fragColor = color; -} diff --git a/src/effects/cube/data/1.40/cube-reflection.glsl b/src/effects/cube/data/1.40/cube-reflection.glsl deleted file mode 100644 index b70e98d923..0000000000 --- a/src/effects/cube/data/1.40/cube-reflection.glsl +++ /dev/null @@ -1,11 +0,0 @@ -#version 140 -uniform float u_alpha; - -in vec2 texcoord0; - -out vec4 fragColor; - -void main() -{ - fragColor = vec4(0.0, 0.0, 0.0, u_alpha*texcoord0.s); -} diff --git a/src/effects/cube/data/1.40/cylinder.vert b/src/effects/cube/data/1.40/cylinder.vert deleted file mode 100644 index d30472ffbe..0000000000 --- a/src/effects/cube/data/1.40/cylinder.vert +++ /dev/null @@ -1,36 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2008, 2011 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#version 140 -uniform mat4 modelViewProjectionMatrix; -uniform float width; -uniform float cubeAngle; -uniform float xCoord; -uniform float timeLine; - -in vec4 position; -in vec4 texcoord; - -out vec2 texcoord0; - -void main() -{ - texcoord0 = texcoord.st; - vec4 transformedVertex = vec4(position.x - ( width - xCoord ), position.yzw); - float radian = radians(cubeAngle); - float radius = (width)*tan(radian); - float azimuthAngle = radians(transformedVertex.x/(width)*(90.0 - cubeAngle)); - - transformedVertex.x = width - xCoord + radius * sin( azimuthAngle ); - transformedVertex.z = position.z + radius * cos( azimuthAngle ) - radius; - - vec3 diff = (position.xyz - transformedVertex.xyz)*timeLine; - transformedVertex.xyz += diff; - - gl_Position = modelViewProjectionMatrix*transformedVertex; -} diff --git a/src/effects/cube/data/1.40/sphere.vert b/src/effects/cube/data/1.40/sphere.vert deleted file mode 100644 index 82648a2cdd..0000000000 --- a/src/effects/cube/data/1.40/sphere.vert +++ /dev/null @@ -1,42 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2008, 2011 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#version 140 -uniform mat4 modelViewProjectionMatrix; -uniform float width; -uniform float height; -uniform float cubeAngle; -uniform vec2 u_offset; -uniform float timeLine; - -in vec4 position; -in vec4 texcoord; - -out vec2 texcoord0; - -void main() -{ - texcoord0 = texcoord.st; - vec4 transformedVertex = position; - transformedVertex.x = transformedVertex.x - width; - transformedVertex.y = transformedVertex.y - height; - transformedVertex.xy = transformedVertex.xy + u_offset; - float radian = radians(cubeAngle); - float radius = (width)/cos(radian); - float zenithAngle = acos(transformedVertex.y/radius); - float azimuthAngle = asin(transformedVertex.x/radius); - transformedVertex.z = radius * sin( zenithAngle ) * cos( azimuthAngle ) - radius*cos( radians( 90.0 - cubeAngle ) ); - transformedVertex.x = radius * sin( zenithAngle ) * sin( azimuthAngle ); - - transformedVertex.xy += vec2( width - u_offset.x, height - u_offset.y ); - - vec3 diff = (position.xyz - transformedVertex.xyz)*timeLine; - transformedVertex.xyz += diff; - - gl_Position = modelViewProjectionMatrix*transformedVertex; -} diff --git a/src/effects/cube/data/cubecap.png b/src/effects/cube/data/cubecap.png deleted file mode 100644 index 229fa04f2bc0f1cbff4cf4b1c38fd9446273d362..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48777 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, - &CubeEffect::supported, - nullptr, -#endif -EFFECT_FALLBACK - QStringLiteral("kwin_cube_config") }, { QStringLiteral("cubeslide"), i18ndc("kwin_effects", "Name of a KWin Effect", "Desktop Cube Animation"), diff --git a/src/effects/effect_builtins.h b/src/effects/effect_builtins.h index a9a2f270bb..00a6fca370 100644 --- a/src/effects/effect_builtins.h +++ b/src/effects/effect_builtins.h @@ -26,7 +26,6 @@ enum class BuiltInEffect Blur, ColorPicker, Contrast, - Cube, CubeSlide, DesktopGrid, DimInactive, diff --git a/src/effects/shaders.qrc b/src/effects/shaders.qrc index 6e1258a902..b93081caad 100644 --- a/src/effects/shaders.qrc +++ b/src/effects/shaders.qrc @@ -1,18 +1,10 @@ - cube/data/1.10/cube-cap.glsl - cube/data/1.10/cube-reflection.glsl - cube/data/1.10/cylinder.vert - cube/data/1.10/sphere.vert invert/data/1.10/invert.frag lookingglass/data/1.10/lookingglass.frag startupfeedback/data/1.10/blinking-startup-fragment.glsl - cube/data/1.40/cube-cap.glsl - cube/data/1.40/cube-reflection.glsl - cube/data/1.40/cylinder.vert - cube/data/1.40/sphere.vert invert/data/1.40/invert.frag lookingglass/data/1.40/lookingglass.frag startupfeedback/data/1.40/blinking-startup-fragment.glsl diff --git a/src/kcmkwin/kwinscreenedges/kwinscreenedgesettings.kcfg b/src/kcmkwin/kwinscreenedges/kwinscreenedgesettings.kcfg index 29368fc929..a88dfc0692 100644 --- a/src/kcmkwin/kwinscreenedges/kwinscreenedgesettings.kcfg +++ b/src/kcmkwin/kwinscreenedges/kwinscreenedgesettings.kcfg @@ -66,17 +66,6 @@ ElectricNone - - - ElectricNone - - - ElectricNone - - - ElectricNone - - ElectricLeft diff --git a/src/kcmkwin/kwinscreenedges/kwintouchscreensettings.kcfg b/src/kcmkwin/kwinscreenedges/kwintouchscreensettings.kcfg index feca5cb0cf..41528cddfb 100644 --- a/src/kcmkwin/kwinscreenedges/kwintouchscreensettings.kcfg +++ b/src/kcmkwin/kwinscreenedges/kwintouchscreensettings.kcfg @@ -34,17 +34,6 @@ ElectricNone - - - ElectricNone - - - ElectricNone - - - ElectricNone - - ElectricNone diff --git a/src/kcmkwin/kwinscreenedges/main.cpp b/src/kcmkwin/kwinscreenedges/main.cpp index a43123bdb1..7e76f9e0fb 100644 --- a/src/kcmkwin/kwinscreenedges/main.cpp +++ b/src/kcmkwin/kwinscreenedges/main.cpp @@ -92,7 +92,6 @@ void KWinScreenEdgesConfig::save() QDBusConnection::sessionBus()); interface.reconfigureEffect(BuiltInEffects::nameForEffect(BuiltInEffect::PresentWindows)); interface.reconfigureEffect(BuiltInEffects::nameForEffect(BuiltInEffect::DesktopGrid)); - interface.reconfigureEffect(BuiltInEffects::nameForEffect(BuiltInEffect::Cube)); KCModule::save(); } @@ -135,10 +134,6 @@ void KWinScreenEdgesConfig::monitorInit() m_form->monitorAddItem(i18n("%1 - Current Desktop", presentWindowsName)); m_form->monitorAddItem(i18n("%1 - Current Application", presentWindowsName)); m_form->monitorAddItem(BuiltInEffects::effectData(BuiltInEffect::DesktopGrid).displayName); - const QString cubeName = BuiltInEffects::effectData(BuiltInEffect::Cube).displayName; - m_form->monitorAddItem(i18n("%1 - Cube", cubeName)); - m_form->monitorAddItem(i18n("%1 - Cylinder", cubeName)); - m_form->monitorAddItem(i18n("%1 - Sphere", cubeName)); m_form->monitorAddItem(i18n("Toggle window switching")); m_form->monitorAddItem(i18n("Toggle alternative window switching")); @@ -189,11 +184,6 @@ void KWinScreenEdgesConfig::monitorLoadSettings() // Desktop Grid m_form->monitorChangeEdge(m_data->settings()->borderActivateDesktopGrid(), DesktopGrid); - // Desktop Cube - m_form->monitorChangeEdge(m_data->settings()->borderActivateCube(), Cube); - m_form->monitorChangeEdge(m_data->settings()->borderActivateCylinder(), Cylinder); - m_form->monitorChangeEdge(m_data->settings()->borderActivateSphere(), Sphere); - // TabBox m_form->monitorChangeEdge(m_data->settings()->borderActivateTabBox(), TabBox); // Alternative TabBox @@ -232,11 +222,6 @@ void KWinScreenEdgesConfig::monitorLoadDefaultSettings() // Desktop Grid m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateDesktopGridValue(), DesktopGrid); - // Desktop Cube - m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateCubeValue(), Cube); - m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateCylinderValue(), Cylinder); - m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateSphereValue(), Sphere); - // TabBox m_form->monitorChangeDefaultEdge(m_data->settings()->defaultBorderActivateTabBoxValue(), TabBox); // Alternative TabBox @@ -265,11 +250,6 @@ void KWinScreenEdgesConfig::monitorSaveSettings() // Desktop Grid m_data->settings()->setBorderActivateDesktopGrid(m_form->monitorCheckEffectHasEdge(DesktopGrid)); - // Desktop Cube - m_data->settings()->setBorderActivateCube(m_form->monitorCheckEffectHasEdge(Cube)); - m_data->settings()->setBorderActivateCylinder(m_form->monitorCheckEffectHasEdge(Cylinder)); - m_data->settings()->setBorderActivateSphere(m_form->monitorCheckEffectHasEdge(Sphere)); - // TabBox m_data->settings()->setBorderActivateTabBox(m_form->monitorCheckEffectHasEdge(TabBox)); m_data->settings()->setBorderAlternativeActivate(m_form->monitorCheckEffectHasEdge(TabBoxAlternative)); @@ -295,11 +275,6 @@ void KWinScreenEdgesConfig::monitorShowEvent() enabled = effectEnabled(BuiltInEffect::DesktopGrid, config); m_form->monitorItemSetEnabled(DesktopGrid, enabled); - // Desktop Cube - enabled = effectEnabled(BuiltInEffect::Cube, config); - m_form->monitorItemSetEnabled(Cube, enabled); - m_form->monitorItemSetEnabled(Cylinder, enabled); - m_form->monitorItemSetEnabled(Sphere, enabled); // tabbox, depends on reasonable focus policy. KConfigGroup config2(m_config, "Windows"); QString focusPolicy = config2.readEntry("FocusPolicy", QString()); diff --git a/src/kcmkwin/kwinscreenedges/main.h b/src/kcmkwin/kwinscreenedges/main.h index e96b1c9903..5f2a1d1244 100644 --- a/src/kcmkwin/kwinscreenedges/main.h +++ b/src/kcmkwin/kwinscreenedges/main.h @@ -53,9 +53,6 @@ private: PresentWindowsCurrent, PresentWindowsClass, DesktopGrid, - Cube, - Cylinder, - Sphere, TabBox, TabBoxAlternative, EffectCount diff --git a/src/kcmkwin/kwinscreenedges/touch.cpp b/src/kcmkwin/kwinscreenedges/touch.cpp index fc29732271..436d92971e 100644 --- a/src/kcmkwin/kwinscreenedges/touch.cpp +++ b/src/kcmkwin/kwinscreenedges/touch.cpp @@ -85,7 +85,6 @@ void KWinScreenEdgesConfig::save() QDBusConnection::sessionBus()); interface.reconfigureEffect(BuiltInEffects::nameForEffect(BuiltInEffect::PresentWindows)); interface.reconfigureEffect(BuiltInEffects::nameForEffect(BuiltInEffect::DesktopGrid)); - interface.reconfigureEffect(BuiltInEffects::nameForEffect(BuiltInEffect::Cube)); KCModule::save(); } @@ -133,10 +132,6 @@ void KWinScreenEdgesConfig::monitorInit() m_form->monitorAddItem(i18n("%1 - Current Desktop", presentWindowsName)); m_form->monitorAddItem(i18n("%1 - Current Application", presentWindowsName)); m_form->monitorAddItem(BuiltInEffects::effectData(BuiltInEffect::DesktopGrid).displayName); - const QString cubeName = BuiltInEffects::effectData(BuiltInEffect::Cube).displayName; - m_form->monitorAddItem(i18n("%1 - Cube", cubeName)); - m_form->monitorAddItem(i18n("%1 - Cylinder", cubeName)); - m_form->monitorAddItem(i18n("%1 - Sphere", cubeName)); m_form->monitorAddItem(i18n("Toggle window switching")); m_form->monitorAddItem(i18n("Toggle alternative window switching")); @@ -181,13 +176,6 @@ void KWinScreenEdgesConfig::monitorLoadSettings() // Desktop Grid BorderActivate m_form->monitorChangeEdge(m_data->settings()->touchBorderActivateDesktopGrid(), DesktopGrid); - // Desktop Cube BorderActivate - m_form->monitorChangeEdge(m_data->settings()->touchBorderActivateCube(), Cube); - // Desktop Cube BorderActivateCylinder - m_form->monitorChangeEdge(m_data->settings()->touchBorderActivateCylinder(), Cylinder); - // Desktop Cube BorderActivateSphere - m_form->monitorChangeEdge(m_data->settings()->touchBorderActivateSphere(), Sphere); - // TabBox BorderActivate m_form->monitorChangeEdge(m_data->settings()->touchBorderActivateTabBox(), TabBox); // Alternative TabBox @@ -217,13 +205,6 @@ void KWinScreenEdgesConfig::monitorLoadDefaultSettings() // Desktop Grid BorderActivate m_form->monitorChangeDefaultEdge(m_data->settings()->defaultTouchBorderActivateDesktopGridValue(), DesktopGrid); - // Desktop Cube BorderActivate - m_form->monitorChangeDefaultEdge(m_data->settings()->defaultTouchBorderActivateCubeValue(), Cube); - // Desktop Cube BorderActivateCylinder - m_form->monitorChangeDefaultEdge(m_data->settings()->defaultTouchBorderActivateCylinderValue(), Cylinder); - // Desktop Cube BorderActivateSphere - m_form->monitorChangeDefaultEdge(m_data->settings()->defaultTouchBorderActivateSphereValue(), Sphere); - // TabBox BorderActivate m_form->monitorChangeDefaultEdge(m_data->settings()->defaultTouchBorderActivateTabBoxValue(), TabBox); // Alternative TabBox @@ -248,11 +229,6 @@ void KWinScreenEdgesConfig::monitorSaveSettings() // Desktop Grid m_data->settings()->setTouchBorderActivateDesktopGrid(m_form->monitorCheckEffectHasEdge(DesktopGrid)); - // Desktop Cube - m_data->settings()->setTouchBorderActivateCube(m_form->monitorCheckEffectHasEdge(Cube)); - m_data->settings()->setTouchBorderActivateCylinder(m_form->monitorCheckEffectHasEdge(Cylinder)); - m_data->settings()->setTouchBorderActivateSphere(m_form->monitorCheckEffectHasEdge(Sphere)); - // TabBox m_data->settings()->setTouchBorderActivateTabBox(m_form->monitorCheckEffectHasEdge(TabBox)); m_data->settings()->setTouchBorderAlternativeActivate(m_form->monitorCheckEffectHasEdge(TabBoxAlternative)); @@ -278,11 +254,6 @@ void KWinScreenEdgesConfig::monitorShowEvent() enabled = effectEnabled(BuiltInEffect::DesktopGrid, config); m_form->monitorItemSetEnabled(DesktopGrid, enabled); - // Desktop Cube - enabled = effectEnabled(BuiltInEffect::Cube, config); - m_form->monitorItemSetEnabled(Cube, enabled); - m_form->monitorItemSetEnabled(Cylinder, enabled); - m_form->monitorItemSetEnabled(Sphere, enabled); // tabbox, depends on reasonable focus policy. KConfigGroup config2(m_config, "Windows"); QString focusPolicy = config2.readEntry("FocusPolicy", QString()); diff --git a/src/kcmkwin/kwinscreenedges/touch.h b/src/kcmkwin/kwinscreenedges/touch.h index 61403abb2e..96b33af318 100644 --- a/src/kcmkwin/kwinscreenedges/touch.h +++ b/src/kcmkwin/kwinscreenedges/touch.h @@ -53,9 +53,6 @@ private: PresentWindowsCurrent, PresentWindowsClass, DesktopGrid, - Cube, - Cylinder, - Sphere, TabBox, TabBoxAlternative, EffectCount