Add Rounded Window plugin

pull/3/head
cutefishd 4 years ago
parent 748ce1a88c
commit 73459ffd95

@ -26,3 +26,4 @@ endif()
# add_subdirectory(blur)
add_subdirectory(decoration)
add_subdirectory(roundedwindow)

@ -173,6 +173,7 @@ void Decoration::init()
void Decoration::reconfigure()
{
recalculateBorders();
updateResizeBorders();
updateShadow();
}
@ -202,11 +203,10 @@ void Decoration::updateResizeBorders()
{
QMargins borders;
const int extender = settings()->largeSpacing();
borders.setLeft(extender);
borders.setTop(extender);
borders.setRight(extender);
borders.setBottom(extender);
borders.setLeft(5);
borders.setTop(5);
borders.setRight(5);
borders.setBottom(5);
setResizeOnlyBorders(borders);
}
@ -261,7 +261,8 @@ void Decoration::updateShadow()
g_shadowSize = 70;
g_shadowStrength = 30;
g_shadowColor = Qt::black;
const int shadowOverlap = m_frameRadius;
const int frameRadius = 12;
const int shadowOverlap = frameRadius;
// const int shadowOffset = qMax(6 * g_shadowSize / 16, shadowOverlap * 2);
const int shadowOffset = shadowOverlap;
@ -304,13 +305,13 @@ void Decoration::updateShadow()
painter.setPen( gradientStopColor(g_shadowColor, g_shadowStrength * 0.5));
painter.setBrush(Qt::NoBrush);
painter.drawRoundedRect(innerRect, -0.5 + m_frameRadius, -0.5 + m_frameRadius);
painter.drawRoundedRect(innerRect, -0.5 + frameRadius, -0.5 + frameRadius);
// mask out inner rect
painter.setPen(Qt::NoPen);
painter.setBrush(Qt::black);
painter.setCompositionMode(QPainter::CompositionMode_DestinationOut);
painter.drawRoundedRect(innerRect, 0.5 + m_frameRadius, 0.5 + m_frameRadius);
painter.drawRoundedRect(innerRect, 0.5 + frameRadius, 0.5 + frameRadius);
painter.end();
g_sShadow = QSharedPointer<KDecoration2::DecorationShadow>::create();
@ -386,31 +387,12 @@ void Decoration::paintFrameBackground(QPainter *painter, const QRect &repaintReg
painter->fillRect(rect(), Qt::transparent);
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::NoPen);
// painter->setBrush(decoratedClient->color(
// decoratedClient->isActive()
// ? KDecoration2::ColorGroup::Active
// : KDecoration2::ColorGroup::Inactive,
// KDecoration2::ColorRole::Frame));
// painter->setClipRect(0, borderTop(), size().width(), size().height() - borderTop(), Qt::IntersectClip);
// painter->drawRect(rect());
painter->restore();
}
QColor Decoration::titleBarBackgroundColor() const
{
return darkMode() ? m_titleBarBgDarkColor : m_titleBarBgColor;
// const auto *decoratedClient = client().toStrongRef().data();
// const auto group = decoratedClient->isActive()
// ? KDecoration2::ColorGroup::Active
// : KDecoration2::ColorGroup::Inactive;
// const qreal opacity = decoratedClient->isActive()
// ? s_titleBarOpacityActive
// : s_titleBarOpacityInactive;
// QColor color = decoratedClient->color(group, KDecoration2::ColorRole::TitleBar);
// color.setAlphaF(opacity);
// return color;
}
QColor Decoration::titleBarForegroundColor() const
@ -437,10 +419,8 @@ void Decoration::paintTitleBarBackground(QPainter *painter, const QRect &repaint
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::NoPen);
// painter->setBrush(titleBarBackgroundColor());
painter->setBrush(Qt::red);
painter->drawRoundedRect(QRect(0, 0, decoratedClient->width(), titleBarHeight()), 6, 6);
// painter->drawRect(QRect(0, 0, decoratedClient->width(), titleBarHeight()));
painter->restore();
}

@ -90,7 +90,7 @@ private:
private:
int m_titleBarHeight = 38;
int m_frameRadius = 10;
int m_frameRadius = 0;
QColor m_titleBarBgColor = QColor(255, 255, 255, 255);
QColor m_titleBarFgColor = QColor(56, 56, 56, 255);
QColor m_unfocusedFgColor = QColor(127, 127, 127, 255);

