Commit 6dfb7ba1 authored by David Edmundson's avatar David Edmundson
Browse files

[aurorae] Use shared implementation of QtQuick rendering

Summary:
Removes a tonne of complex code, means any future improvements to our
QtQuick integration only need to be in one place.

QML logic remains in Aurorae as it does complex things. All other
aurorae specialties remain.

Only functional difference is that we now use a shared GL context
between window frames, which Plasma::FrameSVG will make use of.

Test Plan:
kcmshell5 kwindecoration
ran some aurorrae themes on my kwin. Look the same as master

Reviewers: #kwin, mart

Reviewed By: mart

Subscribers: mart, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D25206
parent 8d137290
......@@ -17,6 +17,7 @@ set_target_properties(kwin5_aurorae PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE
target_link_libraries(kwin5_aurorae
KDecoration2::KDecoration
kwineffects
KF5::ConfigWidgets
KF5::I18n
KF5::Package
......
......@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "aurorae.h"
#include "auroraetheme.h"
#include "config-kwin.h"
#include "kwineffectquickview.h"
// qml imports
#include "decorationoptions.h"
// KDecoration2
......@@ -259,6 +260,7 @@ Decoration::Decoration(QObject *parent, const QVariantList &args)
, m_extendedBorders(nullptr)
, m_padding(nullptr)
, m_themeName(s_defaultTheme)
, m_view(nullptr)
{
m_themeName = findTheme(args);
Helper::instance().ref();
......@@ -266,18 +268,8 @@ Decoration::Decoration(QObject *parent, const QVariantList &args)
Decoration::~Decoration()
{
if (m_context) {
m_context->makeCurrent(m_offscreenSurface.data());
delete m_renderControl;
delete m_view.data();
m_fbo.reset();
m_context->doneCurrent();
}
// deleted explicitly before our own qobject destructor as "this" is a context property of m_qmlContext,
// and changing contextProperties is a bad idea
delete m_qmlContext;
delete m_view;
Helper::instance().unref();
}
......@@ -324,6 +316,7 @@ void Decoration::init()
}
return;
}
m_item->setParent(m_qmlContext);
QVariant visualParent = property("visualParent");
......@@ -331,51 +324,17 @@ void Decoration::init()
m_item->setParentItem(visualParent.value<QQuickItem*>());
visualParent.value<QQuickItem*>()->setProperty("drawBackground", false);
} else {
m_renderControl = new QQuickRenderControl(this);
m_view = new QQuickWindow(m_renderControl);
const bool usingGL = m_view->rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL;
m_view->setColor(Qt::transparent);
m_view->setFlags(Qt::FramelessWindowHint);
if (usingGL) {
// first create the context
QSurfaceFormat format;
format.setSwapBehavior(QSurfaceFormat::SingleBuffer);
format.setDepthBufferSize(16);
format.setStencilBufferSize(8);
m_context.reset(new QOpenGLContext);
m_context->setFormat(format);
m_context->create();
// and the offscreen surface
m_offscreenSurface.reset(new QOffscreenSurface);
m_offscreenSurface->setFormat(m_context->format());
m_offscreenSurface->create();
}
// delay rendering a little bit for better performance
m_updateTimer.reset(new QTimer);
m_updateTimer->setSingleShot(true);
m_updateTimer->setInterval(5);
connect(m_updateTimer.data(), &QTimer::timeout, this, &Decoration::updateBuffer);
auto requestUpdate = [this] {
if (m_updateTimer->isActive()) {
return;
}
m_updateTimer->start();
};
connect(m_renderControl, &QQuickRenderControl::renderRequested, this, requestUpdate);
connect(m_renderControl, &QQuickRenderControl::sceneChanged, this, requestUpdate);
m_view = new KWin::EffectQuickView(this, KWin::EffectQuickView::ExportMode::Image);
m_item->setParentItem(m_view->contentItem());
if (usingGL) {
m_context->makeCurrent(m_offscreenSurface.data());
m_renderControl->initialize(m_context.data());
m_context->doneCurrent();
}
auto updateSize = [this]() { m_item->setSize(m_view->contentItem()->size()); };
updateSize();
connect(m_view->contentItem(), &QQuickItem::widthChanged, m_item, updateSize);
connect(m_view->contentItem(), &QQuickItem::heightChanged, m_item, updateSize);
connect(m_view, &KWin::EffectQuickView::repaintNeeded, this, &Decoration::updateBuffer);
}
setupBorders(m_item);
// TODO: Is there a more efficient way to react to border changes?
auto trackBorders = [this](KWin::Borders *borders) {
if (!borders) {
......@@ -401,7 +360,7 @@ void Decoration::init()
connect(client().data(), &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateBorders, Qt::QueuedConnection);
connect(client().data(), &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::updateBorders);
updateBorders();
if (!m_view.isNull()) {
if (m_view) {
auto resizeWindow = [this] {
QRect rect(QPoint(0, 0), size());
if (m_padding && !client().data()->isMaximized()) {
......@@ -456,12 +415,18 @@ void Decoration::updateBorders()
void Decoration::paint(QPainter *painter, const QRect &repaintRegion)
{
Q_UNUSED(repaintRegion)
if (!m_view) {
return;
}
painter->fillRect(rect(), Qt::transparent);
painter->drawImage(rect(), m_buffer, m_contentRect);
painter->drawImage(rect(), m_view->bufferAsImage(), m_contentRect);
}
void Decoration::updateShadow()
{
if (!m_view) {
return;
}
bool updateShadow = false;
const auto oldShadow = shadow();
if (m_padding &&
......@@ -475,6 +440,8 @@ void Decoration::updateShadow()
updateShadow = true;
}
}
const QImage m_buffer = m_view->bufferAsImage();
QImage img(m_buffer.size(), QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::transparent);
QPainter p(&img);
......@@ -510,23 +477,11 @@ void Decoration::updateShadow()
}
}
QMouseEvent Decoration::translatedMouseEvent(QMouseEvent *orig)
{
if (!m_padding || client().data()->isMaximized()) {
orig->setAccepted(false);
return *orig;
}
QMouseEvent event(orig->type(), orig->localPos() + QPointF(m_padding->left(), m_padding->top()), orig->button(), orig->buttons(), orig->modifiers());
event.setAccepted(false);
return event;
}
void Decoration::hoverEnterEvent(QHoverEvent *event)
{
if (m_view) {
event->setAccepted(false);
QCoreApplication::sendEvent(m_view.data(), event);
m_view->forwardMouseEvent(event);
}
KDecoration2::Decoration::hoverEnterEvent(event);
}
......@@ -534,8 +489,7 @@ void Decoration::hoverEnterEvent(QHoverEvent *event)
void Decoration::hoverLeaveEvent(QHoverEvent *event)
{
if (m_view) {
event->setAccepted(false);
QCoreApplication::sendEvent(m_view.data(), event);
m_view->forwardMouseEvent(event);
}
KDecoration2::Decoration::hoverLeaveEvent(event);
}
......@@ -543,10 +497,11 @@ void Decoration::hoverLeaveEvent(QHoverEvent *event)
void Decoration::hoverMoveEvent(QHoverEvent *event)
{
if (m_view) {
QMouseEvent mouseEvent(QEvent::MouseMove, event->posF(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
QMouseEvent ev = translatedMouseEvent(&mouseEvent);
QCoreApplication::sendEvent(m_view.data(), &ev);
event->setAccepted(ev.isAccepted());
// turn a hover event into a mouse becase we don't follow hovers as we don't think we have focus
QMouseEvent cloneEvent(QEvent::MouseMove, event->posF(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
event->setAccepted(false);
m_view->forwardMouseEvent(&cloneEvent);
event->setAccepted(cloneEvent.isAccepted());
}
KDecoration2::Decoration::hoverMoveEvent(event);
}
......@@ -554,9 +509,7 @@ void Decoration::hoverMoveEvent(QHoverEvent *event)
void Decoration::mouseMoveEvent(QMouseEvent *event)
{
if (m_view) {
QMouseEvent ev = translatedMouseEvent(event);
QCoreApplication::sendEvent(m_view.data(), &ev);
event->setAccepted(ev.isAccepted());
m_view->forwardMouseEvent(event);
}
KDecoration2::Decoration::mouseMoveEvent(event);
}
......@@ -564,16 +517,14 @@ void Decoration::mouseMoveEvent(QMouseEvent *event)
void Decoration::mousePressEvent(QMouseEvent *event)
{
if (m_view) {
QMouseEvent ev = translatedMouseEvent(event);
QCoreApplication::sendEvent(m_view.data(), &ev);
if (ev.button() == Qt::LeftButton) {
m_view->forwardMouseEvent(event);
if (event->button() == Qt::LeftButton) {
if (!m_doubleClickTimer.hasExpired(QGuiApplication::styleHints()->mouseDoubleClickInterval())) {
QMouseEvent dc(QEvent::MouseButtonDblClick, ev.localPos(), ev.windowPos(), ev.screenPos(), ev.button(), ev.buttons(), ev.modifiers());
QCoreApplication::sendEvent(m_view.data(), &dc);
QMouseEvent dc(QEvent::MouseButtonDblClick, event->localPos(), event->windowPos(), event->screenPos(), event->button(), event->buttons(), event->modifiers());
m_view->forwardMouseEvent(&dc);
}
}
m_doubleClickTimer.invalidate();
event->setAccepted(ev.isAccepted());
}
KDecoration2::Decoration::mousePressEvent(event);
}
......@@ -581,10 +532,8 @@ void Decoration::mousePressEvent(QMouseEvent *event)
void Decoration::mouseReleaseEvent(QMouseEvent *event)
{
if (m_view) {
QMouseEvent ev = translatedMouseEvent(event);
QCoreApplication::sendEvent(m_view.data(), &ev);
event->setAccepted(ev.isAccepted());
if (ev.isAccepted() && ev.button() == Qt::LeftButton) {
m_view->forwardMouseEvent(event);
if (event->isAccepted() && event->button() == Qt::LeftButton) {
m_doubleClickTimer.start();
}
}
......@@ -609,36 +558,13 @@ void Decoration::installTitleItem(QQuickItem *item)
void Decoration::updateBuffer()
{
Q_ASSERT(m_view);
const bool usingGL = m_view->rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL;
if (usingGL) {
Q_ASSERT(m_view->size().isValid());
if (!m_context->makeCurrent(m_offscreenSurface.data())) {
return;
}
if (m_fbo.isNull() || m_fbo->size() != m_view->size()) {
m_fbo.reset(new QOpenGLFramebufferObject(m_view->size(), QOpenGLFramebufferObject::CombinedDepthStencil));
if (!m_fbo->isValid()) {
qCWarning(AURORAE) << "Creating FBO as render target failed";
m_fbo.reset();
return;
}
}
m_view->setRenderTarget(m_fbo.data());
m_view->resetOpenGLState();
}
m_buffer = m_renderControl->grab();
m_contentRect = QRect(QPoint(0, 0), m_buffer.size());
m_contentRect = QRect(QPoint(0, 0), m_view->bufferAsImage().size());
if (m_padding &&
(m_padding->left() > 0 || m_padding->top() > 0 || m_padding->right() > 0 || m_padding->bottom() > 0) &&
!client().data()->isMaximized()) {
m_contentRect = m_contentRect.adjusted(m_padding->left(), m_padding->top(), -m_padding->right(), -m_padding->bottom());
}
updateShadow();
QOpenGLFramebufferObject::bindDefault();
update();
}
......
......@@ -23,21 +23,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QVariant>
#include <KCModule>
class QOffscreenSurface;
class QOpenGLContext;
class QOpenGLFramebufferObject;
class QQmlComponent;
class QQmlContext;
class QQmlEngine;
class QQuickItem;
class QQuickRenderControl;
class QQuickWindow;
class KConfigLoader;
namespace KWin
{
class Borders;
class EffectQuickView;
}
namespace Aurorae
......@@ -78,11 +74,7 @@ private:
void setupBorders(QQuickItem *item);
void updateBorders();
void updateBuffer();
QMouseEvent translatedMouseEvent(QMouseEvent *orig);
QScopedPointer<QOpenGLFramebufferObject> m_fbo;
QImage m_buffer;
QRect m_contentRect; //the geometry of the part of the buffer that is not a shadow when buffer was created.
QPointer<QQuickWindow> m_view;
QQuickItem *m_item = nullptr;
QQmlContext *m_qmlContext = nullptr;
KWin::Borders *m_borders;
......@@ -90,10 +82,8 @@ private:
KWin::Borders *m_extendedBorders;
KWin::Borders *m_padding;
QString m_themeName;
QQuickRenderControl *m_renderControl = nullptr;
QScopedPointer<QTimer> m_updateTimer;
QScopedPointer<QOpenGLContext> m_context;
QScopedPointer<QOffscreenSurface> m_offscreenSurface;
KWin::EffectQuickView *m_view;
QElapsedTimer m_doubleClickTimer;
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment