kwin/kcmkwin/kwindecoration/preview.cpp

631 lines
15 KiB
C++

/*
*
* Copyright (c) 2003 Lubos Lunak <l.lunak@kde.org>
* Copyright (c) 2013 Martin Gräßlin <mgraesslin@kde.org>
*
* 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "preview.h"
#include <KLocalizedString>
#include <kconfig.h>
#include <QApplication>
#include <QPainter>
#include <QMouseEvent>
#include <kdecorationfactory.h>
static const int SMALL_OFFSET = 10;
static const int LARGE_OFFSET = 40;
PreviewItem::PreviewItem(QQuickItem *parent)
: QQuickPaintedItem(parent)
, m_plugins(new KDecorationPreviewPlugins(KSharedConfig::openConfig(QStringLiteral("kwinrc"))))
, m_activeBridge(new KDecorationPreviewBridge(this, true))
, m_inactiveBridge(new KDecorationPreviewBridge(this, false))
, m_activeDecoration(nullptr)
, m_inactiveDecoration(nullptr)
, m_activeEntered(nullptr)
, m_inactiveEntered(nullptr)
{
setFlag(ItemHasContents, true);
setAcceptHoverEvents(true);
connect(this, &PreviewItem::libraryChanged, this, &PreviewItem::loadDecorationPlugin);
}
PreviewItem::~PreviewItem()
{
delete m_activeDecoration;
delete m_inactiveDecoration;
}
void PreviewItem::setLibraryName(const QString &library)
{
if (library == m_libraryName || library.isEmpty()) {
return;
}
m_libraryName = library;
emit libraryChanged();
}
void PreviewItem::loadDecorationPlugin()
{
const bool loaded = m_plugins->loadPlugin(m_libraryName);
if (!loaded) {
return;
}
m_plugins->destroyPreviousPlugin();
connect(m_plugins->factory(), &KDecorationFactory::recreateDecorations,
this, &PreviewItem::recreateDecorations, Qt::QueuedConnection);
recreateDecorations();
}
void PreviewItem::recreateDecorations()
{
delete m_activeDecoration;
delete m_inactiveDecoration;
m_activeEntered = nullptr;
m_inactiveEntered = nullptr;
m_activeDecoration = m_plugins->createDecoration(m_activeBridge.data());
m_inactiveDecoration = m_plugins->createDecoration(m_inactiveBridge.data());
if (m_activeDecoration) {
m_activeDecoration->init();
if (m_activeDecoration->widget()) {
m_activeDecoration->widget()->installEventFilter(this);
}
}
if (m_inactiveDecoration) {
m_inactiveDecoration->init();
if (m_inactiveDecoration->widget()) {
m_inactiveDecoration->widget()->installEventFilter(this);
}
}
updatePreview();
}
void PreviewItem::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
{
QQuickPaintedItem::geometryChanged(newGeometry, oldGeometry);
updatePreview();
}
void PreviewItem::updatePreview()
{
if (width() == 0 && height() == 0) {
return;
}
if (!m_activeDecoration && !m_inactiveDecoration) {
return;
}
const QSize size(width() - 50, height() - 50);
updateSize(size, m_activeDecoration, m_activeBuffer);
updateSize(size, m_inactiveDecoration, m_inactiveBuffer);
render(&m_activeBuffer, m_activeDecoration);
render(&m_inactiveBuffer, m_inactiveDecoration);
update();
}
void PreviewItem::updateSize(const QSize &baseSize, KDecoration *decoration, QImage &buffer)
{
if (!decoration) {
return;
}
int left, right, top, bottom;
left = right = top = bottom = 0;
decoration->padding(left, right, top, bottom);
const QSize size = baseSize + QSize(left + right, top + bottom);
if (decoration->geometry().size() != size) {
decoration->resize(size);
}
if (buffer.isNull() || buffer.size() != size) {
buffer = QImage(size, QImage::Format_ARGB32_Premultiplied);
}
}
void PreviewItem::render(QImage* image, KDecoration* decoration)
{
image->fill(Qt::transparent);
decoration->render(image, QRegion());
}
void PreviewItem::paint(QPainter *painter)
{
int paddingLeft, paddingRigth, paddingTop, paddingBottom;
paddingLeft = paddingRigth = paddingTop = paddingBottom = 0;
if (m_inactiveDecoration) {
m_inactiveDecoration->padding(paddingLeft, paddingRigth, paddingTop, paddingBottom);
}
painter->drawImage(LARGE_OFFSET - paddingLeft, SMALL_OFFSET - paddingTop, m_inactiveBuffer);
paddingLeft = paddingRigth = paddingTop = paddingBottom = 0;
if (m_activeDecoration) {
m_activeDecoration->padding(paddingLeft, paddingRigth, paddingTop, paddingBottom);
}
painter->drawImage(SMALL_OFFSET - paddingLeft, LARGE_OFFSET - paddingTop, m_activeBuffer);
}
void PreviewItem::hoverMoveEvent(QHoverEvent* event)
{
QQuickItem::hoverMoveEvent(event);
const int w = width() - LARGE_OFFSET - SMALL_OFFSET;
const int h = height() - LARGE_OFFSET - SMALL_OFFSET;
forwardMoveEvent(event, QRect(SMALL_OFFSET, LARGE_OFFSET, w, h), m_activeDecoration, &m_activeEntered);
forwardMoveEvent(event, QRect(LARGE_OFFSET, SMALL_OFFSET, w, h), m_inactiveDecoration, &m_inactiveEntered);
}
void PreviewItem::forwardMoveEvent(QHoverEvent *event, const QRect &geo, KDecoration *deco, QWidget **entered)
{
auto leaveEvent = [](QWidget **widget) {
if (!(*widget)) {
return;
}
// send old one a leave event
QEvent leave(QEvent::Leave);
QApplication::sendEvent(*widget, &leave);
*widget = nullptr;
};
if (geo.contains(event->pos()) && deco && deco->widget()) {
int paddingLeft, paddingRigth, paddingTop, paddingBottom;
paddingLeft = paddingRigth = paddingTop = paddingBottom = 0;
deco->padding(paddingLeft, paddingRigth, paddingTop, paddingBottom);
const QPoint widgetPos = event->pos() - geo.topLeft() + QPoint(paddingLeft, paddingTop);
if (QWidget *widget = deco->widget()->childAt(widgetPos)) {
if (widget != *entered) {
leaveEvent(entered);
// send enter event
*entered = widget;
QEnterEvent enter(widgetPos - widget->geometry().topLeft(), widgetPos, event->pos());
QApplication::sendEvent(*entered, &enter);
}
} else {
leaveEvent(entered);
}
} else {
leaveEvent(entered);
}
}
void PreviewItem::updateDecoration(KDecorationPreviewBridge *bridge)
{
if (bridge == m_activeBridge.data()) {
render(&m_activeBuffer, m_activeDecoration);
} else if (bridge == m_inactiveBridge.data()) {
render(&m_inactiveBuffer, m_inactiveDecoration);
}
update();
}
KDecorationPreview::KDecorationPreview(QWidget* parent)
: QWidget(parent)
{
bridge[Active] = new KDecorationPreviewBridge(this, true);
bridge[Inactive] = new KDecorationPreviewBridge(this, false);
deco[Active] = deco[Inactive] = NULL;
setMinimumSize(100, 100);
}
KDecorationPreview::~KDecorationPreview()
{
for (int i = 0; i < NumWindows; i++) {
delete deco[i];
delete bridge[i];
}
}
void KDecorationPreview::disablePreview()
{
delete deco[Active];
delete deco[Inactive];
deco[Active] = deco[Inactive] = NULL;
}
KDecorationFactory *KDecorationPreview::factory() const
{
return deco[Active] ? deco[Active]->factory() : 0;
}
QRect KDecorationPreview::windowGeometry(bool active) const
{
QWidget *widget = active ? deco[Active]->widget() : deco[Inactive]->widget();
return widget->geometry();
}
QRegion KDecorationPreview::unobscuredRegion(bool active, const QRegion& r) const
{
Q_UNUSED(active)
return r;
}
KDecorationPreviewBridge::KDecorationPreviewBridge(KDecorationPreview* p, bool a)
: preview(p)
, m_previewItem(nullptr)
, active(a)
{
}
KDecorationPreviewBridge::KDecorationPreviewBridge(PreviewItem *p, bool a)
: preview(nullptr)
, m_previewItem(p)
, active(a)
{
}
Qt::WindowFlags KDecorationPreviewBridge::initialWFlags() const
{
return 0;
}
bool KDecorationPreviewBridge::isActive() const
{
return active;
}
bool KDecorationPreviewBridge::isCloseable() const
{
return true;
}
bool KDecorationPreviewBridge::isMaximizable() const
{
return true;
}
KDecoration::MaximizeMode KDecorationPreviewBridge::maximizeMode() const
{
return KDecoration::MaximizeRestore;
}
KDecoration::QuickTileMode KDecorationPreviewBridge::quickTileMode() const
{
return KDecoration::QuickTileNone;
}
bool KDecorationPreviewBridge::isMinimizable() const
{
return true;
}
bool KDecorationPreviewBridge::providesContextHelp() const
{
return true;
}
int KDecorationPreviewBridge::desktop() const
{
return 1;
}
bool KDecorationPreviewBridge::isOnAllDesktopsAvailable() const
{
return true;
}
bool KDecorationPreviewBridge::isModal() const
{
return false;
}
bool KDecorationPreviewBridge::isShadeable() const
{
return true;
}
bool KDecorationPreviewBridge::isShade() const
{
return false;
}
bool KDecorationPreviewBridge::isSetShade() const
{
return false;
}
bool KDecorationPreviewBridge::keepAbove() const
{
return false;
}
bool KDecorationPreviewBridge::keepBelow() const
{
return false;
}
bool KDecorationPreviewBridge::isMovable() const
{
return true;
}
bool KDecorationPreviewBridge::isResizable() const
{
return true;
}
NET::WindowType KDecorationPreviewBridge::windowType(unsigned long) const
{
return NET::Normal;
}
QIcon KDecorationPreviewBridge::icon() const
{
return QIcon::fromTheme(QStringLiteral("xorg"));
}
QString KDecorationPreviewBridge::caption() const
{
return active ? i18n("Active Window") : i18n("Inactive Window");
}
void KDecorationPreviewBridge::processMousePressEvent(QMouseEvent*)
{
}
void KDecorationPreviewBridge::showWindowMenu(const QRect &)
{
}
void KDecorationPreviewBridge::showWindowMenu(const QPoint &)
{
}
void KDecorationPreviewBridge::showApplicationMenu(const QPoint &)
{
}
bool KDecorationPreviewBridge::menuAvailable() const
{
return false;
}
void KDecorationPreviewBridge::performWindowOperation(WindowOperation)
{
}
void KDecorationPreviewBridge::setMask(const QRegion& reg, int mode)
{
Q_UNUSED(reg)
Q_UNUSED(mode)
}
bool KDecorationPreviewBridge::isPreview() const
{
return true;
}
QRect KDecorationPreviewBridge::geometry() const
{
if (preview) {
return preview->windowGeometry(active);
}
return QRect();
}
QRect KDecorationPreviewBridge::iconGeometry() const
{
return QRect();
}
QRegion KDecorationPreviewBridge::unobscuredRegion(const QRegion& r) const
{
return preview->unobscuredRegion(active, r);
}
WId KDecorationPreviewBridge::windowId() const
{
return 0; // no decorated window
}
void KDecorationPreviewBridge::closeWindow()
{
}
void KDecorationPreviewBridge::maximize(MaximizeMode)
{
}
void KDecorationPreviewBridge::minimize()
{
}
void KDecorationPreviewBridge::showContextHelp()
{
}
void KDecorationPreviewBridge::setDesktop(int)
{
}
void KDecorationPreviewBridge::titlebarDblClickOperation()
{
}
void KDecorationPreviewBridge::titlebarMouseWheelOperation(int)
{
}
void KDecorationPreviewBridge::setShade(bool)
{
}
void KDecorationPreviewBridge::setKeepAbove(bool)
{
}
void KDecorationPreviewBridge::setKeepBelow(bool)
{
}
int KDecorationPreviewBridge::currentDesktop() const
{
return 1;
}
void KDecorationPreviewBridge::grabXServer(bool)
{
}
bool KDecorationPreviewBridge::compositingActive() const
{
return true;
}
QRect KDecorationPreviewBridge::transparentRect() const
{
return QRect();
}
// Window tabbing
int KDecorationPreviewBridge::tabCount() const
{
return 1;
}
QString KDecorationPreviewBridge::caption(int) const
{
return active ? "Active Window" : "Inactive Window";
}
QIcon KDecorationPreviewBridge::icon(int) const
{
return icon();
}
long KDecorationPreviewBridge::tabId(int) const
{
return 0;
}
long KDecorationPreviewBridge::currentTabId() const
{
return 0;
}
void KDecorationPreviewBridge::setCurrentTab(long)
{
}
void KDecorationPreviewBridge::tab_A_before_B(long, long)
{
}
void KDecorationPreviewBridge::tab_A_behind_B(long, long)
{
}
void KDecorationPreviewBridge::untab(long, const QRect&)
{
}
void KDecorationPreviewBridge::closeTab(long)
{
}
void KDecorationPreviewBridge::closeTabGroup()
{
}
void KDecorationPreviewBridge::showWindowMenu(const QPoint &, long)
{
}
void KDecorationPreviewBridge::update(const QRegion&)
{
if (m_previewItem) {
// call update
m_previewItem->updateDecoration(this);
}
}
KDecoration::WindowOperation KDecorationPreviewBridge::buttonToWindowOperation(Qt::MouseButtons)
{
return KDecoration::NoOp;
}
QPalette KDecorationPreviewBridge::palette() const
{
return QApplication::palette();
}
KDecorationPreviewOptions::KDecorationPreviewOptions()
{
customBorderSize = BordersCount; // invalid
customButtonsChanged = false; // invalid
customButtons = true;
customTitleButtonsLeft.clear(); // invalid
customTitleButtonsRight.clear(); // invalid
updateSettings();
}
KDecorationPreviewOptions::~KDecorationPreviewOptions()
{
}
void KDecorationPreviewOptions::updateSettings()
{
KConfig cfg("kwinrc");
KDecorationOptions::updateSettings(&cfg);
// set custom border size/buttons
if (customBorderSize != BordersCount)
setBorderSize(customBorderSize);
if (customButtonsChanged)
setCustomButtonPositions(customButtons);
if (customButtons) {
if (!customTitleButtonsLeft.isEmpty())
setTitleButtonsLeft(customTitleButtonsLeft);
if (!customTitleButtonsRight.isEmpty())
setTitleButtonsRight(customTitleButtonsRight);
} else {
setTitleButtonsLeft(KDecorationOptions::defaultTitleButtonsLeft());
setTitleButtonsRight(KDecorationOptions::defaultTitleButtonsRight());
}
}
void KDecorationPreviewOptions::setCustomBorderSize(BorderSize size)
{
customBorderSize = size;
updateSettings();
}
void KDecorationPreviewOptions::setCustomTitleButtonsEnabled(bool enabled)
{
customButtonsChanged = true;
customButtons = enabled;
updateSettings();
}
void KDecorationPreviewOptions::setCustomTitleButtons(const QList<DecorationButton> &left, const QList<DecorationButton> &right)
{
customTitleButtonsLeft = left;
customTitleButtonsRight = right;
updateSettings();
}
bool KDecorationPreviewPlugins::provides(Requirement)
{
return false;
}
#include "preview.moc"