@ -0,0 +1,66 @@
find_package(Qt5 CONFIG REQUIRED COMPONENTS
Gui
Core
DBus
UiTools
Widgets
X11Extras
OpenGL
Network
Xml
)
find_package(KF5CoreAddons)
find_package(KF5Config)
find_package(KF5WindowSystem)
include_directories(${Qt5Widgets_INCLUDE_DIRS} ${Qt5X11Extras_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5OpenGL_INCLUDE_DIRS} ${Qt5Xml_INCLUDE_DIRS})
add_definitions(${Qt5Widgets_DEFINITIONS})
find_path(EFFECTS_H kwineffects.h PATH_SUFFIXES kf5)
if (EFFECTS_H)
include_directories(${EFFECTS_H})
else (EFFECTS_H)
message(STATUS "didnt find kwineffects.h, not building effects")
endif (EFFECTS_H)
find_library(KWIN_EFFECTS NAMES kwineffects PATH_SUFFIXES kf5)
find_library(KWIN_GLUTILS NAMES kwinglutils PATH_SUFFIXES kf5)
find_library(OPENGL NAMES GL)
if (NOT KWIN_EFFECTS)
message(STATUS "didnt find kwineffects lib, not building effects")
endif (NOT KWIN_EFFECTS)
if (NOT KWIN_GLUTILS)
message(STATUS "didnt find kwin glutils lib, not building effects")
endif (NOT KWIN_GLUTILS)
if (NOT OPENGL)
message(STATUS "didnt find opengl, not building effects")
endif (NOT OPENGL)
if (NOT EFFECTS_H OR NOT KWIN_GLUTILS OR NOT KWIN_EFFECTS OR NOT OPENGL)
message(FATAL_ERROR "cant continue")
endif (NOT EFFECTS_H OR NOT KWIN_GLUTILS OR NOT KWIN_EFFECTS OR NOT OPENGL)
add_library(roundedwindow MODULE roundedwindow.cpp resources.qrc)
target_link_libraries(roundedwindow
PUBLIC
Qt5::Core
Qt5::Gui
Qt5::DBus
${KWIN_EFFECTS}
${KWIN_GLUTILS}
epoxy
GL
PRIVATE
KF5::CoreAddons
KF5::ConfigCore
KF5::WindowSystem
)
install (TARGETS roundedwindow
DESTINATION ${QT_PLUGINS_DIR}/kwin/effects/plugins)

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>shaders.frag.110</file>
<file>shaders.frag.140</file>
</qresource>
</RCC>

