diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 8fc5cd3..5a9af3c 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1 +1 @@
-custom: https://www.paypal.com/donate/?business=WYGJ6T4J23P2L&no_recurring=0¤cy_code=CAD
+github: USERNAME
diff --git a/.github/workflows/arch.yml b/.github/workflows/arch.yml
index 2137aea..0cc4ab2 100644
--- a/.github/workflows/arch.yml
+++ b/.github/workflows/arch.yml
@@ -27,10 +27,10 @@ jobs:
steps:
- name: Refresh Packages
- run: yes | pacman -Syu
+ run: pacman -Syu --noconfirm
- name: Install Dependencies
- run: yes | pacman -S git cmake extra-cmake-modules qt5-tools kwin wireplumber
+ run: pacman -S --noconfirm git cmake extra-cmake-modules qt5-tools kwin wireplumber
- name: Check out repository
uses: actions/checkout@v3
diff --git a/.github/workflows/debian12.yml b/.github/workflows/debian12.yml
index 73a2fd3..be68082 100644
--- a/.github/workflows/debian12.yml
+++ b/.github/workflows/debian12.yml
@@ -34,7 +34,7 @@ jobs:
continue-on-error: true
- name: Install Dependencies
- run: apt -y install cmake g++ gettext extra-cmake-modules qttools5-dev libqt5x11extras5-dev libkf5configwidgets-dev libkf5globalaccel-dev libkf5notifications-dev kwin-dev
+ run: apt -y install cmake g++ gettext extra-cmake-modules qttools5-dev libkf5configwidgets-dev kwin-dev
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
diff --git a/.github/workflows/glslangValidator.yml b/.github/workflows/glslangValidator.yml
index 744974c..243992d 100644
--- a/.github/workflows/glslangValidator.yml
+++ b/.github/workflows/glslangValidator.yml
@@ -28,4 +28,4 @@ jobs:
run: sudo apt update && sudo apt install -y glslang-tools
- name: Validate Shaders
- run: glslangValidator src/shaders_110/shapecorners.frag src/shaders_140/shapecorners.frag
+ run: glslangValidator src/shaders/shapecorners.frag src/shaders/shapecorners_core.frag
diff --git a/.github/workflows/kubuntu2204-backports.yml b/.github/workflows/kubuntu2204-backports.yml
index c3acfae..4813c0c 100644
--- a/.github/workflows/kubuntu2204-backports.yml
+++ b/.github/workflows/kubuntu2204-backports.yml
@@ -39,7 +39,7 @@ jobs:
run: sudo add-apt-repository -y ppa:kubuntu-ppa/backports-extra
- name: Install Dependencies
- run: sudo apt install -y gettext extra-cmake-modules qttools5-dev libqt5x11extras5-dev libkf5configwidgets-dev libkf5globalaccel-dev libkf5notifications-dev kwin-dev
+ run: sudo apt install -y gettext extra-cmake-modules qttools5-dev libkf5configwidgets-dev kwin-dev
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
diff --git a/.github/workflows/neon-unstable.yml b/.github/workflows/neon-unstable.yml
index 0cce047..b5cbcc7 100644
--- a/.github/workflows/neon-unstable.yml
+++ b/.github/workflows/neon-unstable.yml
@@ -1,7 +1,14 @@
name: KDE Neon (Unstable)
on:
- workflow_dispatch:
+ push:
+ branches: [ master ]
+ paths-ignore: [ '**.md', '**.png' ]
+ pull_request:
+ branches: [ master ]
+ paths-ignore: [ '**.md', '**.png' ]
+ schedule:
+ - cron: "0 0 * * *"
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
@@ -23,11 +30,19 @@ jobs:
uses: actions/checkout@v3
- name: Refresh KDE Neon Packages
- run: apt update && apt -y dist-upgrade
+ run: apt update && apt -y --allow-downgrades dist-upgrade
+ continue-on-error: true
+
+ - name: Second refresh KDE Neon Packages
+ run: apt update && apt -y --allow-downgrades dist-upgrade
+ continue-on-error: true
+
+ - name: Third refresh KDE Neon Packages
+ run: apt update && apt -y --allow-downgrades autoremove
continue-on-error: true
- name: Install Dependencies
- run: apt -y install cmake g++ gettext extra-cmake-modules qttools5-dev libqt5x11extras5-dev libkf5configwidgets-dev libkf5globalaccel-dev libkf5notifications-dev kwin-dev
+ run: apt -y install cmake g++ gettext extra-cmake-modules qt6-base-dev-tools kf6-kcmutils-dev kwin-dev
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
diff --git a/.github/workflows/neon.yml b/.github/workflows/neon.yml
index f84cecd..da5347e 100644
--- a/.github/workflows/neon.yml
+++ b/.github/workflows/neon.yml
@@ -34,7 +34,7 @@ jobs:
continue-on-error: true
- name: Install Dependencies
- run: apt -y install cmake g++ gettext extra-cmake-modules qttools5-dev libqt5x11extras5-dev libkf5configwidgets-dev libkf5globalaccel-dev libkf5notifications-dev kwin-dev
+ run: apt -y install cmake g++ gettext extra-cmake-modules qttools5-dev libkf5configwidgets-dev kwin-dev
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
diff --git a/.gitignore b/.gitignore
index 864c833..733dbb2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,5 @@
/cmake-build-*/
/qt5build/
/build/
+/Testing/
CMakeLists.txt.user
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6c333af..fa5ead6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,8 +1,11 @@
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.20)
-project(kwin-effects-yaml)
+project(kwin4_effect_shapecorners)
+
+set(KF_MIN_VERSION "5.78")
+set(QT_MIN_VERSION "5.15")
+set(QT_MAJOR_VERSION 5)
-set(KF5_MIN_VERSION "5.78")
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
@@ -12,24 +15,16 @@ if(NOT CMAKE_BUILD_TYPE)
endif()
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DQT_NO_DEBUG_OUTPUT")
-find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
+find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH
${CMAKE_MODULE_PATH}
${ECM_MODULE_PATH}
${ECM_KDE_MODULE_DIR}
)
-
-find_package(Qt5 CONFIG REQUIRED COMPONENTS
- Gui
- Core
- DBus
- UiTools
- Widgets
- X11Extras
- OpenGL
- Network
- Xml
-)
+if(ECM_VERSION VERSION_GREATER "5.200.0")
+ set(QT_MIN_VERSION "6.4.0")
+ set(QT_MAJOR_VERSION 6)
+endif()
include(FeatureSummary)
include(KDEInstallDirs)
@@ -37,28 +32,46 @@ include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
# required frameworks by Core
-find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
- Config
+find_package(KF${QT_MAJOR_VERSION} ${KF_MIN_VERSION} REQUIRED COMPONENTS
ConfigWidgets
- CoreAddons
- GlobalAccel
- WindowSystem
)
+if(${QT_MAJOR_VERSION} EQUAL 6)
+ find_package(KF${QT_MAJOR_VERSION} ${KF_MIN_VERSION} REQUIRED COMPONENTS
+ KCMUtils
+ )
+
+ find_package(KWin REQUIRED COMPONENTS
+ kwineffects
+ )
+ set(KWIN_EFFECT_INCLUDE_FILE "/usr/include/kwin/effect/effect.h")
+else()
+ find_package(KWinEffects REQUIRED COMPONENTS
+ kwineffects
+ kwinglutils
+ )
+ set(KWIN_EFFECT_INCLUDE_FILE "/usr/include/kwineffects.h")
+endif ()
+find_package(epoxy REQUIRED)
find_package(XCB REQUIRED COMPONENTS XCB)
-find_package(KWinEffects REQUIRED COMPONENTS
- kwineffects
- kwinglutils
-)
-
find_package(KWinDBusInterface CONFIG REQUIRED)
-find_package(epoxy REQUIRED)
add_subdirectory(src)
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
+execute_process(
+ COMMAND sh -c "grep '#define KWIN_EFFECT_API_VERSION_MINOR' ${KWIN_EFFECT_INCLUDE_FILE} | awk '{print \$NF}'"
+ OUTPUT_VARIABLE KWIN_EFFECT_API_VERSION_MINOR OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+message("KWinEffect API Version: ${KWIN_EFFECT_API_VERSION_MINOR}")
+message("")
+
+add_test (NAME KWinEffectSupport COMMAND sh ${CMAKE_CURRENT_LIST_DIR}/tools/isSupported.sh)
+set_property (TEST KWinEffectSupport PROPERTY PASS_REGULAR_EXPRESSION "true")
+
+
# these are cache variables, so they could be overwritten with -D,
set(CPACK_PACKAGE_NAME kwin4-effect-shapecorners
CACHE STRING kwin4-effect-shapecorners
diff --git a/README.md b/README.md
index b091ead..dc2931d 100644
--- a/README.md
+++ b/README.md
@@ -4,44 +4,66 @@ This effect rounds the corners of your windows and adds an outline around them w
This effect started as a fork of [shapecorners](https://sourceforge.net/projects/shapecorners/) with some additional contributions in [Alex47's project](https://github.com/alex47/KDE-Rounded-Corners), then I optimized and reimplemented the effect with shaders with influences from the [invert effect](https://github.com/KDE/kwin/tree/master/src/plugins/invert).
-#### Tested on:
+**Tested on:**
+-  
- 
-
-- 
-
+ 
+- 
+ 
- 
- 
-- 
-
+  
+- 
+ 
- 
-
+ 
- [  ](https://aur.archlinux.org/packages/kwin-effect-rounded-corners-git)
-
+
# Contributions:
-- Compatibility of the effect with other effects like Wobbly windows - by [matinlotfali](https://github.com/matinlotfali)
-- Optimize the effect to render once instead of 5 times - by [matinlotfali](https://github.com/matinlotfali) - see [#49](https://github.com/matinlotfali/KDE-Rounded-Corners/pull/49)
-- Reimplementation with shaders to include shadows at corners and an outline - by [matinlotfali](https://github.com/matinlotfali)
-- Compatibility with KWin from versions 5.23 to 5.27 - by [matinlotfali](https://github.com/matinlotfali)
-- Disable effect when window gets maximized - by [matinlotfali](https://github.com/matinlotfali)
+- Compatibility of the effect with other effects like Wobbly windows
+- Compatibility with KWin for Plasma versions 5.27 to 6.0
+- Optimize the effect to render once instead of 5 times - see [#49](https://github.com/matinlotfali/KDE-Rounded-Corners/pull/49)
+- Reimplementation with shaders to include shadows at corners and an outline
+- Disable effect when windows get maximized
- Cleanups for the plugin logic, remove unneeded dependencies from CMakeLists.txt file - by [alex1701c](https://github.com/alex1701c)
- Separate outline color for active and inactive windows - by [OrkenWhite](https://github.com/OrkenWhite)
+- Add natural shadows using parametric blend - by [paletteOvO](https://github.com/paletteOvO)
# How to build from source code:
You need to install development packages for your distribution first:
-- **Debian based (Ubuntu, Kubuntu, KDE Neon)** - by [alex47](https://github.com/alex47):
- ```
- sudo apt install git cmake g++ gettext extra-cmake-modules qttools5-dev libqt5x11extras5-dev libkf5configwidgets-dev libkf5globalaccel-dev libkf5notifications-dev kwin-dev
- ```
-- **Fedora** - by [matinlotfali](https://github.com/matinlotfali)
- ```
- sudo dnf install git cmake gcc-c++ extra-cmake-modules qt5-qttools-devel qt5-qttools-static qt5-qtx11extras-devel kf5-kconfigwidgets-devel kf5-kcrash-devel kf5-kguiaddons-devel kf5-kglobalaccel-devel kf5-kio-devel kf5-ki18n-devel kwin-devel qt5-qtbase-devel libepoxy-devel
- ```
-- **Arch** - by [hexa-one](https://github.com/hexa-one)
+
+Debian based (Ubuntu, Kubuntu, KDE Neon)
+
+
+ - Plasma 5 - by [alex47](https://github.com/alex47):
+ ```
+ sudo apt install git cmake g++ extra-cmake-modules kwin-dev libkf5configwidgets-dev
+ ```
+ - Plasma 6
+ ```
+ sudo apt install git cmake g++ extra-cmake-modules kwin-dev qt6-base-dev-tools kf6-kcmutils-dev
+ ```
+
+
+Fedora
+
+
+ - Plasma 5 (Fedora 39)
+ ```bash
+ sudo dnf install git cmake gcc-c++ extra-cmake-modules kwin-devel kf5-kconfigwidgets-devel libepoxy-devel
+ ```
+ - Plasma 6 (Fedora 40 and later)
+ ```bash
+ sudo dnf install git cmake gcc-c++ extra-cmake-modules kwin-devel kf6-kconfigwidgets-devel libepoxy-devel kf6-kcmutils-devel qt6-qtbase-private-devel wayland-devel
+ ```
+
+
+Arch - by https://github.com/hexa-one
+
```
sudo pacman -S git cmake extra-cmake-modules base-devel
yay -S qt5-tools
@@ -50,22 +72,31 @@ You need to install development packages for your distribution first:
```
sudo pamac build kwin-effect-rounded-corners-git
```
-- **OpenSUSE** - by [mathiasgredal](https://github.com/mathiasgredal) and [Richardsause](https://github.com/Richardsause)
+
+
+OpenSUSE - by https://github.com/mathiasgredal and https://github.com/Richardsause
+
```
- sudo zypper install git cmake gcc-c++ extra-cmake-modules libqt5-qttools-devel libqt5-qtx11extras-devel kconfigwidgets-devel kguiaddons-devel kglobalaccel-devel ki18n-devel knotifications-devel kwin5-devel libQt5Gui-devel libQt5OpenGL-devel libepoxy-devel kwindowsystem-devel libqt5-qtnetworkauth-devel
+ sudo zypper install git cmake gcc-c++ extra-cmake-modules libqt5-qttools-devel kconfigwidgets-devel kguiaddons-devel ki18n-devel knotifications-devel kwin5-devel libQt5Gui-devel libQt5OpenGL-devel libepoxy-devel libqt5-qtnetworkauth-devel
```
-- **Void** - by [lay-by](https://github.com/lay-by)
+
+
+Void - by https://github.com/lay-by
+
```
- xbps-install git cmake make qt5-tools-devel extra-cmake-modules qt5-x11extras-devel gettext-devel kwin-devel
+ xbps-install git cmake make qt5-tools-devel extra-cmake-modules gettext-devel kwin-devel
```
-- **NixOS** - by [Pavel Zolotarevskiy](https://github.com/flexagoon)
+
+
+NixOS - by https://github.com/flexagoon
+
```
nix-env -iA nixos.kde-rounded-corners
```
-
+
-Then get the source code and compile:
-```
+Then clone the source code and compile it:
+```bash
git clone https://github.com/matinlotfali/KDE-Rounded-Corners
cd KDE-Rounded-Corners
mkdir build
@@ -75,15 +106,53 @@ make
sudo make install
```
-You can now logout and log back in or run the command below to have it activated.
+# Load & Unload
+
+To activate the effect, you can now log out and log back in, or run the command below inside the `build` directory:
+```bash
+sh ../tools/load.sh
```
-kwin --replace &
+
+To fully uninstall the effect, run the following commands inside the `build` directory:
+
+```bash
+sh ../tools/unload.sh
+sudo make uninstall
+```
+
+# Auto install after KWin update
+
+After each `kwin` package update, the effect becomes incompatible. So it won't load without a rebuild.
+
+As long as the effect is not part of the `kwin` yet (being discussed
+[here](https://invent.kde.org/plasma/kwin/-/issues/198)), you can automate the re-installation by running the command
+below inside the `build` directory:
+
+```bash
+sh ../tools/autorun-test-install.sh
```
+The command above adds a `desktop` file inside the `autorun` directory which checks if the effect is still supported,
+if it is not supported, it would automatically rebuild and reinstall the effect.
+
# Settings
-You can change corner radius, or disable the effect in:
+You can change the corner radius, or disable the effect in:
+
+> [ System Settings ] --> [ Workspace Behavior ] --> [ Desktop Effects ] --> [ ShapeCorners ]
+
+# Tips
+
+## Add shadow to windows without decoration (like Steam)
+
+You can add shadows for specific windows using the hack below. I don't know how to enforce it in my code.
+
+1. In [ System settings ] -> [ Window management ] -> [ Window rules ] -> [ Appearance & Fixes ]:
+
+ **Add [steam] and set [ No titlebar ] and frame to [ No ]**
+
+3. In [ System settings ] -> [ Application Style ] -> [ Window decoration ] -> [ Breeze theme setting ] -> [ Window specific overrides ]:
-> System Settings --> Workspace Behavior --> Desktop Effects --> ShapeCorners
+ **Add [steam] and set [ Hide Window title bar ] to [ Yes ].**
-To fully uninstall, simply run the command `sudo make uninstall` inside `build` directory
+After that, the Steam window gets its shadows back.
diff --git a/screenshots/shadows2.png b/screenshots/shadows2.png
new file mode 100644
index 0000000..0e60700
Binary files /dev/null and b/screenshots/shadows2.png differ
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4eafc81..7cfdbef 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,29 +1,30 @@
add_subdirectory(kcm)
set(effect_SRCS
+ ShapeCornersEffect.h
ShapeCornersEffect.cpp
+ ShapeCornersShader.h
ShapeCornersShader.cpp
plugin.cpp
)
kconfig_add_kcfg_files(effect_SRCS ShapeCornersConfig.kcfgc)
-add_library(kwin4_effect_shapecorners SHARED ${effect_SRCS})
+kcoreaddons_add_plugin(kwin4_effect_shapecorners SOURCES ${effect_SRCS} INSTALL_NAMESPACE "kwin/effects/plugins/")
target_link_libraries(kwin4_effect_shapecorners
- Qt5::Core
- Qt5::Gui
- Qt5::DBus
- KWinEffects::kwineffects
- KWinEffects::kwinglutils
- epoxy::epoxy
- KF5::ConfigCore
- KF5::ConfigGui
- KF5::CoreAddons
- KF5::WindowSystem
+ Qt${QT_MAJOR_VERSION}::DBus
+ KF${QT_MAJOR_VERSION}::ConfigGui
)
+if(${QT_MAJOR_VERSION} EQUAL 6)
+ target_link_libraries(kwin4_effect_shapecorners
+ KWin::kwin
+ Qt${QT_MAJOR_VERSION}::CorePrivate
+ )
+else()
+ target_link_libraries(kwin4_effect_shapecorners
+ KWinEffects::kwineffects
+ KWinEffects::kwinglutils
+ )
+endif()
-install(TARGETS kwin4_effect_shapecorners DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/plugins/)
-
-execute_process(COMMAND kf5-config --install data OUTPUT_VARIABLE DATAPATH OUTPUT_STRIP_TRAILING_WHITESPACE)
-install(FILES shaders_140/shapecorners.frag DESTINATION ${DATAPATH}/kwin/shaders/1.40)
-install(FILES shaders_110/shapecorners.frag DESTINATION ${DATAPATH}/kwin/shaders/1.10)
\ No newline at end of file
+install(DIRECTORY shaders DESTINATION ${KDE_INSTALL_DATADIR}/kwin)
diff --git a/src/ShapeCornersEffect.cpp b/src/ShapeCornersEffect.cpp
index 0b92b9c..3c0fd07 100644
--- a/src/ShapeCornersEffect.cpp
+++ b/src/ShapeCornersEffect.cpp
@@ -18,49 +18,43 @@
*/
#include "ShapeCornersEffect.h"
-#include
+#include "ShapeCornersConfig.h"
#include
#include
-
-#if KWIN_EFFECT_API_VERSION >= 235
#include
+
+#if QT_VERSION_MAJOR >= 6
+ #include
+ #include
+ #include
+ #include
#else
-#include
+ #include
#endif
ShapeCornersEffect::ShapeCornersEffect()
-#if KWIN_EFFECT_API_VERSION >= 236
: KWin::OffscreenEffect()
-#else
- : KWin::DeformEffect()
-#endif
{
reconfigure(ReconfigureAll);
- auto connection = QDBusConnection::sessionBus();
- if (!connection.isConnected()) {
+ if (auto connection = QDBusConnection::sessionBus();
+ !connection.isConnected()) {
qWarning("ShapeCorners: Cannot connect to the D-Bus session bus.\n");
}
else {
- if (!connection.registerService("org.kde.ShapeCorners")) {
+ if (!connection.registerService(QStringLiteral("org.kde.ShapeCorners"))) {
qWarning("%s\n", qPrintable(connection.lastError().message()));
}
else {
- if (!connection.registerObject("/ShapeCornersEffect", this, QDBusConnection::ExportAllSlots)) {
+ if (!connection.registerObject(QStringLiteral("/ShapeCornersEffect"), this, QDBusConnection::ExportAllSlots)) {
qWarning("%s\n", qPrintable(connection.lastError().message()));
}
}
}
if(m_shaderManager.IsValid()) {
-#if KWIN_EFFECT_API_VERSION >= 235
- const auto& windowList = KX11Extras::windows();
-#else
- const auto& windowList = KWindowSystem::windows();
-#endif
- for (const auto& id: windowList)
- if (auto win = KWin::effects->findWindow(id))
- windowAdded(win);
+ for (const auto& win: KWin::effects->stackingOrder())
+ windowAdded(win);
connect(KWin::effects, &KWin::EffectsHandler::windowAdded, this, &ShapeCornersEffect::windowAdded);
connect(KWin::effects, &KWin::EffectsHandler::windowDeleted, this, &ShapeCornersEffect::windowRemoved);
connect(KWin::effects, &KWin::EffectsHandler::windowFinishUserMovedResized, this, &ShapeCornersEffect::windowResized);
@@ -74,8 +68,7 @@ void
ShapeCornersEffect::windowAdded(KWin::EffectWindow *w)
{
qDebug() << w->windowRole() << w->windowType() << w->windowClass();
- auto [it, success] = m_managed.insert({w, false});
- if (success) {
+ if (const auto& [w2, r] = m_managed.insert({w, false}); r) {
redirect(w);
setShader(w, m_shaderManager.GetShader().get());
if (w->width() >= 300 && w->height() >= 300)
@@ -92,17 +85,12 @@ void ShapeCornersEffect::windowRemoved(KWin::EffectWindow *w)
}
void
-ShapeCornersEffect::reconfigure(ReconfigureFlags flags)
+ShapeCornersEffect::reconfigure(const ReconfigureFlags flags)
{
Q_UNUSED(flags)
ShapeCornersConfig::self()->read();
}
-QRectF operator *(QRect r, qreal scale) { return {r.x() * scale, r.y() * scale, r.width() * scale, r.height() * scale}; }
-QRectF operator *(QRectF r, qreal scale) { return {r.x() * scale, r.y() * scale, r.width() * scale, r.height() * scale}; }
-QRect toRect(const QRectF& r) { return {(int)r.x(), (int)r.y(), (int)r.width(), (int)r.height()}; }
-const QRect& toRect(const QRect& r) { return r; }
-
void ShapeCornersEffect::prePaintWindow(KWin::EffectWindow *w, KWin::WindowPrePaintData &data, std::chrono::milliseconds time)
{
if (!hasEffect(w) || (isTiled(w) && ShapeCornersConfig::disableRoundTile()))
@@ -111,33 +99,24 @@ void ShapeCornersEffect::prePaintWindow(KWin::EffectWindow *w, KWin::WindowPrePa
return;
}
- auto size = isWindowActive(w) ? ShapeCornersConfig::size(): ShapeCornersConfig::inactiveCornerRadius();
+ const auto size = isWindowActive(w) ? ShapeCornersConfig::size(): ShapeCornersConfig::inactiveCornerRadius();
-#if KWIN_EFFECT_API_VERSION >= 234
- const auto geo_ex = w->expandedGeometry() * KWin::effects->renderTargetScale();
- const auto geo = w->frameGeometry() * KWin::effects->renderTargetScale();
+#if QT_VERSION_MAJOR >= 6
+ const auto geo = w->frameGeometry() * w->screen()->scale();
data.setTranslucent();
#else
- const auto& geo_ex = w->expandedGeometry();
- const auto& geo = w->expandedGeometry();
+ const auto geo = w->frameGeometry() * KWin::effects->renderTargetScale();
+ data.setTranslucent();
#endif
QRegion reg {};
- reg += toRect(geo_ex);
- reg -= toRect(geo);
reg += QRect(geo.x(), geo.y(), size, size);
reg += QRect(geo.x()+geo.width()-size, geo.y(), size, size);
reg += QRect(geo.x(), geo.y()+geo.height()-size, size, size);
reg += QRect(geo.x()+geo.width()-size, geo.y()+geo.height()-size, size, size);
-#if KWIN_EFFECT_API_VERSION >= 234
data.opaque -= reg;
-#endif
data.paint += reg;
-#if KWIN_EFFECT_API_VERSION >= 236
OffscreenEffect::prePaintWindow(w, data, time);
-#else
- DeformEffect::prePaintWindow(w, data, time);
-#endif
}
bool ShapeCornersEffect::supported()
@@ -145,45 +124,57 @@ bool ShapeCornersEffect::supported()
return KWin::effects->isOpenGLCompositing();
}
+#if QT_VERSION_MAJOR >= 6
+void ShapeCornersEffect::drawWindow(const KWin::RenderTarget &renderTarget, const KWin::RenderViewport &viewport,
+ KWin::EffectWindow *w, int mask, const QRegion ®ion,
+ KWin::WindowPaintData &data) {
+#else
void ShapeCornersEffect::drawWindow(KWin::EffectWindow *w, int mask, const QRegion ®ion,
KWin::WindowPaintData &data) {
+#endif
if (!hasEffect(w))
{
unredirect(w);
-#if KWIN_EFFECT_API_VERSION >= 236
- OffscreenEffect::drawWindow(w, mask, region, data);
+#if QT_VERSION_MAJOR >= 6
+ OffscreenEffect::drawWindow(renderTarget, viewport, w, mask, region, data);
#else
- DeformEffect::drawWindow(w, mask, region, data);
+ OffscreenEffect::drawWindow(w, mask, region, data);
#endif
return;
}
+#if QT_VERSION_MAJOR >= 6
+ const auto scale = viewport.scale();
+#else
+ const auto scale = KWin::effects->renderTargetScale();
+#endif
+
redirect(w);
setShader(w, m_shaderManager.GetShader().get());
- m_shaderManager.Bind(w, isTiled(w));
+ m_shaderManager.Bind(w, scale, isTiled(w));
glActiveTexture(GL_TEXTURE0);
-#if KWIN_EFFECT_API_VERSION >= 236
- OffscreenEffect::drawWindow(w, mask, region, data);
+#if QT_VERSION_MAJOR >= 6
+ OffscreenEffect::drawWindow(renderTarget, viewport, w, mask, region, data);
#else
- DeformEffect::drawWindow(w, mask, region, data);
+ OffscreenEffect::drawWindow(w, mask, region, data);
#endif
m_shaderManager.Unbind();
}
bool ShapeCornersEffect::hasEffect(const KWin::EffectWindow *w) const {
- auto name = w->windowClass().split(' ').first();
+ const auto name = w->windowClass().split(QChar::Space).first();
return m_shaderManager.IsValid()
&& m_managed.contains(w)
- && (w->hasDecoration() || ShapeCornersConfig::inclusions().contains(name))
+ && (w->isNormalWindow() || ShapeCornersConfig::inclusions().contains(name))
&& !ShapeCornersConfig::exclusions().contains(name);
}
-QString ShapeCornersEffect::get_window_titles() {
+QString ShapeCornersEffect::get_window_titles() const {
QList response;
for (const auto& [win, tiled]: m_managed) {
- auto name = win->windowClass().split(' ').first();
- if (name == "plasmashell")
+ const auto name = win->windowClass().split(QChar::Space).first();
+ if (name == QStringLiteral("plasmashell"))
continue;
if (!response.contains(name))
response.push_back(name);
diff --git a/src/ShapeCornersEffect.h b/src/ShapeCornersEffect.h
index 0302aee..21f0e19 100644
--- a/src/ShapeCornersEffect.h
+++ b/src/ShapeCornersEffect.h
@@ -19,18 +19,17 @@
#pragma once
-#include
-#include
#include "ShapeCornersShader.h"
-#define qDebugIfActive(w, s) if(ShapeCornersEffect::isWindowActive(w)) { qDebug() << s; }
-#if KWIN_EFFECT_API_VERSION >= 236
-#include
-class ShapeCornersEffect : public KWin::OffscreenEffect
+#if QT_VERSION_MAJOR >= 6
+ #include
+ #include
#else
-#include
-class ShapeCornersEffect : public KWin::DeformEffect
+ #include
+ #include
#endif
+
+class ShapeCornersEffect final: public KWin::OffscreenEffect
{
Q_OBJECT
public:
@@ -43,11 +42,19 @@ class ShapeCornersEffect : public KWin::DeformEffect
void reconfigure(ReconfigureFlags flags) override;
void prePaintWindow(KWin::EffectWindow *w, KWin::WindowPrePaintData &data, std::chrono::milliseconds time) override;
- void drawWindow(KWin::EffectWindow *window, int mask, const QRegion ®ion, KWin::WindowPaintData &data) override;
- int requestedEffectChainPosition() const override { return 99; }
+
+#if QT_VERSION_MAJOR >= 6
+ void drawWindow(const KWin::RenderTarget &RenderTarget, const KWin::RenderViewport& viewport,
+ KWin::EffectWindow *w, int mask, const QRegion ®ion, KWin::WindowPaintData &data) override;
+#else
+ void drawWindow(KWin::EffectWindow *w, int mask, const QRegion ®ion, KWin::WindowPaintData &data) override;
+#endif
+
+ [[nodiscard]] int requestedEffectChainPosition() const override { return 99; }
+ [[nodiscard]] bool blocksDirectScanout() const override { return false; }
public Q_SLOTS:
- QString get_window_titles();
+ [[nodiscard]] QString get_window_titles() const;
private Q_SLOTS:
void windowAdded(KWin::EffectWindow *window);
diff --git a/src/ShapeCornersShader.cpp b/src/ShapeCornersShader.cpp
index 008e05c..42cfbf1 100644
--- a/src/ShapeCornersShader.cpp
+++ b/src/ShapeCornersShader.cpp
@@ -2,54 +2,46 @@
// Created by matin on 20/07/22.
//
-#include
+#include "ShapeCornersShader.h"
+#include "ShapeCornersEffect.h"
+#include "ShapeCornersConfig.h"
#include
-#include
-#include
#include
-#include "ShapeCornersEffect.h"
-#include "ShapeCornersShader.h"
+
+#if QT_VERSION_MAJOR >= 6
+ #include
+#else
+ #include
+#endif
ShapeCornersShader::ShapeCornersShader():
m_manager(KWin::ShaderManager::instance()),
- m_palette(QWidget().palette())
+ m_widget(new QWidget)
{
- const QString shadersDir = IsLegacy()? "kwin/shaders/1.10/": "kwin/shaders/1.40/";
- const QString fragmentshader = QStandardPaths::locate(QStandardPaths::GenericDataLocation, shadersDir + QStringLiteral("shapecorners.frag"));
+ const QString fragmentshader = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/shaders/shapecorners.frag"));
// m_shader = KWin::ShaderManager::instance()->loadFragmentShader(KWin::ShaderManager::GenericShader, fragmentshader);
QFile file(fragmentshader);
- if (file.open(QFile::ReadOnly))
- {
- QByteArray frag = file.readAll();
- auto shader = m_manager->generateCustomShader(KWin::ShaderTrait::MapTexture, QByteArray(), frag);
-#if KWIN_EFFECT_API_VERSION >= 235
- m_shader = std::move(shader);
-#else
- m_shader.reset(shader);
-#endif
- file.close();
-// qDebug() << frag;
- if (m_shader->isValid())
- {
- m_shader_disableRoundedTile = m_shader->uniformLocation("disableRoundedTile");
- m_shader_windowSize = m_shader->uniformLocation("windowSize");
- m_shader_windowExpandedSize = m_shader->uniformLocation("windowExpandedSize");
- m_shader_windowTopLeft = m_shader->uniformLocation("windowTopLeft");
- m_shader_shadowColor = m_shader->uniformLocation("shadowColor");
- m_shader_shadowSize = m_shader->uniformLocation("shadowSize");
- m_shader_radius = m_shader->uniformLocation("radius");
- m_shader_outlineColor = m_shader->uniformLocation("outlineColor");
- m_shader_outlineThickness = m_shader->uniformLocation("outlineThickness");
- m_shader_front = m_shader->uniformLocation("front");
- qInfo() << "ShapeCorners: shaders loaded.";
- }
- else
- qCritical() << "ShapeCorners: no valid shaders found! ShapeCorners will not work.";
- }
- else
- {
+ if (!file.open(QFile::ReadOnly))
qCritical() << "ShapeCorners: no shaders found! Exiting...";
- }
+
+ const QByteArray frag = file.readAll();
+ auto shader = m_manager->generateShaderFromFile(KWin::ShaderTrait::MapTexture, QStringLiteral(""), fragmentshader);
+ m_shader = std::move(shader);
+ file.close();
+ if (!m_shader->isValid())
+ qCritical() << "ShapeCorners: no valid shaders found! ShapeCorners will not work.";
+
+ m_shader_disableRoundedTile = m_shader->uniformLocation("disableRoundedTile");
+ m_shader_windowSize = m_shader->uniformLocation("windowSize");
+ m_shader_windowExpandedSize = m_shader->uniformLocation("windowExpandedSize");
+ m_shader_windowTopLeft = m_shader->uniformLocation("windowTopLeft");
+ m_shader_shadowColor = m_shader->uniformLocation("shadowColor");
+ m_shader_shadowSize = m_shader->uniformLocation("shadowSize");
+ m_shader_radius = m_shader->uniformLocation("radius");
+ m_shader_outlineColor = m_shader->uniformLocation("outlineColor");
+ m_shader_outlineThickness = m_shader->uniformLocation("outlineThickness");
+ m_shader_front = m_shader->uniformLocation("front");
+ qInfo() << "ShapeCorners: shaders loaded.";
}
bool ShapeCornersShader::IsValid() const {
@@ -57,20 +49,24 @@ bool ShapeCornersShader::IsValid() const {
}
const std::unique_ptr&
-ShapeCornersShader::Bind(KWin::EffectWindow *w, bool isTiled) const {
+ShapeCornersShader::Bind(KWin::EffectWindow *w, qreal scale, bool isTiled) const {
QColor outlineColor, shadowColor;
- auto xy = QVector2D((w->frameGeometry().left() - w->expandedGeometry().left()),
- (w->frameGeometry().top() - w->expandedGeometry().top()));
+ qreal shadowSize;
+ auto& m_palette = m_widget->palette();
+ auto frameGeometry = w->frameGeometry() * scale;
+ auto expandedGeometry = w->expandedGeometry() * scale;
+ auto xy = QVector2D(frameGeometry.topLeft() - expandedGeometry.topLeft());
+ qreal max_shadow_size = xy.length();
m_manager->pushShader(m_shader.get());
- m_shader->setUniform(m_shader_windowSize, QVector2D(w->frameGeometry().width(), w->frameGeometry().height()));
- m_shader->setUniform(m_shader_windowExpandedSize, QVector2D(w->expandedGeometry().width(), w->expandedGeometry().height()));
+ m_shader->setUniform(m_shader_windowSize, toVector2D(frameGeometry.size()));
+ m_shader->setUniform(m_shader_windowExpandedSize, toVector2D(expandedGeometry.size()));
m_shader->setUniform(m_shader_windowTopLeft, xy);
m_shader->setUniform(m_shader_disableRoundedTile, isTiled && ShapeCornersConfig::disableRoundTile());
m_shader->setUniform(m_shader_front, 0);
if (ShapeCornersEffect::isWindowActive(w)) {
- m_shader->setUniform(m_shader_shadowSize, (float)ShapeCornersConfig::shadowSize());
- m_shader->setUniform(m_shader_radius, (float)ShapeCornersConfig::size());
- m_shader->setUniform(m_shader_outlineThickness, (float)ShapeCornersConfig::outlineThickness());
+ shadowSize = std::min(ShapeCornersConfig::shadowSize() * scale, max_shadow_size);
+ m_shader->setUniform(m_shader_radius, static_cast(ShapeCornersConfig::size() * scale));
+ m_shader->setUniform(m_shader_outlineThickness, static_cast(ShapeCornersConfig::outlineThickness() * scale));
outlineColor = ShapeCornersConfig::activeOutlineUsePalette() ?
m_palette.color(QPalette::Active, static_cast(ShapeCornersConfig::activeOutlinePalette())):
@@ -81,19 +77,20 @@ ShapeCornersShader::Bind(KWin::EffectWindow *w, bool isTiled) const {
outlineColor.setAlpha(isTiled && ShapeCornersConfig::disableOutlineTile() ? 0: ShapeCornersConfig::activeOutlineAlpha());
shadowColor.setAlpha(ShapeCornersConfig::activeShadowAlpha());
} else {
- m_shader->setUniform(m_shader_shadowSize, (float)ShapeCornersConfig::inactiveShadowSize());
- m_shader->setUniform(m_shader_radius, (float)ShapeCornersConfig::inactiveCornerRadius());
- m_shader->setUniform(m_shader_outlineThickness, (float)ShapeCornersConfig::inactiveOutlineThickness());
+ shadowSize = std::min(ShapeCornersConfig::inactiveShadowSize() * scale, max_shadow_size);
+ m_shader->setUniform(m_shader_radius, static_cast(ShapeCornersConfig::inactiveCornerRadius() * scale));
+ m_shader->setUniform(m_shader_outlineThickness, static_cast(ShapeCornersConfig::inactiveOutlineThickness() * scale));
outlineColor = ShapeCornersConfig::inactiveOutlineUsePalette() ?
- m_palette.color(QPalette::Active, static_cast(ShapeCornersConfig::inactiveOutlinePalette())):
+ m_palette.color(QPalette::Inactive, static_cast(ShapeCornersConfig::inactiveOutlinePalette())):
ShapeCornersConfig::inactiveOutlineColor();
shadowColor = ShapeCornersConfig::inactiveShadowUsePalette() ?
- m_palette.color(QPalette::Active, static_cast(ShapeCornersConfig::inactiveShadowPalette())):
+ m_palette.color(QPalette::Inactive, static_cast(ShapeCornersConfig::inactiveShadowPalette())):
ShapeCornersConfig::inactiveShadowColor();
outlineColor.setAlpha(isTiled && ShapeCornersConfig::disableOutlineTile() ? 0: ShapeCornersConfig::inactiveOutlineAlpha());
shadowColor.setAlpha(ShapeCornersConfig::inactiveShadowAlpha());
}
+ m_shader->setUniform(m_shader_shadowSize, static_cast(shadowSize));
m_shader->setUniform(m_shader_outlineColor, outlineColor);
m_shader->setUniform(m_shader_shadowColor, shadowColor);
return m_shader;
@@ -102,12 +99,3 @@ ShapeCornersShader::Bind(KWin::EffectWindow *w, bool isTiled) const {
void ShapeCornersShader::Unbind() const {
m_manager->popShader();
}
-
-bool ShapeCornersShader::IsLegacy() {
-#ifdef KWIN_HAVE_OPENGLES
- const qint64 coreVersionNumber = kVersionNumber(3, 0);
-#else
- const qint64 version = KWin::kVersionNumber(1, 40);
-#endif
- return (KWin::GLPlatform::instance()->glslVersion() < version);
-}
diff --git a/src/ShapeCornersShader.h b/src/ShapeCornersShader.h
index 074a084..bab7268 100644
--- a/src/ShapeCornersShader.h
+++ b/src/ShapeCornersShader.h
@@ -5,39 +5,127 @@
#ifndef KWIN4_SHAPECORNERS_CONFIG_SHADERMANAGER_H
#define KWIN4_SHAPECORNERS_CONFIG_SHADERMANAGER_H
-#include
-#include
-#include
-#include "ShapeCornersConfig.h"
+#include
+#if QT_VERSION_MAJOR >= 6
+ #include
+#else
+ #include
+#endif
namespace KWin {
class GLShader;
class ShaderManager;
}
+inline QRectF operator *(const QRect& r, const qreal scale) { return {r.x() * scale, r.y() * scale, r.width() * scale, r.height() * scale}; }
+inline QRectF operator *(const QRectF& r, const qreal scale) { return {r.x() * scale, r.y() * scale, r.width() * scale, r.height() * scale}; }
+inline QVector2D toVector2D(const QSizeF& s) { return {static_cast(s.width()), static_cast(s.height())}; }
+
class ShapeCornersShader {
public:
- ShapeCornersShader();
+ /**
+ * \brief Loads the correct shader based on the GL platform in KWin.
+ * Then it assigns the location references for all its uniform variables so they could be written in.
+ */
+ explicit ShapeCornersShader();
+
+ /**
+ * \return True if the shader is valid and loaded
+ */
+ [[nodiscard]] bool IsValid() const;
- static bool IsLegacy();
- bool IsValid() const;
- const std::unique_ptr& Bind(KWin::EffectWindow *w, bool isTiled) const;
+ /**
+ * \brief This function assigns the required variables to the shader.
+ * Then it pushes the shader to the stack of rendering.
+ * This needs to be called before each window is rendered.
+ * \param w The window that the effect will be rendering on
+ * \return A reference to the unique pointer of the loaded shader.
+ */
+ const std::unique_ptr& Bind(KWin::EffectWindow *w, qreal scale, bool isTiled) const;
+
+ /**
+ * \brief Pop the shader from the stack of rendering.
+ * This needs to be called after each window is rendered.
+ */
void Unbind() const;
+
+ /**
+ * \return A reference to the unique pointer of the loaded shader.
+ */
std::unique_ptr& GetShader() { return m_shader; }
private:
+ /**
+ * \brief A pointer to the loaded shader used to assign the value of uniform variables.
+ */
std::unique_ptr m_shader;
+
+ /**
+ * \brief An instance of `ShaderManager` used to load shader from file and push/pop the shader for each render.
+ */
KWin::ShaderManager* m_manager;
- QPalette m_palette;
+
+ /**
+ * \brief Used only for its `palette()` function which holds the currently active highlight colors.
+ */
+ std::shared_ptr m_widget;
+
+ /**
+ * \brief Reference to `uniform vec2 windowSize;`
+ * Containing `window->frameGeometry().size()`
+ */
int m_shader_windowSize = 0;
+
+ /**
+ * \brief Reference to `uniform vec2 windowExpandedSize;`
+ * Containing `window->expandedGeometry().size()`
+ * \note When `expandedGeometry = frameGeometry`, it means there is no shadow.
+ */
int m_shader_windowExpandedSize = 0;
+
+ /**
+ * \brief Reference to `uniform vec2 windowTopLeft;`
+ * Containing the distance between the top-left of `expandedGeometry` and the top-left of `frameGeometry`.
+ * \note When `windowTopLeft = {0,0}`, it means `expandedGeometry = frameGeometry` and there is no shadow.
+ */
int m_shader_windowTopLeft = 0;
+
int m_shader_disableRoundedTile = 0;
+
+ /**
+ * \brief Reference to `uniform vec4 shadowColor;`
+ * Containing the RGBA of the shadow color specified in settings.
+ */
int m_shader_shadowColor = 0;
+
+ /**
+ * \brief Reference to `uniform float shadowSize;`
+ * Containing the shadow size specified in settings.
+ */
int m_shader_shadowSize = 0;
+
+ /**
+ * \brief Reference to `uniform float radius;`
+ * Containing the corner radius in pixels specified in settings.
+ */
int m_shader_radius = 0;
+
+ /**
+ * \brief Reference to `uniform vec4 outlineColor;`
+ * Containing the RGBA of the outline color specified in settings.
+ */
int m_shader_outlineColor = 0;
+
+ /**
+ * \brief Reference to `uniform float outlineThickness;`
+ * Containing the thickness of the outline in pixels specified in settings.
+ */
int m_shader_outlineThickness = 0;
+
+ /**
+ * \brief Reference to `uniform sampler2D front;`
+ * Containing the active texture. When assigned to zero, it will contain the painted contents of the window.
+ */
int m_shader_front = 0;
};
diff --git a/src/kcm/CMakeLists.txt b/src/kcm/CMakeLists.txt
index 83c0247..d812930 100644
--- a/src/kcm/CMakeLists.txt
+++ b/src/kcm/CMakeLists.txt
@@ -1,24 +1,27 @@
set(kcm_SRCS
+ ShapeCornersKCM.h
ShapeCornersKCM.cpp
plugin.cpp
)
kconfig_add_kcfg_files(kcm_SRCS ../ShapeCornersConfig.kcfgc)
-qt5_wrap_ui(kcm_SRCS ShapeCornersKCM.ui)
+if(${QT_MAJOR_VERSION} EQUAL 6)
+ qt6_wrap_ui(kcm_SRCS ShapeCornersKCM.ui)
+ qt6_add_dbus_interface(kcm_SRCS ${KWIN_EFFECTS_INTERFACE} kwineffects_interface)
+ kcoreaddons_add_plugin(kwin_shapecorners_config INSTALL_NAMESPACE "kwin/effects/configs" SOURCES ${kcm_SRCS})
-qt5_add_dbus_interface(kcm_SRCS ${KWIN_EFFECTS_INTERFACE} kwineffects_interface)
-
-add_library(kwin_shapecorners_config MODULE ${kcm_SRCS})
+ target_link_libraries(kwin_shapecorners_config
+ Qt${QT_MAJOR_VERSION}::CorePrivate
+ KF${QT_MAJOR_VERSION}::KCMUtils
+ )
+else()
+ qt5_wrap_ui(kcm_SRCS ShapeCornersKCM.ui)
+ qt5_add_dbus_interface(kcm_SRCS ${KWIN_EFFECTS_INTERFACE} kwineffects_interface)
+ kcoreaddons_add_plugin(kwin_shapecorners_config INSTALL_NAMESPACE "kwin/effects/configs" SOURCES ${kcm_SRCS})
+endif ()
target_link_libraries(kwin_shapecorners_config
- Qt5::Core
- Qt5::DBus
- Qt5::Gui
- KF5::ConfigWidgets
- KF5::ConfigGui
- KF5::GlobalAccel
- KF5::WindowSystem
+ Qt${QT_MAJOR_VERSION}::DBus
+ KF${QT_MAJOR_VERSION}::ConfigWidgets
)
-
-install(TARGETS kwin_shapecorners_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs)
\ No newline at end of file
diff --git a/src/kcm/ShapeCornersKCM.cpp b/src/kcm/ShapeCornersKCM.cpp
index 8bfdf72..b644cc2 100644
--- a/src/kcm/ShapeCornersKCM.cpp
+++ b/src/kcm/ShapeCornersKCM.cpp
@@ -1,18 +1,26 @@
+#include "ShapeCornersKCM.h"
+#include "ui_ShapeCornersKCM.h"
+#include "kwineffects_interface.h"
+#include "ShapeCornersConfig.h"
#include
#include
-#include
-#include "kwineffects_interface.h"
-#include "ShapeCornersKCM.h"
-
-#include
-
+#if (QT_VERSION_MAJOR >= 6)
+ShapeCornersKCM::ShapeCornersKCM(QObject* parent, const KPluginMetaData& args)
+ : KCModule(parent, args)
+ , ui(new Ui::Form)
+{
+ ui->setupUi(widget());
+ addConfig(ShapeCornersConfig::self(), widget());
+#else
ShapeCornersKCM::ShapeCornersKCM(QWidget* parent, const QVariantList& args)
: KCModule(parent, args)
, ui(new Ui::Form)
{
ui->setupUi(this);
addConfig(ShapeCornersConfig::self(), this);
+#endif
+
update_colors();
update_windows();
@@ -45,15 +53,22 @@ ShapeCornersKCM::ShapeCornersKCM(QWidget* parent, const QVariantList& args)
connect(ui->kcfg_ActiveShadowUsePalette, &QRadioButton::toggled, this, &ShapeCornersKCM::update_colors);
connect(ui->kcfg_InactiveShadowUsePalette, &QRadioButton::toggled, this, &ShapeCornersKCM::update_colors);
+ // It was expected that the Apply button would get enabled automatically as the gradient sliders move, but it doesn't.
+ // Maybe it is a bug on the KCM side. Need to check and delete these lines later.
+ connect(ui->kcfg_ActiveShadowAlpha, &KGradientSelector::sliderMoved, this, &ShapeCornersKCM::markAsChanged);
+ connect(ui->kcfg_InactiveShadowAlpha, &KGradientSelector::sliderMoved, this, &ShapeCornersKCM::markAsChanged);
+ connect(ui->kcfg_ActiveOutlineAlpha, &KGradientSelector::sliderMoved, this, &ShapeCornersKCM::markAsChanged);
+ connect(ui->kcfg_InactiveOutlineAlpha, &KGradientSelector::sliderMoved, this, &ShapeCornersKCM::markAsChanged);
+
connect(ui->refreshButton, &QPushButton::pressed, this, &ShapeCornersKCM::update_windows);
connect(ui->includeButton, &QPushButton::pressed, [=, this]() {
- auto s = ui->currentWindowList->currentItem();
- if (s && ui->InclusionList->findItems(s->text(), Qt::MatchExactly).empty())
+ if (const auto s = ui->currentWindowList->currentItem();
+ s && ui->InclusionList->findItems(s->text(), Qt::MatchExactly).empty())
ui->InclusionList->addItem(s->text());
});
connect(ui->excludeButton, &QPushButton::pressed, [=, this]() {
- auto s = ui->currentWindowList->currentItem();
- if (s && ui->ExclusionList->findItems(s->text(), Qt::MatchExactly).empty())
+ if (const auto s = ui->currentWindowList->currentItem();
+ s && ui->ExclusionList->findItems(s->text(), Qt::MatchExactly).empty())
ui->ExclusionList->addItem(s->text());
});
connect(ui->deleteIncludeButton, &QPushButton::pressed, [=, this]() {
@@ -77,14 +92,18 @@ ShapeCornersKCM::save()
ShapeCornersConfig::setExclusions(exclusions);
ShapeCornersConfig::self()->save();
KCModule::save();
+
+ const auto dbusName = QStringLiteral("kwin4_effect_shapecorners");
OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"),
QStringLiteral("/Effects"),
QDBusConnection::sessionBus());
- interface.reconfigureEffect(QStringLiteral("kwin4_effect_shapecorners"));
-}
+ interface.reconfigureEffect(dbusName);
-ShapeCornersKCM::~ShapeCornersKCM() {
- delete ui;
+ // It was expected that the Apply button would repaint the whole screen, but it doesn't.
+ // Even calling KWin::effects->addRepaintFull(); didn't do the trick.
+ // Maybe it is a bug on the KWin side. Need to check and delete these lines later.
+ interface.unloadEffect(dbusName);
+ interface.loadEffect(dbusName);
}
void ShapeCornersKCM::update_colors() {
@@ -113,23 +132,15 @@ void ShapeCornersKCM::update_colors() {
ui->kcfg_InactiveShadowAlpha->setSecondColor(color);
}
-void ShapeCornersKCM::update_windows() {
- QList windowList;
- ui->currentWindowList->clear();
-
- auto connection = QDBusConnection::sessionBus();
- if (connection.isConnected()) {
- QDBusInterface interface("org.kde.ShapeCorners", "/ShapeCornersEffect");
- if (interface.isValid()) {
- QDBusReply reply = interface.call("get_window_titles");
- if (reply.isValid())
- windowList = reply.value().split("\n");
- }
- }
+void ShapeCornersKCM::update_windows() const {
+ QStringList windowList;
+ if (const auto connection = QDBusConnection::sessionBus(); connection.isConnected())
+ if (QDBusInterface interface(QStringLiteral("org.kde.ShapeCorners"), QStringLiteral("/ShapeCornersEffect")); interface.isValid())
+ if (const QDBusReply reply = interface.call(QStringLiteral("get_window_titles")); reply.isValid())
+ windowList = reply.value().split(QStringLiteral("\n"));
- for (const auto& w: windowList)
- if (!w.isEmpty())
- ui->currentWindowList->addItem(w);
+ ui->currentWindowList->clear();
+ ui->currentWindowList->addItems(windowList);
}
void ShapeCornersKCM::load() {
diff --git a/src/kcm/ShapeCornersKCM.h b/src/kcm/ShapeCornersKCM.h
index fd71560..df06e99 100644
--- a/src/kcm/ShapeCornersKCM.h
+++ b/src/kcm/ShapeCornersKCM.h
@@ -1,22 +1,32 @@
-
+#pragma once
+
#include
-#include "ui_ShapeCornersKCM.h"
-#include "ShapeCornersConfig.h"
-class ShapeCornersKCM : public KCModule
+namespace Ui {
+ class Form;
+}
+
+class ShapeCornersKCM final: public KCModule
{
Q_OBJECT
public:
+#if (QT_VERSION_MAJOR >= 6)
+ explicit ShapeCornersKCM(QObject* parent, const KPluginMetaData& args);
+#else
explicit ShapeCornersKCM(QWidget* parent = nullptr, const QVariantList& args = QVariantList());
- ~ShapeCornersKCM() override;
+#endif
-public slots:
+public Q_SLOTS:
void defaults() override;
void load() override;
void save() override;
void update_colors();
- void update_windows();
+ void update_windows() const;
private:
- Ui::Form *ui;
+ std::shared_ptr ui;
+
+#if (QT_VERSION_MAJOR >= 6)
+ const QPalette& palette() { return widget()->palette(); };
+#endif
};
diff --git a/src/kcm/ShapeCornersKCM.ui b/src/kcm/ShapeCornersKCM.ui
index 725a9a8..8d5f62b 100644
--- a/src/kcm/ShapeCornersKCM.ui
+++ b/src/kcm/ShapeCornersKCM.ui
@@ -987,9 +987,28 @@
Inclusions && Exclusions
-
- -
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Include >
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
16777215
@@ -997,38 +1016,43 @@
- Excluded Windows:
+ List of Current Open Windows:
- -
-
-
- QAbstractItemView::NoEditTriggers
+
-
+
+
+
+ 0
+ 0
+
-
- false
+
+
+ 16777215
+ 20
+
-
-
- -
-
- Exclude >
+ Included Windows:
- -
-
-
- QAbstractItemView::NoEditTriggers
+
-
+
+
+
+ 0
+ 0
+
-
- false
+
+ <
- -
+
-
@@ -1041,8 +1065,14 @@
- -
-
+
-
+
+
+
+ 0
+ 0
+
+
QAbstractItemView::NoEditTriggers
@@ -1051,50 +1081,108 @@
- -
-
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 5
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 16777215
+ 20
+
+
+
+ Excluded Windows:
+
+
+
+ -
+
+
+ Maximized Windows
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
- Include >
+ Exclude >
-
+
+
+ 0
+ 0
+
+
<
- -
-
-
-
- 16777215
- 20
-
+
-
+
+
+
+ 0
+ 0
+
-
- List of Current Open Windows:
+
+ QAbstractItemView::NoEditTriggers
-
-
- -
-
-
- <
+
+ false
- -
-
-
-
- 16777215
- 20
-
+
-
+
+
+
+ 0
+ 0
+
-
- Included Windows:
+
+ QAbstractItemView::NoEditTriggers
+
+
+ false
diff --git a/src/kcm/plugin.cpp b/src/kcm/plugin.cpp
index fcfb002..aae6c9a 100644
--- a/src/kcm/plugin.cpp
+++ b/src/kcm/plugin.cpp
@@ -3,8 +3,12 @@
// KF5
#include
+#if (QT_VERSION_MAJOR >= 248)
+K_PLUGIN_CLASS(ShapeCornersKCM)
+#else
K_PLUGIN_FACTORY_WITH_JSON(ShapeCornersConfigFactory,
"metadata.json",
registerPlugin();)
+#endif
#include "plugin.moc"
\ No newline at end of file
diff --git a/src/options.kcfg b/src/options.kcfg
index 12b8d84..75c49c3 100644
--- a/src/options.kcfg
+++ b/src/options.kcfg
@@ -97,15 +97,15 @@
false
+
+
+
+
true
true
-
-
-
-
\ No newline at end of file
diff --git a/src/shaders/shapecorners.frag b/src/shaders/shapecorners.frag
new file mode 100644
index 0000000..7e34920
--- /dev/null
+++ b/src/shaders/shapecorners.frag
@@ -0,0 +1,167 @@
+#version 110
+
+uniform sampler2D front; // The painted contents of the window.
+uniform float radius; // The thickness of the outline in pixels specified in settings.
+uniform vec2 windowSize; // Containing `window->frameGeometry().size()`
+uniform vec2 windowExpandedSize; // Containing `window->expandedGeometry().size()`
+
+uniform vec2 windowTopLeft; /* Containing the distance between the top-left of `expandedGeometry` and
+ * the top-left of `frameGeometry`. When `windowTopLeft = {0,0}`, it means
+ * `expandedGeometry = frameGeometry` and there is no shadow. */
+
+uniform vec4 shadowColor; // The RGBA of the shadow color specified in settings.
+uniform float shadowSize; // The shadow size specified in settings.
+uniform vec4 outlineColor; // The RGBA of the outline color specified in settings.
+uniform float outlineThickness; // The thickness of the outline in pixels specified in settings.
+
+uniform vec4 modulation; // This variable is assigned and used by KWinEffects used for proper fading.
+uniform float saturation; // This variable is assigned and used by KWinEffects used for proper fading.
+
+varying vec2 texcoord0; // The XY location of the rendering pixel. Starting from {0.0, 0.0} to {1.0, 1.0}
+
+// Note: This version of GLSL uses the built-in variable `gl_FragColor` instead of `out vec4 fragColor;`
+
+vec2 tex_to_pixel(vec2 texcoord) {
+ return vec2(texcoord0.x * windowExpandedSize.x - windowTopLeft.x,
+ (1.0-texcoord0.y)* windowExpandedSize.y - windowTopLeft.y);
+}
+vec2 pixel_to_tex(vec2 pixelcoord) {
+ return vec2((pixelcoord.x + windowTopLeft.x) / windowExpandedSize.x,
+ 1.0-(pixelcoord.y + windowTopLeft.y) / windowExpandedSize.y);
+}
+bool isDrawingShadows() { return windowSize != windowExpandedSize && shadowColor.a > 0.0; }
+bool isDrawingOutline() {
+ vec2 one_edge = vec2(windowSize.x/2.0, 0.0);
+ return texture2D(front, pixel_to_tex(one_edge)).a > 0.5 &&
+ outlineColor.a > 0.0 && outlineThickness > 0.0;
+}
+
+float parametricBlend(float t) {
+ float sqt = t * t;
+ return sqt / (2.0 * (sqt - t) + 1.0);
+}
+
+/*
+ * \brief This function generates the shadow color based on the distance_from_center
+ * \param distance_from_center: Distance of the rendering point and the reference point that is being used for rounding corners.
+ * \return The RGBA color to be used for shadow.
+ */
+vec4 getShadowColor(float distance_from_center) {
+ if(!isDrawingShadows())
+ return vec4(0.0, 0.0, 0.0, 0.0);
+ float percent = -distance_from_center/shadowSize + 1.0;
+ percent = clamp(percent, 0.0, 1.0);
+ percent = parametricBlend(percent);
+ if (percent < 0.0)
+ return vec4(0.0, 0.0, 0.0, 0.0);
+ else
+ return vec4(shadowColor.rgb * shadowColor.a * percent, shadowColor.a * percent);
+}
+
+/*
+ * \brief This function is used to choose the pixel color based on its distance to the center input.
+ * \param coord0: The XY point
+ * \param tex: The RGBA color of the pixel in XY
+ * \param center: The origin XY point that is being used as a reference for rounding corners.
+ * \return The RGBA color to be used instead of tex input.
+ */
+vec4 shapeCorner(vec2 coord0, vec4 tex, vec2 start, float angle) {
+ bool diagonal = abs(cos(angle)) > 0.1 && abs(sin(angle)) > 0.1;
+ vec2 center;
+ float distance_from_center;
+ vec4 c;
+ float r;
+ if (disableRoundedTile) {
+ r = outlineThickness;
+ center = start + r * vec2(cos(angle), sin(angle));
+ distance_from_center = distance(coord0, center);
+ c = tex;
+ }
+ else {
+ r = radius;
+ center = start + radius * (diagonal? sqrt(2.0) : 1.0) * vec2(cos(angle), sin(angle));
+ distance_from_center = distance(coord0, center);
+ c = getShadowColor(distance_from_center);
+ }
+
+ if(isDrawingOutline()) {
+ vec4 outlineOverlay = vec4(mix(tex.rgb, outlineColor.rgb, outlineColor.a), tex.a);
+
+ if (distance_from_center < r - outlineThickness + 0.5) {
+ // from the window to the outline
+ float antialiasing = clamp(r-outlineThickness+0.5-distance_from_center, 0.0, 1.0);
+ return mix(outlineOverlay, tex, antialiasing);
+ }
+ else {
+ // from the outline to the shadow
+ float antialiasing = clamp(distance_from_center-r+0.5, 0.0, 1.0);
+ return mix(outlineOverlay, c, antialiasing);
+ }
+ }
+ else {
+ // from the window to the shadow
+ float antialiasing = clamp(r-distance_from_center, 0.0, 1.0);
+ return mix(c, tex, antialiasing);
+ }
+}
+
+void main(void)
+{
+ vec4 tex = texture2D(front, texcoord0); // The RGBA of the XY pixel for the painted window
+ if(tex.a == 0.0) {
+ gl_FragColor = tex;
+ return;
+ }
+
+ float r = disableRoundedTile? outlineThickness: radius;
+
+ /* Since `texcoord0` is ranging from {0.0, 0.0} to {1.0, 1.0} is not pixel intuitive,
+ * I am changing the range to become from {0.0, 0.0} to {width, height}
+ * in a way that {0,0} is the top-left of the window and not its shadow.
+ * This means areas with negative numbers and areas beyond windowSize is considered part of the shadow. */
+ vec2 coord0 = tex_to_pixel(texcoord0);
+
+ /*
+ Split the window into these sections below. They will have a different center of circle for rounding.
+
+ TL T T TR
+ L x x R
+ L x x R
+ BL B B BR
+ */
+ if (coord0.y < r) {
+ if (coord0.x < r)
+ tex = shapeCorner(coord0, tex, vec2(0.0, 0.0), radians(45.0)); // Section TL
+ else if (coord0.x > windowSize.x - r)
+ tex = shapeCorner(coord0, tex, vec2(windowSize.x, 0.0), radians(135.0)); // Section TR
+ else if (coord0.y < outlineThickness)
+ tex = shapeCorner(coord0, tex, vec2(coord0.x, 0.0), radians(90.0)); // Section T
+ }
+ else if (coord0.y > windowSize.y - r) {
+ if (coord0.x < r)
+ tex = shapeCorner(coord0, tex, vec2(0.0, windowSize.y), radians(315.0)); // Section BL
+ else if (coord0.x > windowSize.x - r)
+ tex = shapeCorner(coord0, tex, vec2(windowSize.x, windowSize.y), radians(225.0)); // Section BR
+ else if (coord0.y > windowSize.y - outlineThickness)
+ tex = shapeCorner(coord0, tex, vec2(coord0.x, windowSize.y), radians(270.0)); // Section B
+ }
+ else {
+ if (coord0.x < r)
+ tex = shapeCorner(coord0, tex, vec2(0.0, coord0.y), radians(0.0)); // Section L
+ else if (coord0.x > windowSize.x - r)
+ tex = shapeCorner(coord0, tex, vec2(windowSize.x, coord0.y), radians(180.0)); // Section R
+
+ // For section x, the tex is not changing
+ }
+
+ // Apply the saturation and modulation. This is essential for proper fades in other KWin effects.
+ if (saturation != 1.0) {
+ vec3 desaturated = tex.rgb * vec3( 0.30, 0.59, 0.11 );
+ desaturated = vec3( dot( desaturated, tex.rgb ));
+ tex.rgb = tex.rgb * vec3( saturation ) + desaturated * vec3( 1.0 - saturation );
+ }
+ tex *= modulation;
+
+ // Send to output
+ gl_FragColor = tex;
+}
diff --git a/src/shaders/shapecorners_core.frag b/src/shaders/shapecorners_core.frag
new file mode 100644
index 0000000..33ef88c
--- /dev/null
+++ b/src/shaders/shapecorners_core.frag
@@ -0,0 +1,167 @@
+#version 140
+
+uniform sampler2D front; // The painted contents of the window.
+uniform float radius; // The thickness of the outline in pixels specified in settings.
+uniform vec2 windowSize; // Containing `window->frameGeometry().size()`
+uniform vec2 windowExpandedSize; // Containing `window->expandedGeometry().size()`
+uniform bool disableRoundedTile;
+
+uniform vec2 windowTopLeft; /* The distance between the top-left of `expandedGeometry` and
+ * the top-left of `frameGeometry`. When `windowTopLeft = {0,0}`, it means
+ * `expandedGeometry = frameGeometry` and there is no shadow. */
+
+uniform vec4 shadowColor; // The RGBA of the shadow color specified in settings.
+uniform float shadowSize; // The shadow size specified in settings.
+uniform vec4 outlineColor; // The RGBA of the outline color specified in settings.
+uniform float outlineThickness; // The thickness of the outline in pixels specified in settings.
+
+uniform vec4 modulation; // This variable is assigned and used by KWinEffects used for proper fading.
+uniform float saturation; // This variable is assigned and used by KWinEffects used for proper fading.
+
+in vec2 texcoord0; // The XY location of the rendering pixel. Starting from {0.0, 0.0} to {1.0, 1.0}
+out vec4 fragColor; // The RGBA color that can be rendered
+
+vec2 tex_to_pixel(vec2 texcoord) {
+ return vec2(texcoord0.x * windowExpandedSize.x - windowTopLeft.x,
+ (1.0-texcoord0.y)* windowExpandedSize.y - windowTopLeft.y);
+}
+vec2 pixel_to_tex(vec2 pixelcoord) {
+ return vec2((pixelcoord.x + windowTopLeft.x) / windowExpandedSize.x,
+ 1.0-(pixelcoord.y + windowTopLeft.y) / windowExpandedSize.y);
+}
+bool isDrawingShadows() { return windowSize != windowExpandedSize && shadowColor.a > 0.0; }
+bool isDrawingOutline() {
+ vec2 one_edge = vec2(windowSize.x/2.0, 0.0);
+ return texture2D(front, pixel_to_tex(one_edge)).a > 0.5 &&
+ outlineColor.a > 0.0 && outlineThickness > 0.0;
+}
+
+float parametricBlend(float t) {
+ float sqt = t * t;
+ return sqt / (2.0 * (sqt - t) + 1.0);
+}
+
+/*
+ * \brief This function generates the shadow color based on the distance_from_center
+ * \param distance_from_center: Distance of the rendering point and the reference point that is being used for rounding corners.
+ * \return The RGBA color to be used for shadow.
+ */
+vec4 getShadowColor(float distance_from_center) {
+ if(!isDrawingShadows())
+ return vec4(0,0,0,0);
+ float percent = -distance_from_center/shadowSize + 1;
+ percent = clamp(percent, 0, 1);
+ percent = parametricBlend(percent);
+ if(percent < 0)
+ return vec4(0,0,0,0);
+ else
+ return vec4(shadowColor.rgb * shadowColor.a * percent, shadowColor.a * percent);
+}
+
+/*
+ * \brief This function is used to choose the pixel color based on its distance to the center input.
+ * \param coord0: The XY point
+ * \param tex: The RGBA color of the pixel in XY
+ * \param center: The origin XY point that is being used as a reference for rounding corners.
+ * \return The RGBA color to be used instead of tex input.
+ */
+vec4 shapeCorner(vec2 coord0, vec4 tex, vec2 start, float angle) {
+ bool diagonal = abs(cos(angle)) > 0.1 && abs(sin(angle)) > 0.1;
+ vec2 center;
+ float distance_from_center;
+ vec4 c;
+ float r;
+ if (disableRoundedTile) {
+ r = outlineThickness;
+ center = start + r * vec2(cos(angle), sin(angle));
+ distance_from_center = distance(coord0, center);
+ c = tex;
+ }
+ else {
+ r = radius;
+ center = start + radius * (diagonal? sqrt(2.0) : 1.0) * vec2(cos(angle), sin(angle));
+ distance_from_center = distance(coord0, center);
+ c = getShadowColor(distance_from_center);
+ }
+
+ if(isDrawingOutline()) {
+ vec4 outlineOverlay = vec4(mix(tex.rgb, outlineColor.rgb, outlineColor.a), tex.a);
+
+ if (distance_from_center < r - outlineThickness + 0.5) {
+ // from the window to the outline
+ float antialiasing = clamp(r-outlineThickness+0.5-distance_from_center, 0.0, 1.0);
+ return mix(outlineOverlay, tex, antialiasing);
+ }
+ else {
+ // from the outline to the shadow
+ float antialiasing = clamp(distance_from_center-r+0.5, 0.0, 1.0);
+ return mix(outlineOverlay, c, antialiasing);
+ }
+ }
+ else {
+ // from the window to the shadow
+ float antialiasing = clamp(r-distance_from_center, 0.0, 1.0);
+ return mix(c, tex, antialiasing);
+ }
+}
+
+void main(void)
+{
+ vec4 tex = texture(front, texcoord0); // The RGBA of the XY pixel for the painted window
+ if(tex.a == 0.0) {
+ fragColor = tex;
+ return;
+ }
+
+ float r = disableRoundedTile? outlineThickness: radius;
+
+ /* Since `texcoord0` is ranging from {0.0, 0.0} to {1.0, 1.0} is not pixel intuitive,
+ * I am changing the range to become from {0.0, 0.0} to {width, height}
+ * in a way that {0,0} is the top-left of the window and not its shadow.
+ * This means areas with negative numbers and areas beyond windowSize is considered part of the shadow. */
+ vec2 coord0 = tex_to_pixel(texcoord0);
+
+ /*
+ Split the window into these sections below. They will have a different center of circle for rounding.
+
+ TL T T TR
+ L x x R
+ L x x R
+ BL B B BR
+ */
+ if (coord0.y < r) {
+ if (coord0.x < r)
+ tex = shapeCorner(coord0, tex, vec2(0, 0), radians(45)); // Section TL
+ else if (coord0.x > windowSize.x - r)
+ tex = shapeCorner(coord0, tex, vec2(windowSize.x, 0), radians(135)); // Section TR
+ else if (coord0.y < outlineThickness)
+ tex = shapeCorner(coord0, tex, vec2(coord0.x, 0), radians(90)); // Section T
+ }
+ else if (coord0.y > windowSize.y - r) {
+ if (coord0.x < r)
+ tex = shapeCorner(coord0, tex, vec2(0, windowSize.y), radians(315)); // Section BL
+ else if (coord0.x > windowSize.x - r)
+ tex = shapeCorner(coord0, tex, vec2(windowSize.x, windowSize.y), radians(225)); // Section BR
+ else if (coord0.y > windowSize.y - outlineThickness)
+ tex = shapeCorner(coord0, tex, vec2(coord0.x, windowSize.y), radians(270)); // Section B
+ }
+ else {
+ if (coord0.x < r)
+ tex = shapeCorner(coord0, tex, vec2(0, coord0.y), radians(0)); // Section L
+ else if (coord0.x > windowSize.x - r)
+ tex = shapeCorner(coord0, tex, vec2(windowSize.x, coord0.y), radians(180)); // Section R
+
+ // For section x, the tex is not changing
+ }
+
+ // Apply the saturation and modulation. This is essential for proper fades in other KWin effects.
+ if (saturation != 1.0) {
+ vec3 desaturated = tex.rgb * vec3( 0.30, 0.59, 0.11 );
+ desaturated = vec3( dot( desaturated, tex.rgb ));
+ tex.rgb = tex.rgb * vec3( saturation ) + desaturated * vec3( 1.0 - saturation );
+ }
+ tex *= modulation;
+
+ // Send to output
+ fragColor = tex;
+}
diff --git a/src/shaders_110/shapecorners.frag b/src/shaders_110/shapecorners.frag
deleted file mode 100644
index f2572a9..0000000
--- a/src/shaders_110/shapecorners.frag
+++ /dev/null
@@ -1,107 +0,0 @@
-#version 110
-
-uniform sampler2D front;
-uniform float radius;
-uniform bool disableRoundedTile;
-uniform vec2 windowSize;
-uniform vec2 windowExpandedSize;
-uniform vec2 windowTopLeft;
-uniform vec4 shadowColor;
-uniform float shadowSize;
-uniform vec4 outlineColor;
-uniform float outlineThickness;
-uniform vec4 modulation;
-uniform float saturation;
-
-varying vec2 texcoord0;
-
-bool isDrawingShadows() { return windowSize != windowExpandedSize && shadowColor.a > 0.0; }
-bool isDrawingOutline() { return outlineColor.a > 0.0 && outlineThickness > 0.0; }
-
-vec4 shadowCorner(float distance_from_center) {
- float percent = -distance_from_center/shadowSize + 1.0;
- if (percent < 0.0)
- return vec4(0.0, 0.0, 0.0, 0.0);
- else
- return vec4(shadowColor.rgb * shadowColor.a * percent, shadowColor.a * percent);
-}
-
-vec4 shapeCorner(vec2 coord0, vec4 tex, vec2 start, float angle) {
- bool diagonal = abs(cos(angle)) > 0.1 && abs(sin(angle)) > 0.1;
-
- vec2 center;
- float distance_from_center;
- vec4 c;
- float r;
-
- if (disableRoundedTile) {
- r = outlineThickness;
- center = start + r * vec2(cos(angle), sin(angle));
- distance_from_center = distance(coord0, center);
- c = tex;
- }
- else {
- r = radius;
- center = start + radius * (diagonal? sqrt(2.0) : 1.0) * vec2(cos(angle), sin(angle));
- distance_from_center = distance(coord0, center);
- c = isDrawingShadows() ? shadowCorner(distance_from_center) : vec4(0.0, 0.0, 0.0, 0.0);
- }
-
- if(isDrawingOutline()) {
- vec4 outlineOverlay = vec4(mix(tex.rgb, outlineColor.rgb, outlineColor.a), 1.0);
-
- if (distance_from_center < r - outlineThickness+0.5) {
- float antialiasing = clamp(r-outlineThickness+0.5-distance_from_center, 0.0, 1.0);
- return mix(outlineOverlay, tex, antialiasing);
- }
- else {
- float antialiasing = clamp(distance_from_center-r+0.5, 0.0, 1.0);
- return mix(outlineOverlay, c, antialiasing);
- }
- }
- else {
- float antialiasing = clamp(r-distance_from_center, 0.0, 1.0);
- return mix(c, tex, antialiasing);
- }
-}
-
-void main(void)
-{
- vec4 tex = texture2D(front, texcoord0);
- vec2 coord0 = vec2(texcoord0.x * windowExpandedSize.x - windowTopLeft.x,
- (1.0-texcoord0.y)* windowExpandedSize.y - windowTopLeft.y);
-
- float r = disableRoundedTile? outlineThickness: radius;
-
- if (coord0.y < r) {
- if (coord0.x < r)
- tex = shapeCorner(coord0, tex, vec2(0.0, 0.0), radians(45.0));
- else if (coord0.x > windowSize.x - r)
- tex = shapeCorner(coord0, tex, vec2(windowSize.x, 0.0), radians(135.0));
- else if (coord0.y < outlineThickness)
- tex = shapeCorner(coord0, tex, vec2(coord0.x, 0.0), radians(90.0));
- }
- else if (coord0.y > windowSize.y - r) {
- if (coord0.x < r)
- tex = shapeCorner(coord0, tex, vec2(0.0, windowSize.y), radians(315.0));
- else if (coord0.x > windowSize.x - r)
- tex = shapeCorner(coord0, tex, vec2(windowSize.x, windowSize.y), radians(225.0));
- else if (coord0.y > windowSize.y - outlineThickness)
- tex = shapeCorner(coord0, tex, vec2(coord0.x, windowSize.y), radians(270.0));
- }
- else {
- if (coord0.x < radius)
- tex = shapeCorner(coord0, tex, vec2(0.0, coord0.y), radians(0.0));
- else if (coord0.x > windowSize.x - radius)
- tex = shapeCorner(coord0, tex, vec2(windowSize.x, coord0.y), radians(180.0));
- }
-
- if (saturation != 1.0) {
- vec3 desaturated = tex.rgb * vec3( 0.30, 0.59, 0.11 );
- desaturated = vec3( dot( desaturated, tex.rgb ));
- tex.rgb = tex.rgb * vec3( saturation ) + desaturated * vec3( 1.0 - saturation );
- }
- tex *= modulation;
-
- gl_FragColor = tex;
-}
diff --git a/src/shaders_140/shapecorners.frag b/src/shaders_140/shapecorners.frag
deleted file mode 100644
index 41df6c5..0000000
--- a/src/shaders_140/shapecorners.frag
+++ /dev/null
@@ -1,108 +0,0 @@
-#version 140
-
-uniform sampler2D front;
-uniform float radius;
-uniform bool disableRoundedTile;
-uniform vec2 windowSize;
-uniform vec2 windowExpandedSize;
-uniform vec2 windowTopLeft;
-uniform vec4 shadowColor;
-uniform float shadowSize;
-uniform vec4 outlineColor;
-uniform float outlineThickness;
-uniform vec4 modulation;
-uniform float saturation;
-
-in vec2 texcoord0;
-out vec4 fragColor;
-
-bool isDrawingShadows() { return windowSize != windowExpandedSize && shadowColor.a > 0.0; }
-bool isDrawingOutline() { return outlineColor.a > 0.0 && outlineThickness > 0.0; }
-
-vec4 shadowCorner(float distance_from_center) {
- float percent = -distance_from_center/shadowSize + 1;
- if(percent < 0)
- return vec4(0,0,0,0);
- else
- return vec4(shadowColor.rgb * shadowColor.a * percent, shadowColor.a * percent);
-}
-
-vec4 shapeCorner(vec2 coord0, vec4 tex, vec2 start, float angle) {
- bool diagonal = abs(cos(angle)) > 0.1 && abs(sin(angle)) > 0.1;
-
- vec2 center;
- float distance_from_center;
- vec4 c;
- float r;
-
- if (disableRoundedTile) {
- r = outlineThickness;
- center = start + r * vec2(cos(angle), sin(angle));
- distance_from_center = distance(coord0, center);
- c = tex;
- }
- else {
- r = radius;
- center = start + radius * (diagonal? sqrt(2.0) : 1.0) * vec2(cos(angle), sin(angle));
- distance_from_center = distance(coord0, center);
- c = isDrawingShadows() ? shadowCorner(distance_from_center) : vec4(0.0, 0.0, 0.0, 0.0);
- }
-
- if(isDrawingOutline()) {
- vec4 outlineOverlay = vec4(mix(tex.rgb, outlineColor.rgb, outlineColor.a), 1.0);
-
- if (distance_from_center < r - outlineThickness+0.5) {
- float antialiasing = clamp(r-outlineThickness+0.5-distance_from_center, 0.0, 1.0);
- return mix(outlineOverlay, tex, antialiasing);
- }
- else {
- float antialiasing = clamp(distance_from_center-r+0.5, 0.0, 1.0);
- return mix(outlineOverlay, c, antialiasing);
- }
- }
- else {
- float antialiasing = clamp(r-distance_from_center, 0.0, 1.0);
- return mix(c, tex, antialiasing);
- }
-}
-
-void main(void)
-{
- vec4 tex = texture(front, texcoord0);
- vec2 coord0 = vec2(texcoord0.x * windowExpandedSize.x - windowTopLeft.x,
- (1-texcoord0.y)* windowExpandedSize.y - windowTopLeft.y);
-
- float r = disableRoundedTile? outlineThickness: radius;
-
- if (coord0.y < r) {
- if (coord0.x < r)
- tex = shapeCorner(coord0, tex, vec2(0, 0), radians(45));
- else if (coord0.x > windowSize.x - r)
- tex = shapeCorner(coord0, tex, vec2(windowSize.x, 0), radians(135));
- else if (coord0.y < outlineThickness)
- tex = shapeCorner(coord0, tex, vec2(coord0.x, 0), radians(90));
- }
- else if (coord0.y > windowSize.y - r) {
- if (coord0.x < r)
- tex = shapeCorner(coord0, tex, vec2(0, windowSize.y), radians(315));
- else if (coord0.x > windowSize.x - r)
- tex = shapeCorner(coord0, tex, vec2(windowSize.x, windowSize.y), radians(225));
- else if (coord0.y > windowSize.y - outlineThickness)
- tex = shapeCorner(coord0, tex, vec2(coord0.x, windowSize.y), radians(270));
- }
- else {
- if (coord0.x < radius)
- tex = shapeCorner(coord0, tex, vec2(0, coord0.y), radians(0));
- else if (coord0.x > windowSize.x - radius)
- tex = shapeCorner(coord0, tex, vec2(windowSize.x, coord0.y), radians(180));
- }
-
- if (saturation != 1.0) {
- vec3 desaturated = tex.rgb * vec3( 0.30, 0.59, 0.11 );
- desaturated = vec3( dot( desaturated, tex.rgb ));
- tex.rgb = tex.rgb * vec3( saturation ) + desaturated * vec3( 1.0 - saturation );
- }
- tex *= modulation;
-
- fragColor = tex;
-}
diff --git a/tools/autorun-test-install.sh b/tools/autorun-test-install.sh
new file mode 100644
index 0000000..ddb90ed
--- /dev/null
+++ b/tools/autorun-test-install.sh
@@ -0,0 +1,6 @@
+AUTOSTART_FILE=~/.config/autostart/test-install-kde-rounded-corners.desktop
+GIT_PATH="$(dirname "$(pwd)")"
+mkdir -p ~/.config/autostart
+cp "${GIT_PATH}"/tools/test-install.desktop ${AUTOSTART_FILE}
+sed -i -e "s|Exec=|Exec=sh ${GIT_PATH}/|g" ${AUTOSTART_FILE}
+sed -i -e "s|Path=|Path=${GIT_PATH}|g" ${AUTOSTART_FILE}
\ No newline at end of file
diff --git a/tools/isSupported.sh b/tools/isSupported.sh
new file mode 100644
index 0000000..83934aa
--- /dev/null
+++ b/tools/isSupported.sh
@@ -0,0 +1,2 @@
+dbus-send --dest=org.kde.KWin --print-reply /Effects \
+ org.kde.kwin.Effects.isEffectSupported string:kwin4_effect_shapecorners | awk 'NR==2 {print $2}'
\ No newline at end of file
diff --git a/tools/load.sh b/tools/load.sh
new file mode 100644
index 0000000..9129596
--- /dev/null
+++ b/tools/load.sh
@@ -0,0 +1,2 @@
+dbus-send --dest=org.kde.KWin --print-reply /Effects \
+ org.kde.kwin.Effects.loadEffect string:kwin4_effect_shapecorners | awk 'NR==2 {print $2}'
\ No newline at end of file
diff --git a/tools/test-install.desktop b/tools/test-install.desktop
new file mode 100644
index 0000000..e30e2ea
--- /dev/null
+++ b/tools/test-install.desktop
@@ -0,0 +1,14 @@
+[Desktop Entry]
+Comment=
+Exec=tools/test-install.sh
+GenericName=
+MimeType=
+Name=Test & Install KDE-Rounded-Corners
+NoDisplay=false
+Path=build/
+StartupNotify=true
+Terminal=false
+TerminalOptions=
+Type=Application
+X-KDE-SubstituteUID=false
+X-KDE-Username=
diff --git a/tools/test-install.sh b/tools/test-install.sh
new file mode 100644
index 0000000..20da1a0
--- /dev/null
+++ b/tools/test-install.sh
@@ -0,0 +1,36 @@
+if ctest > /dev/null; then
+ echo "KDE-Rounded-Corners is supported by KWin and doesn't need re-installation."
+else
+ kdialog --msgbox "KDE-Rounded-Corners is not supported by KWin anymore.\n\nThis can probably be for an update.\nWe will now rebuild and reinstall the effect."
+ make clean
+ cmake --build . -j &
+ pid=$!
+
+ p=$(kdialog --progressbar "Building KDE-Rounded-Corners...")
+ qdbus $p showCancelButton false
+
+ # Loop until the cmake --build process is complete
+ while kill -0 $pid 2>/dev/null; do
+ count=$(( $(tail -n 1 CMakeFiles/Progress/count.txt 2>/dev/null) + 2))
+ if [ "$count" -gt "0" ]; then
+ value=$(find CMakeFiles/Progress/ | wc -l)
+ echo $value $count
+ qdbus $p Set "" value "$value"
+ qdbus $p Set "" maximum "$count"
+ fi
+
+ # Sleep for a short duration to avoid excessive CPU usage
+ sleep 0.1
+ done
+ qdbus $p close
+
+
+ kdialog --password "Enter password to install KDE-Rounded-Corners: " | sudo -S cmake --install .
+
+ sh ../tools/load.sh
+ if ctest > /dev/null; then
+ kdialog --msgbox "KDE-Rounded-Corners is now installed and loaded."
+ else
+ kdialog --error "The installation was not successful.\nSee logs by compiling manually."
+ fi
+fi
\ No newline at end of file
diff --git a/tools/unload.sh b/tools/unload.sh
new file mode 100644
index 0000000..54874fc
--- /dev/null
+++ b/tools/unload.sh
@@ -0,0 +1,2 @@
+dbus-send --dest=org.kde.KWin --print-reply /Effects \
+ org.kde.kwin.Effects.unloadEffect string:kwin4_effect_shapecorners > /dev/null