@ -0,0 +1,231 @@
/*
* Copyright © 2021 Reven Martin <revenmartin@gmail.com>
* Copyright © 2015 Robert Metsäranta <therealestrob@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. if not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "roundedwindow.h"
// Qt
#include <QFile>
#include <QPainter>
// KWin
#include <kwinglplatform.h>
#include <kwinglutils.h>
KWIN_EFFECT_FACTORY_SUPPORTED_ENABLED(RoundedWindowFactory,
RoundedWindow,
"roundedwindow.json",
return RoundedWindow::supported();,
return RoundedWindow::enabledByDefault();)
RoundedWindow::RoundedWindow()
: KWin::Effect()
, m_shader(nullptr)
, m_frameRadius(12)
, m_corner(m_frameRadius, m_frameRadius)
{
QString versionStr = "110";
#ifdef KWIN_HAVE_OPENGLES
const qint64 coreVersionNumber = kVersionNumber(3, 0);
#else
const qint64 version = KWin::kVersionNumber(1, 40);
#endif
if (KWin::GLPlatform::instance()->glslVersion() >= version)
versionStr = "140";
QFile file(QString(":/shaders.frag.%1").arg(versionStr));
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "RoundedWindow: cannot open " + file.fileName();
}
m_shader = KWin::ShaderManager::instance()->generateCustomShader(KWin::ShaderTrait::MapTexture, QByteArray(), file.readAll());
file.close();
if (m_shader->isValid()) {
const int sampler = m_shader->uniformLocation("sampler");
const int corner = m_shader->uniformLocation("corner");
KWin::ShaderManager::instance()->pushShader(m_shader);
m_shader->setUniform(corner, 1);
m_shader->setUniform(sampler, 0);
KWin::ShaderManager::instance()->popShader();
for (int i = 0; i < NTex; ++i) {
m_tex[i] = 0;
m_rect[i] = 0;
}
genMasks();
genRect();
} else {
qDebug() << "RoundedWindow: no valid shaders found!";
deleteLater();
}
}
RoundedWindow::~RoundedWindow()
{
}
bool RoundedWindow::supported()
{
return KWin::effects->isOpenGLCompositing() && KWin::GLRenderTarget::supported();
}
bool RoundedWindow::enabledByDefault()
{
return supported();
}
bool RoundedWindow::hasShadow(KWin::WindowQuadList &qds)
{
for (int i = 0; i < qds.count(); ++i)
if (qds.at(i).type() == KWin::WindowQuadShadow)
return true;
return false;
}
void RoundedWindow::paintWindow(KWin::EffectWindow *w, int mask, QRegion region, KWin::WindowPaintData &data)
{
if (!m_shader->isValid()
|| !w->isPaintingEnabled()
|| KWin::effects->hasActiveFullScreenEffect()
|| w->isDesktop()
|| w->isMenu()
|| w->isDock()
|| w->isPopupWindow()
|| w->isPopupMenu()
// || data.quads.isTransformed()
// || (mask & (PAINT_WINDOW_TRANSFORMED|PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS))
|| !hasShadow(data.quads)) {
KWin::effects->paintWindow(w, mask, region, data);
return;
}
//map the corners
const QRect geo(w->geometry());
const QRect rect[NTex] = {
QRect(geo.topLeft(), m_corner),
QRect(geo.topRight()-QPoint(m_frameRadius - 1, 0), m_corner),
QRect(geo.bottomRight()-QPoint(m_frameRadius - 1, m_frameRadius - 1), m_corner),
QRect(geo.bottomLeft()-QPoint(0, m_frameRadius - 1), m_corner)
};
const KWin::WindowQuadList qds(data.quads);
//paint the shadow
data.quads = qds.select(KWin::WindowQuadShadow);
KWin::effects->paintWindow(w, mask, region, data);
//copy the corner regions
KWin::GLTexture tex[NTex];
const QRect s(KWin::effects->virtualScreenGeometry());
for (int i = 0; i < NTex; ++i) {
tex[i] = KWin::GLTexture(GL_RGBA8, rect[i].size());
tex[i].bind();
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rect[i].x(), s.height() - rect[i].y() - rect[i].height(), rect[i].width(), rect[i].height());
tex[i].unbind();
}
//paint the actual window
data.quads = qds.filterOut(KWin::WindowQuadShadow);
KWin::effects->paintWindow(w, mask, region, data);
//'shape' the corners
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
const int mvpMatrixLocation = m_shader->uniformLocation("modelViewProjectionMatrix");
KWin::ShaderManager *sm = KWin::ShaderManager::instance();
sm->pushShader(m_shader);
for (int i = 0; i < NTex; ++i) {
QMatrix4x4 mvp = data.screenProjectionMatrix();
mvp.translate(rect[i].x(), rect[i].y());
m_shader->setUniform(mvpMatrixLocation, mvp);
glActiveTexture(GL_TEXTURE1);
m_tex[3-i]->bind();
glActiveTexture(GL_TEXTURE0);
tex[i].bind();
tex[i].render(region, rect[i]);
tex[i].unbind();
m_tex[3 - i]->unbind();
}
sm->popShader();
data.quads = qds;
glDisable(GL_BLEND);
}
void RoundedWindow::genMasks()
{
for (int i = 0; i < NTex; ++i)
if (m_tex[i])
delete m_tex[i];
QImage img(m_frameRadius * 2, m_frameRadius * 2, QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::transparent);
QPainter p(&img);
p.fillRect(img.rect(), Qt::white);
p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
p.setPen(Qt::NoPen);
p.setBrush(Qt::white);
p.setRenderHint(QPainter::Antialiasing);
p.drawEllipse(img.rect());
p.end();
m_tex[TopLeft] = new KWin::GLTexture(img.copy(0, 0, m_frameRadius, m_frameRadius));
m_tex[TopRight] = new KWin::GLTexture(img.copy(m_frameRadius, 0, m_frameRadius, m_frameRadius));
m_tex[BottomRight] = new KWin::GLTexture(img.copy(m_frameRadius, m_frameRadius, m_frameRadius, m_frameRadius));
m_tex[BottomLeft] = new KWin::GLTexture(img.copy(0, m_frameRadius, m_frameRadius, m_frameRadius));
}
void RoundedWindow::genRect()
{
for (int i = 0; i < NTex; ++i)
if (m_rect[i])
delete m_rect[i];
int m_rSize = m_frameRadius + 1;
QImage img(m_rSize * 2, m_rSize * 2, QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::transparent);
QPainter p(&img);
QRect r(img.rect());
p.setPen(Qt::NoPen);
p.setBrush(QColor(0, 0, 0, 0xff));
p.setRenderHint(QPainter::Antialiasing);
p.drawEllipse(r);
p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
p.setBrush(Qt::black);
r.adjust(1, 1, -1, -1);
p.drawEllipse(r);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
p.setBrush(QColor(255, 255, 255, 63));
p.drawEllipse(r);
p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
p.setBrush(Qt::black);
r.adjust(0, 1, 0, 0);
p.drawEllipse(r);
p.end();
m_rect[TopLeft] = new KWin::GLTexture(img.copy(0, 0, m_rSize, m_rSize));
m_rect[TopRight] = new KWin::GLTexture(img.copy(m_rSize, 0, m_rSize, m_rSize));
m_rect[BottomRight] = new KWin::GLTexture(img.copy(m_rSize, m_rSize, m_rSize, m_rSize));
m_rect[BottomLeft] = new KWin::GLTexture(img.copy(0, m_rSize, m_rSize, m_rSize));
}
#include "roundedwindow.moc"

@ -0,0 +1,60 @@
/*
* Copyright © 2021 Reven Martin <revenmartin@gmail.com>
* Copyright © 2015 Robert Metsäranta <therealestrob@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. if not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef ROUNDEDWINDOW_H
#define ROUNDEDWINDOW_H
#include <kwineffects.h>
namespace KWin { class GLTexture; }
class RoundedWindow : public KWin::Effect
{
Q_OBJECT
public:
enum { TopLeft = 0,
TopRight,
BottomRight,
BottomLeft,
NTex };
RoundedWindow();
~RoundedWindow();
static bool supported();
static bool enabledByDefault();
bool hasShadow(KWin::WindowQuadList &qds);
void paintWindow(KWin::EffectWindow *w, int mask, QRegion region, KWin::WindowPaintData &data);
private:
void genMasks();
void genRect();
private:
KWin::GLShader *m_shader;
KWin::GLTexture *m_tex[NTex];
KWin::GLTexture *m_rect[NTex];
int m_frameRadius;
QSize m_corner;
};
#endif

@ -0,0 +1,31 @@
{
"KPlugin": {
"Authors": [
{
"Email": "therealestrob@gmail.com",
"Name": "Rob"
}
],
"Category": "Appearance",
"Dependencies": [
],
"Description": "An effect that shapes/rounds corners of windows.",
"EnabledByDefault": true,
"Icon": "",
"Id": "kwin4_effect_roundedwindow",
"License": "GPL",
"Name": "RoundedWindow",
"ServiceTypes": [
"KWin/Effect"
],
"Version": "git"
},
"org.kde.kwin.effect": {
"video": "",
"exclusiveGroup": "",
"enabledByDefaultMethod": true
},
"X-KDE-Ordering": "5",
"X-Plasma-API": "",
"X-Plasma-MainScript": ""
}

@ -0,0 +1,14 @@
#version 110
uniform sampler2D sampler;
uniform sampler2D corner;
varying vec2 texcoord0;
void main()
{
vec4 tex = texture2D(sampler, texcoord0);
vec4 texCorner = texture2D(corner, texcoord0);
tex.a = texCorner.a;
gl_FragColor = tex;
}

@ -0,0 +1,15 @@
#version 140
uniform sampler2D sampler;
uniform sampler2D corner;
in vec2 texcoord0;
out vec4 fragColor;
void main(void)
{
vec4 tex = texture(sampler, texcoord0);
vec4 texCorner = texture(corner, texcoord0);
tex.a = texCorner.a;
fragColor = tex;
}
Loading…
Cancel
Save