Move kwin themes to a separate package

This commit is contained in:
Daniel Ruiz de Alegría 2021-10-13 10:13:47 +02:00
parent 913168e7fb
commit 4827a44c35
No known key found for this signature in database
GPG Key ID: 59667A77E8BFCB6C
42 changed files with 2 additions and 5854 deletions

View File

@ -1,14 +0,0 @@
cmake_minimum_required(VERSION 3.0)
include(GenerateExportHeader)
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
include(KDEInstallDirs)
include(KDECMakeSettings)
find_package(KDecoration2 REQUIRED)
add_subdirectory(kdecoration)
add_subdirectory(libbreezecommon)

View File

@ -1,13 +0,0 @@
.PHONY: build clean install
clean:
rm -rf build
build:
cmake -B build
cmake --build build
install:
DESTDIR=$(DESTDIR) cmake --install build
include ../Makefile.inc

View File

@ -1,96 +0,0 @@
add_definitions(-DTRANSLATION_DOMAIN="breeze_kwin_deco")
find_package(KF5 REQUIRED COMPONENTS CoreAddons GuiAddons ConfigWidgets WindowSystem I18n IconThemes)
find_package(Qt5 CONFIG REQUIRED COMPONENTS DBus)
### XCB
find_package(XCB COMPONENTS XCB)
set_package_properties(XCB PROPERTIES
DESCRIPTION "X protocol C-language Binding"
URL "https://xcb.freedesktop.org"
TYPE OPTIONAL
PURPOSE "Required to pass style properties to native Windows on X11 Platform"
)
if(UNIX AND NOT APPLE)
set(BREEZE_HAVE_X11 ${XCB_XCB_FOUND})
if (XCB_XCB_FOUND)
find_package(Qt5 REQUIRED CONFIG COMPONENTS X11Extras)
endif()
else()
set(BREEZE_HAVE_X11 FALSE)
endif()
################# configuration #################
configure_file(config-breeze.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-breeze.h )
################# includes #################
include_directories(${CMAKE_SOURCE_DIR}/libbreezecommon)
include_directories(${CMAKE_BINARY_DIR}/libbreezecommon)
################# newt target #################
### plugin classes
set(breezedecoration_SRCS
breezebutton.cpp
../libbreezecommon/breezeboxshadowrenderer.cpp
breezedecoration.cpp
breezeexceptionlist.cpp
breezesettingsprovider.cpp
breezesizegrip.cpp)
kconfig_add_kcfg_files(breezedecoration_SRCS breezesettings.kcfgc)
### config classes
### they are kept separately because they might move in a separate library in the future
set(breezedecoration_config_SRCS
config/breezeconfigwidget.cpp
config/breezedetectwidget.cpp
config/breezeexceptiondialog.cpp
config/breezeexceptionlistwidget.cpp
config/breezeexceptionmodel.cpp
config/breezeitemmodel.cpp
)
set(breezedecoration_config_PART_FORMS
config/ui/breezeconfigurationui.ui
config/ui/breezedetectwidget.ui
config/ui/breezeexceptiondialog.ui
config/ui/breezeexceptionlistwidget.ui
)
ki18n_wrap_ui(breezedecoration_config_PART_FORMS_HEADERS ${breezedecoration_config_PART_FORMS})
### build library
add_library(kali-breezedecoration MODULE
${breezedecoration_SRCS}
${breezedecoration_config_SRCS}
${breezedecoration_config_PART_FORMS_HEADERS})
target_link_libraries(kali-breezedecoration
PUBLIC
Qt5::Core
Qt5::Gui
Qt5::DBus
PRIVATE
KDecoration2::KDecoration
KF5::ConfigCore
KF5::CoreAddons
KF5::ConfigWidgets
KF5::GuiAddons
KF5::I18n
KF5::IconThemes
KF5::WindowSystem)
if(BREEZE_HAVE_X11)
target_link_libraries(kali-breezedecoration
PUBLIC
Qt5::X11Extras
XCB::XCB)
endif()
install(TARGETS kali-breezedecoration DESTINATION ${PLUGIN_INSTALL_DIR}/org.kde.kdecoration2)

View File

@ -1,4 +0,0 @@
#!bin/sh
$EXTRACTRC `find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` >> rc.cpp
$XGETTEXT `find . -name \*.cc -o -name \*.cpp -o -name \*.h` -o $podir/breeze_kwin_deco.pot
rm -f rc.cpp

View File

@ -1,61 +0,0 @@
#ifndef breeze_h
#define breeze_h
/*
* SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "breezesettings.h"
#include <QSharedPointer>
#include <QList>
namespace Breeze
{
//* convenience typedefs
using InternalSettingsPtr = QSharedPointer<InternalSettings>;
using InternalSettingsList = QList<InternalSettingsPtr>;
using InternalSettingsListIterator = QListIterator<InternalSettingsPtr>;
//* metrics
enum Metrics
{
//* corner radius (pixels)
Frame_FrameRadius = 4,
//* titlebar metrics, in units of small spacing
TitleBar_TopMargin = 3,
TitleBar_BottomMargin = 3,
TitleBar_SideMargin = 1,
TitleBar_ButtonSpacing = 2,
Frame_BorderSize = 2,
// shadow dimensions (pixels)
Shadow_Overlap = 3,
};
//* standard pen widths
namespace PenWidth
{
/* Using 1 instead of slightly more than 1 causes symbols drawn with
* pen strokes to look skewed. The exact amount added does not matter
* as long as it isn't too visible.
*/
// The standard pen stroke width for symbols.
static constexpr qreal Symbol = 1.01;
}
//* exception
enum ExceptionMask
{
None = 0,
BorderSize = 1<<4
};
}
#endif

View File

@ -1,16 +0,0 @@
{
"KPlugin": {
"Description": "Window decoration using Kali's visual style for the Plasma Desktop",
"EnabledByDefault": true,
"Id": "org.kali.kali",
"Name": "Kali",
"ServiceTypes": [
"org.kde.kdecoration2"
]
},
"org.kde.kdecoration2": {
"blur": false,
"kcmodule": true,
"recommendedBorderSize": "None"
}
}

View File

@ -1,471 +0,0 @@
/*
* SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
* SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "breezebutton.h"
#include <KDecoration2/DecoratedClient>
#include <KColorUtils>
#include <KIconLoader>
#include <QPainter>
#include <QVariantAnimation>
#include <QPainterPath>
namespace Breeze
{
using KDecoration2::ColorRole;
using KDecoration2::ColorGroup;
using KDecoration2::DecorationButtonType;
//__________________________________________________________________
Button::Button(DecorationButtonType type, Decoration* decoration, QObject* parent)
: DecorationButton(type, decoration, parent)
, m_animation( new QVariantAnimation( this ) )
{
// setup animation
// It is important start and end value are of the same type, hence 0.0 and not just 0
m_animation->setStartValue( 0.0 );
m_animation->setEndValue( 1.0 );
m_animation->setEasingCurve( QEasingCurve::InOutQuad );
connect(m_animation, &QVariantAnimation::valueChanged, this, [this](const QVariant &value) {
setOpacity(value.toReal());
});
// setup default geometry
const int height = decoration->buttonHeight();
setGeometry(QRect(0, 0, height, height));
setIconSize(QSize( height, height ));
// connections
connect(decoration->client().data(), SIGNAL(iconChanged(QIcon)), this, SLOT(update()));
connect(decoration->settings().data(), &KDecoration2::DecorationSettings::reconfigured, this, &Button::reconfigure);
connect( this, &KDecoration2::DecorationButton::hoveredChanged, this, &Button::updateAnimationState );
reconfigure();
}
//__________________________________________________________________
Button::Button(QObject *parent, const QVariantList &args)
: Button(args.at(0).value<DecorationButtonType>(), args.at(1).value<Decoration*>(), parent)
{
m_flag = FlagStandalone;
//! icon size must return to !valid because it was altered from the default constructor,
//! in Standalone mode the button is not using the decoration metrics but its geometry
m_iconSize = QSize(-1, -1);
}
//__________________________________________________________________
Button *Button::create(DecorationButtonType type, KDecoration2::Decoration *decoration, QObject *parent)
{
if (auto d = qobject_cast<Decoration*>(decoration))
{
Button *b = new Button(type, d, parent);
switch( type )
{
case DecorationButtonType::Close:
b->setVisible( d->client().data()->isCloseable() );
QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::closeableChanged, b, &Breeze::Button::setVisible );
break;
case DecorationButtonType::Maximize:
b->setVisible( d->client().data()->isMaximizeable() );
QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::maximizeableChanged, b, &Breeze::Button::setVisible );
break;
case DecorationButtonType::Minimize:
b->setVisible( d->client().data()->isMinimizeable() );
QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::minimizeableChanged, b, &Breeze::Button::setVisible );
break;
case DecorationButtonType::ContextHelp:
b->setVisible( d->client().data()->providesContextHelp() );
QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::providesContextHelpChanged, b, &Breeze::Button::setVisible );
break;
case DecorationButtonType::Shade:
b->setVisible( d->client().data()->isShadeable() );
QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::shadeableChanged, b, &Breeze::Button::setVisible );
break;
case DecorationButtonType::Menu:
QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::iconChanged, b, [b]() { b->update(); });
break;
default: break;
}
return b;
}
return nullptr;
}
//__________________________________________________________________
void Button::paint(QPainter *painter, const QRect &repaintRegion)
{
Q_UNUSED(repaintRegion)
if (!decoration()) return;
painter->save();
// translate from offset
if( m_flag == FlagFirstInList ) painter->translate( m_offset );
else painter->translate( 0, m_offset.y() );
if( !m_iconSize.isValid() ) m_iconSize = geometry().size().toSize();
// menu button
if (type() == DecorationButtonType::Menu)
{
const QRectF iconRect( geometry().topLeft(), m_iconSize );
if (auto deco = qobject_cast<Decoration*>(decoration())) {
const QPalette activePalette = KIconLoader::global()->customPalette();
QPalette palette = decoration()->client().data()->palette();
palette.setColor(QPalette::Foreground, deco->fontColor());
KIconLoader::global()->setCustomPalette(palette);
decoration()->client().data()->icon().paint(painter, iconRect.toRect());
if (activePalette == QPalette()) {
KIconLoader::global()->resetPalette();
} else {
KIconLoader::global()->setCustomPalette(palette);
}
} else {
decoration()->client().data()->icon().paint(painter, iconRect.toRect());
}
} else {
drawIcon( painter );
}
painter->restore();
}
//__________________________________________________________________
void Button::drawIcon( QPainter *painter ) const
{
painter->setRenderHints( QPainter::Antialiasing );
/*
scale painter so that its window matches QRect( -1, -1, 20, 20 )
this makes all further rendering and scaling simpler
all further rendering is preformed inside QRect( 0, 0, 18, 18 )
*/
painter->translate( geometry().topLeft() );
const qreal width( m_iconSize.width() );
painter->scale( width/20, width/20 );
painter->translate( 1, 1 );
// render background
const QColor backgroundColor( this->backgroundColor() );
if( backgroundColor.isValid() )
{
painter->setPen( Qt::NoPen );
painter->setBrush( backgroundColor );
painter->drawEllipse( QRectF( 0, 0, 18, 18 ) );
}
// render mark
const QColor foregroundColor( this->foregroundColor() );
if( foregroundColor.isValid() )
{
// setup painter
QPen pen( foregroundColor );
pen.setCapStyle( Qt::RoundCap );
pen.setJoinStyle( Qt::MiterJoin );
pen.setWidthF( PenWidth::Symbol*qMax((qreal)2.0, 20/width ) );
painter->setPen( pen );
painter->setBrush( Qt::NoBrush );
switch( type() )
{
case DecorationButtonType::Close:
{
painter->drawLine( QPointF( 6, 6 ), QPointF( 12, 12 ) );
painter->drawLine( QPointF( 6, 12 ), QPointF( 12, 6 ) );
break;
}
case DecorationButtonType::Maximize:
{
pen.setJoinStyle( Qt::RoundJoin );
painter->setPen( pen );
painter->drawPolygon( QVector<QPointF>{
QPointF( 6, 6 ),
QPointF( 6, 12 ),
QPointF( 12, 12 ),
QPointF( 12, 6 )} );
break;
}
case DecorationButtonType::Minimize:
{
painter->drawLine( QPointF( 6, 12 ), QPointF( 12, 12 ) );
break;
}
case DecorationButtonType::OnAllDesktops:
{
painter->setPen( Qt::NoPen );
painter->setBrush( foregroundColor );
if( isChecked())
{
// outer ring
painter->drawEllipse( QRectF( 3, 3, 12, 12 ) );
// center dot
QColor backgroundColor( this->backgroundColor() );
auto d = qobject_cast<Decoration*>( decoration() );
if( !backgroundColor.isValid() && d ) backgroundColor = d->titleBarColor();
if( backgroundColor.isValid() )
{
painter->setBrush( backgroundColor );
painter->drawEllipse( QRectF( 8, 8, 2, 2 ) );
}
} else {
painter->drawPolygon( QVector<QPointF> {
QPointF( 6.5, 8.5 ),
QPointF( 12, 3 ),
QPointF( 15, 6 ),
QPointF( 9.5, 11.5 )} );
painter->setPen( pen );
painter->drawLine( QPointF( 5.5, 7.5 ), QPointF( 10.5, 12.5 ) );
painter->drawLine( QPointF( 12, 6 ), QPointF( 4.5, 13.5 ) );
}
break;
}
case DecorationButtonType::Shade:
{
if (isChecked())
{
painter->drawLine( QPointF( 4, 5.5 ), QPointF( 14, 5.5 ) );
painter->drawPolyline( QVector<QPointF> {
QPointF( 4, 8 ),
QPointF( 9, 13 ),
QPointF( 14, 8 )} );
} else {
painter->drawLine( QPointF( 4, 5.5 ), QPointF( 14, 5.5 ) );
painter->drawPolyline( QVector<QPointF> {
QPointF( 4, 13 ),
QPointF( 9, 8 ),
QPointF( 14, 13 ) });
}
break;
}
case DecorationButtonType::KeepBelow:
{
painter->drawPolyline( QVector<QPointF> {
QPointF( 4, 5 ),
QPointF( 9, 10 ),
QPointF( 14, 5 ) });
painter->drawPolyline( QVector<QPointF> {
QPointF( 4, 9 ),
QPointF( 9, 14 ),
QPointF( 14, 9 ) });
break;
}
case DecorationButtonType::KeepAbove:
{
painter->drawPolyline( QVector<QPointF> {
QPointF( 4, 9 ),
QPointF( 9, 4 ),
QPointF( 14, 9 ) });
painter->drawPolyline( QVector<QPointF> {
QPointF( 4, 13 ),
QPointF( 9, 8 ),
QPointF( 14, 13 ) });
break;
}
case DecorationButtonType::ApplicationMenu:
{
painter->drawRect( QRectF( 3.5, 4.5, 11, 1 ) );
painter->drawRect( QRectF( 3.5, 8.5, 11, 1 ) );
painter->drawRect( QRectF( 3.5, 12.5, 11, 1 ) );
break;
}
case DecorationButtonType::ContextHelp:
{
QPainterPath path;
path.moveTo( 5, 6 );
path.arcTo( QRectF( 5, 3.5, 8, 5 ), 180, -180 );
path.cubicTo( QPointF(12.5, 9.5), QPointF( 9, 7.5 ), QPointF( 9, 11.5 ) );
painter->drawPath( path );
painter->drawRect( QRectF( 9, 15, 0.5, 0.5 ) );
break;
}
default: break;
}
}
}
//__________________________________________________________________
QColor Button::foregroundColor() const
{
auto d = qobject_cast<Decoration*>( decoration() );
if( !d ) {
return QColor();
} else if( isPressed() ) {
return d->titleBarColor();
} else if( type() == DecorationButtonType::Close && d->internalSettings()->outlineCloseButton() ) {
return d->titleBarColor();
} else if( ( type() == DecorationButtonType::KeepBelow || type() == DecorationButtonType::KeepAbove || type() == DecorationButtonType::Shade ) && isChecked() ) {
return d->titleBarColor();
} else if( m_animation->state() == QAbstractAnimation::Running ) {
return KColorUtils::mix( d->fontColor(), d->titleBarColor(), m_opacity );
} else if( isHovered() ) {
return d->titleBarColor();
} else {
return d->fontColor();
}
}
//__________________________________________________________________
QColor Button::backgroundColor() const
{
auto d = qobject_cast<Decoration*>( decoration() );
if( !d ) {
return QColor();
}
auto c = d->client().data();
QColor blueColor( c->palette().color( QPalette::Highlight ) );
if( isPressed() ) {
if( type() == DecorationButtonType::Close ) return blueColor.darker();
else return KColorUtils::mix( d->titleBarColor(), d->fontColor(), 0.3 );
} else if( ( type() == DecorationButtonType::KeepBelow || type() == DecorationButtonType::KeepAbove || type() == DecorationButtonType::Shade ) && isChecked() ) {
return d->fontColor();
} else if( m_animation->state() == QAbstractAnimation::Running ) {
if( type() == DecorationButtonType::Close )
{
if( d->internalSettings()->outlineCloseButton() )
{
return c->isActive() ? KColorUtils::mix( blueColor, blueColor.lighter(), m_opacity ) : KColorUtils::mix( blueColor.lighter(), blueColor, m_opacity );
} else {
QColor color( blueColor.lighter() );
color.setAlpha( color.alpha()*m_opacity );
return color;
}
} else {
QColor color( d->fontColor() );
color.setAlpha( color.alpha()*m_opacity );
return color;
}
} else if( isHovered() ) {
if( type() == DecorationButtonType::Close ) return c->isActive() ? blueColor.lighter() : blueColor;
else return d->fontColor();
} else if( type() == DecorationButtonType::Close && d->internalSettings()->outlineCloseButton() ) {
return c->isActive() ? blueColor : d->fontColor();
} else {
return QColor();
}
}
//________________________________________________________________
void Button::reconfigure()
{
// animation
auto d = qobject_cast<Decoration*>(decoration());
if( d ) m_animation->setDuration( d->animationsDuration() );
}
//__________________________________________________________________
void Button::updateAnimationState( bool hovered )
{
auto d = qobject_cast<Decoration*>(decoration());
if( !(d && d->animationsDuration() > 0 ) ) return;
m_animation->setDirection( hovered ? QAbstractAnimation::Forward : QAbstractAnimation::Backward );
if( m_animation->state() != QAbstractAnimation::Running ) m_animation->start();
}
} // namespace

View File

@ -1,124 +0,0 @@
#ifndef BREEZE_BUTTONS_H
#define BREEZE_BUTTONS_H
/*
* SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
* SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include <KDecoration2/DecorationButton>
#include "breezedecoration.h"
#include <QHash>
#include <QImage>
class QVariantAnimation;
namespace Breeze
{
class Button : public KDecoration2::DecorationButton
{
Q_OBJECT
public:
//* constructor
explicit Button(QObject *parent, const QVariantList &args);
//* destructor
virtual ~Button() = default;
//* button creation
static Button *create(KDecoration2::DecorationButtonType type, KDecoration2::Decoration *decoration, QObject *parent);
//* render
virtual void paint(QPainter *painter, const QRect &repaintRegion) override;
//* flag
enum Flag
{
FlagNone,
FlagStandalone,
FlagFirstInList,
FlagLastInList
};
//* flag
void setFlag( Flag value )
{ m_flag = value; }
//* standalone buttons
bool isStandAlone() const { return m_flag == FlagStandalone; }
//* offset
void setOffset( const QPointF& value )
{ m_offset = value; }
//* horizontal offset, for rendering
void setHorizontalOffset( qreal value )
{ m_offset.setX( value ); }
//* vertical offset, for rendering
void setVerticalOffset( qreal value )
{ m_offset.setY( value ); }
//* set icon size
void setIconSize( const QSize& value )
{ m_iconSize = value; }
//*@name active state change animation
//@{
void setOpacity( qreal value )
{
if( m_opacity == value ) return;
m_opacity = value;
update();
}
qreal opacity() const
{ return m_opacity; }
//@}
private Q_SLOTS:
//* apply configuration changes
void reconfigure();
//* animation state
void updateAnimationState(bool);
private:
//* private constructor
explicit Button(KDecoration2::DecorationButtonType type, Decoration *decoration, QObject *parent = nullptr);
//* draw button icon
void drawIcon( QPainter *) const;
//*@name colors
//@{
QColor foregroundColor() const;
QColor backgroundColor() const;
//@}
Flag m_flag = FlagNone;
//* active state change animation
QVariantAnimation *m_animation;
//* vertical offset (for rendering)
QPointF m_offset;
//* icon size
QSize m_iconSize;
//* active state change opacity
qreal m_opacity = 0;
};
} // namespace
#endif

View File

@ -1,817 +0,0 @@
/*
* SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
* SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
* SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "breezedecoration.h"
#include "breezesettingsprovider.h"
#include "config-breeze.h"
#include "config/breezeconfigwidget.h"
#include "breezebutton.h"
#include "breezesizegrip.h"
#include "breezeboxshadowrenderer.h"
#include <KDecoration2/DecorationButtonGroup>
#include <KDecoration2/DecorationShadow>
#include <KConfigGroup>
#include <KColorUtils>
#include <KSharedConfig>
#include <KPluginFactory>
#include <QPainter>
#include <QTextStream>
#include <QTimer>
#include <QDBusConnection>
#if BREEZE_HAVE_X11
#include <QX11Info>
#endif
#include <cmath>
K_PLUGIN_FACTORY_WITH_JSON(
BreezeDecoFactory,
"breeze.json",
registerPlugin<Breeze::Decoration>();
registerPlugin<Breeze::Button>(QStringLiteral("button"));
registerPlugin<Breeze::ConfigWidget>(QStringLiteral("kcmodule"));
)
namespace
{
struct ShadowParams {
ShadowParams()
: offset(QPoint(0, 0))
, radius(0)
, opacity(0) {}
ShadowParams(const QPoint &offset, int radius, qreal opacity)
: offset(offset)
, radius(radius)
, opacity(opacity) {}
QPoint offset;
int radius;
qreal opacity;
};
struct CompositeShadowParams {
CompositeShadowParams() = default;
CompositeShadowParams(
const QPoint &offset,
const ShadowParams &shadow1,
const ShadowParams &shadow2)
: offset(offset)
, shadow1(shadow1)
, shadow2(shadow2) {}
bool isNone() const {
return qMax(shadow1.radius, shadow2.radius) == 0;
}
QPoint offset;
ShadowParams shadow1;
ShadowParams shadow2;
};
const CompositeShadowParams s_shadowParams[] = {
// None
CompositeShadowParams(),
// Small
CompositeShadowParams(
QPoint(0, 4),
ShadowParams(QPoint(0, 0), 16, 1),
ShadowParams(QPoint(0, -2), 8, 0.4)),
// Medium
CompositeShadowParams(
QPoint(0, 8),
ShadowParams(QPoint(0, 0), 32, 0.9),
ShadowParams(QPoint(0, -4), 16, 0.3)),
// Large
CompositeShadowParams(
QPoint(0, 12),
ShadowParams(QPoint(0, 0), 48, 0.8),
ShadowParams(QPoint(0, -6), 24, 0.2)),
// Very large
CompositeShadowParams(
QPoint(0, 16),
ShadowParams(QPoint(0, 0), 64, 0.7),
ShadowParams(QPoint(0, -8), 32, 0.1)),
};
inline CompositeShadowParams lookupShadowParams(int size)
{
switch (size) {
case Breeze::InternalSettings::ShadowNone:
return s_shadowParams[0];
case Breeze::InternalSettings::ShadowSmall:
return s_shadowParams[1];
case Breeze::InternalSettings::ShadowMedium:
return s_shadowParams[2];
case Breeze::InternalSettings::ShadowLarge:
return s_shadowParams[3];
case Breeze::InternalSettings::ShadowVeryLarge:
return s_shadowParams[4];
default:
// Fallback to the Large size.
return s_shadowParams[3];
}
}
}
namespace Breeze
{
using KDecoration2::ColorRole;
using KDecoration2::ColorGroup;
//________________________________________________________________
static int g_sDecoCount = 0;
static int g_shadowSizeEnum = InternalSettings::ShadowLarge;
static int g_shadowStrength = 255;
static QColor g_shadowColor = Qt::black;
static QSharedPointer<KDecoration2::DecorationShadow> g_sShadow;
static QSharedPointer<KDecoration2::DecorationShadow> g_sShadowInactive;
//________________________________________________________________
Decoration::Decoration(QObject *parent, const QVariantList &args)
: KDecoration2::Decoration(parent, args)
, m_animation( new QVariantAnimation( this ) )
, m_shadowAnimation( new QVariantAnimation( this ) )
{
g_sDecoCount++;
}
//________________________________________________________________
Decoration::~Decoration()
{
g_sDecoCount--;
if (g_sDecoCount == 0) {
// last deco destroyed, clean up shadow
g_sShadow.clear();
}
deleteSizeGrip();
}
//________________________________________________________________
void Decoration::setOpacity( qreal value )
{
if( m_opacity == value ) return;
m_opacity = value;
update();
if( m_sizeGrip ) m_sizeGrip->update();
}
//________________________________________________________________
QColor Decoration::titleBarColor() const
{
auto c = client().data();
if( hideTitleBar() ) return c->color( ColorGroup::Inactive, ColorRole::TitleBar );
else if( m_animation->state() == QAbstractAnimation::Running )
{
return KColorUtils::mix(
c->color( ColorGroup::Inactive, ColorRole::TitleBar ),
c->color( ColorGroup::Active, ColorRole::TitleBar ),
m_opacity );
} else return c->color( c->isActive() ? ColorGroup::Active : ColorGroup::Inactive, ColorRole::TitleBar );
}
//________________________________________________________________
QColor Decoration::outlineColor() const
{
auto c( client().data() );
if( !m_internalSettings->drawTitleBarSeparator() ) return QColor();
if( m_animation->state() == QAbstractAnimation::Running )
{
QColor color( c->palette().color( QPalette::Highlight ) );
color.setAlpha( color.alpha()*m_opacity );
return color;
} else if( c->isActive() ) return c->palette().color( QPalette::Highlight );
else return QColor();
}
//________________________________________________________________
QColor Decoration::fontColor() const
{
auto c = client().data();
if( m_animation->state() == QAbstractAnimation::Running )
{
return KColorUtils::mix(
c->color( ColorGroup::Inactive, ColorRole::Foreground ),
c->color( ColorGroup::Active, ColorRole::Foreground ),
m_opacity );
} else return c->color( c->isActive() ? ColorGroup::Active : ColorGroup::Inactive, ColorRole::Foreground );
}
//________________________________________________________________
void Decoration::init()
{
auto c = client().data();
// active state change animation
// It is important start and end value are of the same type, hence 0.0 and not just 0
m_animation->setStartValue( 0.0 );
m_animation->setEndValue( 1.0 );
// Linear to have the same easing as Breeze animations
m_animation->setEasingCurve( QEasingCurve::Linear );
connect(m_animation, &QVariantAnimation::valueChanged, this, [this](const QVariant &value) {
setOpacity(value.toReal());
});
m_shadowAnimation->setStartValue( 0.0 );
m_shadowAnimation->setEndValue( 1.0 );
m_shadowAnimation->setEasingCurve( QEasingCurve::InCubic );
connect(m_shadowAnimation, &QVariantAnimation::valueChanged, this, [this](const QVariant& value) {
m_shadowOpacity = value.toReal();
updateShadow();
});
// use DBus connection to update on breeze configuration change
auto dbus = QDBusConnection::sessionBus();
dbus.connect( QString(),
QStringLiteral( "/KGlobalSettings" ),
QStringLiteral( "org.kde.KGlobalSettings" ),
QStringLiteral( "notifyChange" ), this, SLOT(reconfigure()) );
reconfigure();
updateTitleBar();
auto s = settings();
connect(s.data(), &KDecoration2::DecorationSettings::borderSizeChanged, this, &Decoration::recalculateBorders);
// a change in font might cause the borders to change
connect(s.data(), &KDecoration2::DecorationSettings::fontChanged, this, &Decoration::recalculateBorders);
connect(s.data(), &KDecoration2::DecorationSettings::spacingChanged, this, &Decoration::recalculateBorders);
// buttons
connect(s.data(), &KDecoration2::DecorationSettings::spacingChanged, this, &Decoration::updateButtonsGeometryDelayed);
connect(s.data(), &KDecoration2::DecorationSettings::decorationButtonsLeftChanged, this, &Decoration::updateButtonsGeometryDelayed);
connect(s.data(), &KDecoration2::DecorationSettings::decorationButtonsRightChanged, this, &Decoration::updateButtonsGeometryDelayed);
// full reconfiguration
connect(s.data(), &KDecoration2::DecorationSettings::reconfigured, this, &Decoration::reconfigure);
connect(s.data(), &KDecoration2::DecorationSettings::reconfigured, SettingsProvider::self(), &SettingsProvider::reconfigure, Qt::UniqueConnection );
connect(s.data(), &KDecoration2::DecorationSettings::reconfigured, this, &Decoration::updateButtonsGeometryDelayed);
connect(c, &KDecoration2::DecoratedClient::adjacentScreenEdgesChanged, this, &Decoration::recalculateBorders);
connect(c, &KDecoration2::DecoratedClient::maximizedHorizontallyChanged, this, &Decoration::recalculateBorders);
connect(c, &KDecoration2::DecoratedClient::maximizedVerticallyChanged, this, &Decoration::recalculateBorders);
connect(c, &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::recalculateBorders);
connect(c, &KDecoration2::DecoratedClient::captionChanged, this,
[this]()
{
// update the caption area
update(titleBar());
}
);
connect(c, &KDecoration2::DecoratedClient::activeChanged, this, &Decoration::updateAnimationState);
connect(c, &KDecoration2::DecoratedClient::widthChanged, this, &Decoration::updateTitleBar);
connect(c, &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateTitleBar);
connect(c, &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::setOpaque);
connect(c, &KDecoration2::DecoratedClient::widthChanged, this, &Decoration::updateButtonsGeometry);
connect(c, &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateButtonsGeometry);
connect(c, &KDecoration2::DecoratedClient::adjacentScreenEdgesChanged, this, &Decoration::updateButtonsGeometry);
connect(c, &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::updateButtonsGeometry);
createButtons();
updateShadow();
}
//________________________________________________________________
void Decoration::updateTitleBar()
{
auto s = settings();
auto c = client().data();
const bool maximized = isMaximized();
const int width = maximized ? c->width() : c->width() - 2*s->largeSpacing()*Metrics::TitleBar_SideMargin;
const int height = maximized ? borderTop() : borderTop() - s->smallSpacing()*Metrics::TitleBar_TopMargin;
const int x = maximized ? 0 : s->largeSpacing()*Metrics::TitleBar_SideMargin;
const int y = maximized ? 0 : s->smallSpacing()*Metrics::TitleBar_TopMargin;
setTitleBar(QRect(x, y, width, height));
}
//________________________________________________________________
void Decoration::updateAnimationState()
{
if( m_shadowAnimation->duration() > 0 )
{
auto c = client().data();
m_shadowAnimation->setDirection( c->isActive() ? QAbstractAnimation::Forward : QAbstractAnimation::Backward );
if( m_shadowAnimation->state() != QAbstractAnimation::Running ) m_shadowAnimation->start();
} else {
updateShadow();
}
if( m_animation->duration() > 0 )
{
auto c = client().data();
m_animation->setDirection( c->isActive() ? QAbstractAnimation::Forward : QAbstractAnimation::Backward );
if( m_animation->state() != QAbstractAnimation::Running ) m_animation->start();
} else {
update();
}
}
//________________________________________________________________
void Decoration::updateSizeGripVisibility()
{
auto c = client().data();
if( m_sizeGrip )
{ m_sizeGrip->setVisible( c->isResizeable() && !isMaximized() && !c->isShaded() ); }
}
//________________________________________________________________
int Decoration::borderSize(bool bottom) const
{
const int baseSize = settings()->smallSpacing();
return baseSize*Metrics::Frame_BorderSize;
}
//________________________________________________________________
void Decoration::reconfigure()
{
m_internalSettings = SettingsProvider::self()->internalSettings( this );
// animation
KSharedConfig::Ptr config = KSharedConfig::openConfig();
const KConfigGroup cg(config, QStringLiteral("KDE"));
m_animation->setDuration(0);
// Syncing anis between client and decoration is troublesome, so we're not using
// any animations right now.
// m_animation->setDuration( cg.readEntry("AnimationDurationFactor", 1.0f) * 100.0f );
// But the shadow is fine to animate like this!
m_shadowAnimation->setDuration( cg.readEntry("AnimationDurationFactor", 1.0f) * 100.0f );
// borders
recalculateBorders();
// shadow
updateShadow();
// size grip
deleteSizeGrip();
}
//________________________________________________________________
void Decoration::recalculateBorders()
{
auto c = client().data();
auto s = settings();
// left, right and bottom borders
const int left = borderSize();
const int right = borderSize();
const int bottom = c->isShaded() ? 0 : borderSize();
int top = 0;
if( hideTitleBar() ) top = bottom;
else {
QFontMetrics fm(s->font());
top += qMax(fm.height(), buttonHeight() );
// padding below
// extra pixel is used for the active window outline
const int baseSize = s->smallSpacing();
top += baseSize*Metrics::TitleBar_BottomMargin + 1;
// padding above
top += baseSize*TitleBar_TopMargin;
}
setBorders(QMargins(left, top, right, bottom));
// extended sizes
const int extSize = s->largeSpacing();
int extSides = 0;
int extBottom = 0;
setResizeOnlyBorders(QMargins(extSides, 0, extSides, extBottom));
}
//________________________________________________________________
void Decoration::createButtons()
{
m_leftButtons = new KDecoration2::DecorationButtonGroup(KDecoration2::DecorationButtonGroup::Position::Left, this, &Button::create);
m_rightButtons = new KDecoration2::DecorationButtonGroup(KDecoration2::DecorationButtonGroup::Position::Right, this, &Button::create);
updateButtonsGeometry();
}
//________________________________________________________________
void Decoration::updateButtonsGeometryDelayed()
{ QTimer::singleShot( 0, this, &Decoration::updateButtonsGeometry ); }
//________________________________________________________________
void Decoration::updateButtonsGeometry()
{
const auto s = settings();
// adjust button position
const int bHeight = captionHeight() + (isTopEdge() ? s->smallSpacing()*Metrics::TitleBar_TopMargin:0);
const int bWidth = buttonHeight();
const int verticalOffset = (isTopEdge() ? s->smallSpacing()*Metrics::TitleBar_TopMargin:0) + (captionHeight()-buttonHeight())/2;
foreach( const QPointer<KDecoration2::DecorationButton>& button, m_leftButtons->buttons() + m_rightButtons->buttons() )
{
button.data()->setGeometry( QRectF( QPoint( 0, 0 ), QSizeF( bWidth, bHeight ) ) );
static_cast<Button*>( button.data() )->setOffset( QPointF( 0, verticalOffset ) );
static_cast<Button*>( button.data() )->setIconSize( QSize( bWidth, bWidth ) );
}
// padding
const int vPadding = isTopEdge() ? 0 : s->smallSpacing()*Metrics::TitleBar_TopMargin;
const int hPadding = s->smallSpacing()*Metrics::TitleBar_SideMargin;
// left buttons
if( !m_leftButtons->buttons().isEmpty() )
{
// spacing
m_leftButtons->setSpacing(s->smallSpacing()*Metrics::TitleBar_ButtonSpacing);
m_leftButtons->setPos(QPointF(hPadding + borderLeft(), vPadding));
}
// right buttons
if( !m_rightButtons->buttons().isEmpty() )
{
// spacing
m_rightButtons->setSpacing(s->smallSpacing()*Metrics::TitleBar_ButtonSpacing);
m_rightButtons->setPos(QPointF(size().width() - m_rightButtons->geometry().width() - hPadding - borderRight(), vPadding));
}
update();
}
//________________________________________________________________
void Decoration::paint(QPainter *painter, const QRect &repaintRegion)
{
// TODO: optimize based on repaintRegion
auto c = client().data();
auto s = settings();
const int radius = s->smallSpacing()*Metrics::Frame_FrameRadius;
// paint background
if( !c->isShaded() )
{
painter->fillRect(rect(), Qt::transparent);
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::NoPen);
painter->setBrush( c->color( c->isActive() ? ColorGroup::Active : ColorGroup::Inactive, ColorRole::Frame ) );
// clip away the top part
if( !hideTitleBar() ) painter->setClipRect(0, borderTop(), size().width(), size().height() - borderTop(), Qt::IntersectClip);
if( s->isAlphaChannelSupported() ) painter->drawRoundedRect(rect(),
isBottomEdge() ? 0:radius,
isBottomEdge() ? 0:radius);
else painter->drawRect( rect() );
painter->restore();
}
if( !hideTitleBar() ) paintTitleBar(painter, repaintRegion);
if( !s->isAlphaChannelSupported() )
{
painter->save();
painter->setRenderHint(QPainter::Antialiasing, false);
painter->setBrush( Qt::NoBrush );
painter->setPen( c->isActive() ?
c->color( ColorGroup::Active, ColorRole::TitleBar ):
c->color( ColorGroup::Inactive, ColorRole::Foreground ) );
painter->drawRect( rect().adjusted( 0, 0, -1, -1 ) );
painter->restore();
}
}
//________________________________________________________________
void Decoration::paintTitleBar(QPainter *painter, const QRect &repaintRegion)
{
const auto c = client().data();
const QRect titleRect(QPoint(0, 0), QSize(size().width(), borderTop()));
if ( !titleRect.intersects(repaintRegion) ) return;
painter->save();
painter->setPen(Qt::NoPen);
// render a linear gradient on title area
if( c->isActive() && m_internalSettings->drawBackgroundGradient() )
{
const QColor titleBarColor( this->titleBarColor() );
QLinearGradient gradient( 0, 0, 0, titleRect.height() );
gradient.setColorAt(0.0, titleBarColor.lighter( 120 ) );
gradient.setColorAt(0.8, titleBarColor);
painter->setBrush(gradient);
} else {
painter->setBrush( titleBarColor() );
}
auto s = settings();
const int radius = s->smallSpacing()*Metrics::Frame_FrameRadius;
if( isMaximized() || !s->isAlphaChannelSupported() )
{
painter->drawRect(titleRect);
} else if( c->isShaded() ) {
painter->drawRoundedRect(titleRect, radius, radius);
} else {
painter->setClipRect(titleRect, Qt::IntersectClip);
// the rect is made a little bit larger to be able to clip away the rounded corners at the bottom and sides
painter->drawRoundedRect(titleRect.adjusted(
isLeftEdge() ? -radius:0,
isTopEdge() ? -radius:0,
isRightEdge() ? radius:0,
radius),
radius, radius);
}
const QColor outlineColor( this->outlineColor() );
if( !c->isShaded() && outlineColor.isValid() )
{
// outline
painter->setRenderHint( QPainter::Antialiasing, false );
painter->setBrush( Qt::NoBrush );
painter->setPen( outlineColor );
painter->drawLine( titleRect.bottomLeft(), titleRect.bottomRight() );
}
painter->restore();
// draw caption
painter->setFont(s->font());
painter->setPen( fontColor() );
const auto cR = captionRect();
const QString caption = painter->fontMetrics().elidedText(c->caption(), Qt::ElideMiddle, cR.first.width());
painter->drawText(cR.first, cR.second | Qt::TextSingleLine, caption);
// draw all buttons
m_leftButtons->paint(painter, repaintRegion);
m_rightButtons->paint(painter, repaintRegion);
}
//________________________________________________________________
int Decoration::buttonHeight() const
{
const int baseSize = settings()->gridUnit();
switch( m_internalSettings->buttonSize() )
{
case InternalSettings::ButtonTiny: return baseSize;
case InternalSettings::ButtonSmall: return baseSize*1.5;
default:
case InternalSettings::ButtonDefault: return baseSize*2;
case InternalSettings::ButtonLarge: return baseSize*2.5;
case InternalSettings::ButtonVeryLarge: return baseSize*3.5;
}
}
//________________________________________________________________
int Decoration::captionHeight() const
{ return hideTitleBar() ? borderTop() : borderTop() - settings()->smallSpacing()*(Metrics::TitleBar_BottomMargin + Metrics::TitleBar_TopMargin ) - 1; }
//________________________________________________________________
QPair<QRect,Qt::Alignment> Decoration::captionRect() const
{
if( hideTitleBar() ) return qMakePair( QRect(), Qt::AlignCenter );
else {
auto c = client().data();
const int leftOffset = m_leftButtons->buttons().isEmpty() ?
Metrics::TitleBar_SideMargin*settings()->smallSpacing():
m_leftButtons->geometry().x() + m_leftButtons->geometry().width() + Metrics::TitleBar_SideMargin*settings()->smallSpacing();
const int rightOffset = m_rightButtons->buttons().isEmpty() ?
Metrics::TitleBar_SideMargin*settings()->smallSpacing() :
size().width() - m_rightButtons->geometry().x() + Metrics::TitleBar_SideMargin*settings()->smallSpacing();
const int yOffset = settings()->smallSpacing()*Metrics::TitleBar_TopMargin;
const QRect maxRect( leftOffset, yOffset, size().width() - leftOffset - rightOffset, captionHeight() );
switch( m_internalSettings->titleAlignment() )
{
case InternalSettings::AlignLeft:
return qMakePair( maxRect, Qt::AlignVCenter|Qt::AlignLeft );
case InternalSettings::AlignRight:
return qMakePair( maxRect, Qt::AlignVCenter|Qt::AlignRight );
case InternalSettings::AlignCenter:
return qMakePair( maxRect, Qt::AlignCenter );
default:
case InternalSettings::AlignCenterFullWidth:
{
// full caption rect
const QRect fullRect = QRect( 0, yOffset, size().width(), captionHeight() );
QRect boundingRect( settings()->fontMetrics().boundingRect( c->caption()).toRect() );
// text bounding rect
boundingRect.setTop( yOffset );
boundingRect.setHeight( captionHeight() );
boundingRect.moveLeft( ( size().width() - boundingRect.width() )/2 );
if( boundingRect.left() < leftOffset ) return qMakePair( maxRect, Qt::AlignVCenter|Qt::AlignLeft );
else if( boundingRect.right() > size().width() - rightOffset ) return qMakePair( maxRect, Qt::AlignVCenter|Qt::AlignRight );
else return qMakePair(fullRect, Qt::AlignCenter);
}
}
}
}
//________________________________________________________________
void Decoration::updateShadow()
{
const auto s = Decoration::settings();
// Animated case, no cached shadow object
if ( (m_shadowAnimation->state() == QAbstractAnimation::Running) && (m_shadowOpacity != 0.0) && (m_shadowOpacity != 1.0) )
{
setShadow(createShadowObject(m_internalSettings, 0.5 + m_shadowOpacity * 0.5, s->smallSpacing()));
return;
}
if (g_shadowSizeEnum != m_internalSettings->shadowSize()
|| g_shadowStrength != m_internalSettings->shadowStrength()
|| g_shadowColor != m_internalSettings->shadowColor())
{
g_sShadow.clear();
g_sShadowInactive.clear();
g_shadowSizeEnum = m_internalSettings->shadowSize();
g_shadowStrength = m_internalSettings->shadowStrength();
g_shadowColor = m_internalSettings->shadowColor();
}
auto c = client().toStrongRef();
auto& shadow = (c->isActive()) ? g_sShadow : g_sShadowInactive;
if ( !shadow )
{
shadow = createShadowObject(m_internalSettings, c->isActive() ? 1.0 : 0.5, s->smallSpacing());
}
setShadow(shadow);
}
//________________________________________________________________
QSharedPointer<KDecoration2::DecorationShadow> Decoration::createShadowObject(const InternalSettingsPtr& internalSettings, const float strengthScale, const int scale)
{
const CompositeShadowParams params = lookupShadowParams(internalSettings->shadowSize());
if (params.isNone())
{
return nullptr;
}
auto withOpacity = [](const QColor& color, qreal opacity) -> QColor {
QColor c(color);
c.setAlphaF(opacity);
return c;
};
const int radius = scale*Metrics::Frame_FrameRadius;
const QSize boxSize = BoxShadowRenderer::calculateMinimumBoxSize(params.shadow1.radius)
.expandedTo(BoxShadowRenderer::calculateMinimumBoxSize(params.shadow2.radius));
BoxShadowRenderer shadowRenderer;
shadowRenderer.setBorderRadius(radius + 0.5);
shadowRenderer.setBoxSize(boxSize);
shadowRenderer.setDevicePixelRatio(1.0); // TODO: Create HiDPI shadows?
const qreal strength = internalSettings->shadowStrength() / 255.0 * strengthScale;
shadowRenderer.addShadow(params.shadow1.offset, params.shadow1.radius,
withOpacity(internalSettings->shadowColor(), params.shadow1.opacity * strength));
shadowRenderer.addShadow(params.shadow2.offset, params.shadow2.radius,
withOpacity(internalSettings->shadowColor(), params.shadow2.opacity * strength));
QImage shadowTexture = shadowRenderer.render();
QPainter painter(&shadowTexture);
painter.setRenderHint(QPainter::Antialiasing);
const QRect outerRect = shadowTexture.rect();
QRect boxRect(QPoint(0, 0), boxSize);
boxRect.moveCenter(outerRect.center());
// Mask out inner rect.
const QMargins padding = QMargins(
boxRect.left() - outerRect.left() - Metrics::Shadow_Overlap - params.offset.x(),
boxRect.top() - outerRect.top() - Metrics::Shadow_Overlap - params.offset.y(),
outerRect.right() - boxRect.right() - Metrics::Shadow_Overlap + params.offset.x(),
outerRect.bottom() - boxRect.bottom() - Metrics::Shadow_Overlap + params.offset.y());
const QRect innerRect = outerRect - padding;
painter.setPen(Qt::NoPen);
painter.setBrush(Qt::black);
painter.setCompositionMode(QPainter::CompositionMode_DestinationOut);
painter.drawRoundedRect(
innerRect,
radius + 0.5,
radius + 0.5);
// Draw outline.
painter.setPen(withOpacity(internalSettings->shadowColor(), 0.2 * strength));
painter.setBrush(Qt::NoBrush);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.drawRoundedRect(
innerRect,
radius - 0.5,
radius - 0.5);
painter.end();
auto ret = QSharedPointer<KDecoration2::DecorationShadow>::create();
ret->setPadding(padding);
ret->setInnerShadowRect(QRect(outerRect.center(), QSize(1, 1)));
ret->setShadow(shadowTexture);
return ret;
}
//_________________________________________________________________
void Decoration::createSizeGrip()
{
// do nothing if size grip already exist
if( m_sizeGrip ) return;
#if BREEZE_HAVE_X11
if( !QX11Info::isPlatformX11() ) return;
// access client
auto c = client().data();
if( !c ) return;
if( c->windowId() != 0 )
{
m_sizeGrip = new SizeGrip( this );
connect( c, &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateSizeGripVisibility );
connect( c, &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::updateSizeGripVisibility );
connect( c, &KDecoration2::DecoratedClient::resizeableChanged, this, &Decoration::updateSizeGripVisibility );
}
#endif
}
//_________________________________________________________________
void Decoration::deleteSizeGrip()
{
if( m_sizeGrip )
{
m_sizeGrip->deleteLater();
m_sizeGrip = nullptr;
}
}
} // namespace
#include "breezedecoration.moc"

View File

@ -1,170 +0,0 @@
#ifndef BREEZE_DECORATION_H
#define BREEZE_DECORATION_H
/*
* SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
* SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "breeze.h"
#include "breezesettings.h"
#include <KDecoration2/Decoration>
#include <KDecoration2/DecoratedClient>
#include <KDecoration2/DecorationSettings>
#include <QPalette>
#include <QVariant>
#include <QVariantAnimation>
class QVariantAnimation;
namespace KDecoration2
{
class DecorationButton;
class DecorationButtonGroup;
}
namespace Breeze
{
class SizeGrip;
class Decoration : public KDecoration2::Decoration
{
Q_OBJECT
public:
//* constructor
explicit Decoration(QObject *parent = nullptr, const QVariantList &args = QVariantList());
//* destructor
virtual ~Decoration();
//* paint
void paint(QPainter *painter, const QRect &repaintRegion) override;
//* internal settings
InternalSettingsPtr internalSettings() const
{ return m_internalSettings; }
qreal animationsDuration() const
{ return m_animation->duration();}
//* caption height
int captionHeight() const;
//* button height
int buttonHeight() const;
//*@name active state change animation
//@{
void setOpacity( qreal );
qreal opacity() const
{ return m_opacity; }
//@}
//*@name colors
//@{
QColor titleBarColor() const;
QColor outlineColor() const;
QColor fontColor() const;
//@}
//*@name maximization modes
//@{
inline bool isMaximized() const;
inline bool isMaximizedHorizontally() const;
inline bool isMaximizedVertically() const;
inline bool isLeftEdge() const;
inline bool isRightEdge() const;
inline bool isTopEdge() const;
inline bool isBottomEdge() const;
inline bool hideTitleBar() const;
//@}
public Q_SLOTS:
void init() override;
private Q_SLOTS:
void reconfigure();
void recalculateBorders();
void updateButtonsGeometry();
void updateButtonsGeometryDelayed();
void updateTitleBar();
void updateAnimationState();
void updateSizeGripVisibility();
private:
//* return the rect in which caption will be drawn
QPair<QRect,Qt::Alignment> captionRect() const;
void createButtons();
void paintTitleBar(QPainter *painter, const QRect &repaintRegion);
void updateShadow();
static QSharedPointer<KDecoration2::DecorationShadow> createShadowObject(const InternalSettingsPtr& internalSettings, const float strengthScale, const int scale);
//*@name border size
//@{
int borderSize(bool bottom = false) const;
//@}
//*@name size grip
//@{
void createSizeGrip();
void deleteSizeGrip();
SizeGrip* sizeGrip() const
{ return m_sizeGrip; }
//@}
InternalSettingsPtr m_internalSettings;
KDecoration2::DecorationButtonGroup *m_leftButtons = nullptr;
KDecoration2::DecorationButtonGroup *m_rightButtons = nullptr;
//* size grip widget
SizeGrip *m_sizeGrip = nullptr;
//* active state change animation
QVariantAnimation *m_animation;
QVariantAnimation *m_shadowAnimation;
//* active state change opacity
qreal m_opacity = 0;
qreal m_shadowOpacity = 0;
};
bool Decoration::isMaximized() const
{ return client().data()->isMaximized() && !m_internalSettings->drawBorderOnMaximizedWindows(); }
bool Decoration::isMaximizedHorizontally() const
{ return client().data()->isMaximizedHorizontally() && !m_internalSettings->drawBorderOnMaximizedWindows(); }
bool Decoration::isMaximizedVertically() const
{ return client().data()->isMaximizedVertically() && !m_internalSettings->drawBorderOnMaximizedWindows(); }
bool Decoration::isLeftEdge() const
{ return (client().data()->isMaximizedHorizontally() || client().data()->adjacentScreenEdges().testFlag( Qt::LeftEdge ) ) && !m_internalSettings->drawBorderOnMaximizedWindows(); }
bool Decoration::isRightEdge() const
{ return (client().data()->isMaximizedHorizontally() || client().data()->adjacentScreenEdges().testFlag( Qt::RightEdge ) ) && !m_internalSettings->drawBorderOnMaximizedWindows(); }
bool Decoration::isTopEdge() const
{ return (client().data()->isMaximizedVertically() || client().data()->adjacentScreenEdges().testFlag( Qt::TopEdge ) ) && !m_internalSettings->drawBorderOnMaximizedWindows(); }
bool Decoration::isBottomEdge() const
{ return (client().data()->isMaximizedVertically() || client().data()->adjacentScreenEdges().testFlag( Qt::BottomEdge ) ) && !m_internalSettings->drawBorderOnMaximizedWindows(); }
bool Decoration::hideTitleBar() const
{ return m_internalSettings->hideTitleBar() && !client().data()->isShaded(); }
}
#endif

View File

@ -1,112 +0,0 @@
//////////////////////////////////////////////////////////////////////////////
// breezeexceptionlist.cpp
// window decoration exceptions
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "breezeexceptionlist.h"
namespace Breeze
{
//______________________________________________________________
void ExceptionList::readConfig( KSharedConfig::Ptr config )
{
_exceptions.clear();
QString groupName;
for( int index = 0; config->hasGroup( groupName = exceptionGroupName( index ) ); ++index )
{
// create exception
InternalSettings exception;
// reset group
readConfig( &exception, config.data(), groupName );
// create new configuration
InternalSettingsPtr configuration( new InternalSettings() );
configuration.data()->load();
// apply changes from exception
configuration->setEnabled( exception.enabled() );
configuration->setExceptionType( exception.exceptionType() );
configuration->setExceptionPattern( exception.exceptionPattern() );
configuration->setMask( exception.mask() );
// propagate all features found in mask to the output configuration
if( exception.mask() & BorderSize ) configuration->setBorderSize( exception.borderSize() );
configuration->setHideTitleBar( exception.hideTitleBar() );
// append to exceptions
_exceptions.append( configuration );
}
}
//______________________________________________________________
void ExceptionList::writeConfig( KSharedConfig::Ptr config )
{
// remove all existing exceptions
QString groupName;
for( int index = 0; config->hasGroup( groupName = exceptionGroupName( index ) ); ++index )
{ config->deleteGroup( groupName ); }
// rewrite current exceptions
int index = 0;
foreach( const InternalSettingsPtr& exception, _exceptions )
{
writeConfig( exception.data(), config.data(), exceptionGroupName( index ) );
++index;
}
}
//_______________________________________________________________________
QString ExceptionList::exceptionGroupName( int index )
{ return QString( "Windeco Exception %1" ).arg( index ); }
//______________________________________________________________
void ExceptionList::writeConfig( KCoreConfigSkeleton* skeleton, KConfig* config, const QString& groupName )
{
// list of items to be written
QStringList keys = { "Enabled", "ExceptionPattern", "ExceptionType", "HideTitleBar", "Mask", "BorderSize"};
// write all items
foreach( auto key, keys )
{
KConfigSkeletonItem* item( skeleton->findItem( key ) );
if( !item ) continue;
if( !groupName.isEmpty() ) item->setGroup( groupName );
KConfigGroup configGroup( config, item->group() );
configGroup.writeEntry( item->key(), item->property() );
}
}
//______________________________________________________________
void ExceptionList::readConfig( KCoreConfigSkeleton* skeleton, KConfig* config, const QString& groupName )
{
foreach( KConfigSkeletonItem* item, skeleton->items() )
{
if( !groupName.isEmpty() ) item->setGroup( groupName );
item->readConfig( config );
}
}
}

View File

@ -1,63 +0,0 @@
#ifndef breezeexceptionlist_h
#define breezeexceptionlist_h
//////////////////////////////////////////////////////////////////////////////
// breezeexceptionlist.h
// window decoration exceptions
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "breezesettings.h"
#include "breeze.h"
#include <KSharedConfig>
namespace Breeze
{
//! breeze exceptions list
class ExceptionList
{
public:
//! constructor from list
explicit ExceptionList( const InternalSettingsList& exceptions = InternalSettingsList() ):
_exceptions( exceptions )
{}
//! exceptions
const InternalSettingsList& get( void ) const
{ return _exceptions; }
//! read from KConfig
void readConfig( KSharedConfig::Ptr );
//! write to kconfig
void writeConfig( KSharedConfig::Ptr );
protected:
//! generate exception group name for given exception index
static QString exceptionGroupName( int index );
//! read configuration
static void readConfig( KCoreConfigSkeleton*, KConfig*, const QString& );
//! write configuration
static void writeConfig( KCoreConfigSkeleton*, KConfig*, const QString& );
private:
//! exceptions
InternalSettingsList _exceptions;
};
}
#endif

View File

@ -1,7 +0,0 @@
File=breezesettingsdata.kcfg
ClassName=InternalSettings
NameSpace=Breeze
Singleton=false
Mutators=true
GlobalEnums=true
Notifiers=OutlineCloseButton

View File

@ -1,117 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name="breezerc"/>
<!-- common options -->
<group name="Common">
<entry name="ShadowStrength" type = "Int">
<default>255</default>
<min>25</min>
<max>255</max>
</entry>
<!-- shadow -->
<entry name="ShadowSize" type = "Enum">
<choices>
<choice name="ShadowNone"/>
<choice name="ShadowSmall"/>
<choice name="ShadowMedium"/>
<choice name="ShadowLarge"/>
<choice name="ShadowVeryLarge"/>
</choices>
<default>ShadowLarge</default>
</entry>
<entry name="ShadowColor" type = "Color">
<default>0, 0, 0</default>
</entry>
<!-- close button -->
<entry name="OutlineCloseButton" type = "Bool">
<default>true</default>
</entry>
</group>
<group name="Windeco">
<!-- border size -->
<!--
this one is used only for window specific settings, since the default is globally set by kwin
the enumeration must be kept in sync with kwin's global settings
-->
<entry name="BorderSize" type = "Enum"></entry>
<!-- title alignment -->
<entry name="TitleAlignment" type="Enum">
<choices>
<choice name="AlignLeft" />
<choice name="AlignCenter" />
<choice name="AlignCenterFullWidth" />
<choice name="AlignRight" />
</choices>
<default>AlignCenterFullWidth</default>
</entry>
<!-- button size -->
<entry name="ButtonSize" type="Enum">
<choices>
<choice name="ButtonTiny" />
<choice name="ButtonSmall" />
<choice name="ButtonDefault" />
<choice name="ButtonLarge" />
<choice name="ButtonVeryLarge" />
</choices>
<default>ButtonDefault</default>
</entry>
<!-- maximized windows -->
<entry name="DrawBorderOnMaximizedWindows" type = "Bool">
<default>false</default>
</entry>
<entry name="DrawTitleBarSeparator" type = "Bool">
<default>false</default>
</entry>
<!-- size grip -->
<entry name="DrawBackgroundGradient" type = "Bool">
<default>false</default>
</entry>
<!-- size grip -->
<entry name="DrawSizeGrip" type = "Bool">
<default>false</default>
</entry>
<!-- hide title bar -->
<entry name="HideTitleBar" type = "Bool">
<default>false</default>
</entry>
<!-- window specific settings -->
<entry name="ExceptionType" type="Enum">
<choices>
<choice name="ExceptionWindowClassName" />
<choice name="ExceptionWindowTitle" />
</choices>
<default>ExceptionWindowClassName</default>
</entry>
<entry name="ExceptionPattern" type = "String"/>
<entry name="Enabled" type = "Bool">
<default>true</default>
</entry>
<entry name="Mask" type = "Int">
<default>0</default>
</entry>
</group>
</kcfg>

View File

@ -1,116 +0,0 @@
/*
* SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "breezesettingsprovider.h"
#include "breezeexceptionlist.h"
#include <KWindowInfo>
#include <QTextStream>
namespace Breeze
{
SettingsProvider *SettingsProvider::s_self = nullptr;
//__________________________________________________________________
SettingsProvider::SettingsProvider():
m_config( KSharedConfig::openConfig( QStringLiteral("breezerc") ) )
{ reconfigure(); }
//__________________________________________________________________
SettingsProvider::~SettingsProvider()
{ s_self = nullptr; }
//__________________________________________________________________
SettingsProvider *SettingsProvider::self()
{
// TODO: this is not thread safe!
if (!s_self)
{ s_self = new SettingsProvider(); }
return s_self;
}
//__________________________________________________________________
void SettingsProvider::reconfigure()
{
if( !m_defaultSettings )
{
m_defaultSettings = InternalSettingsPtr(new InternalSettings());
m_defaultSettings->setCurrentGroup( QStringLiteral("Windeco") );
}
m_defaultSettings->load();
ExceptionList exceptions;
exceptions.readConfig( m_config );
m_exceptions = exceptions.get();
}
//__________________________________________________________________
InternalSettingsPtr SettingsProvider::internalSettings( Decoration *decoration ) const
{
QString windowTitle;
QString className;
// get the client
auto client = decoration->client().data();
foreach( auto internalSettings, m_exceptions )
{
// discard disabled exceptions
if( !internalSettings->enabled() ) continue;
// discard exceptions with empty exception pattern
if( internalSettings->exceptionPattern().isEmpty() ) continue;
/*
decide which value is to be compared
to the regular expression, based on exception type
*/
QString value;
switch( internalSettings->exceptionType() )
{
case InternalSettings::ExceptionWindowTitle:
{
value = windowTitle.isEmpty() ? (windowTitle = client->caption()):windowTitle;
break;
}
default:
case InternalSettings::ExceptionWindowClassName:
{
if( className.isEmpty() )
{
// retrieve class name
KWindowInfo info( client->windowId(), nullptr, NET::WM2WindowClass );
QString window_className( QString::fromUtf8(info.windowClassName()) );
QString window_class( QString::fromUtf8(info.windowClassClass()) );
className = window_className + QStringLiteral(" ") + window_class;
}
value = className;
break;
}
}
// check matching
if( QRegExp( internalSettings->exceptionPattern() ).indexIn( value ) >= 0 )
{ return internalSettings; }
}
return m_defaultSettings;
}
}

View File

@ -1,62 +0,0 @@
#ifndef breezesettingsprovider_h
#define breezesettingsprovider_h
/*
* SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "breezedecoration.h"
#include "breezesettings.h"
#include "breeze.h"
#include <KSharedConfig>
#include <QObject>
namespace Breeze
{
class SettingsProvider: public QObject
{
Q_OBJECT
public:
//* destructor
~SettingsProvider();
//* singleton
static SettingsProvider *self();
//* internal settings for given decoration
InternalSettingsPtr internalSettings(Decoration *) const;
public Q_SLOTS:
//* reconfigure
void reconfigure();
private:
//* constructor
SettingsProvider();
//* default configuration
InternalSettingsPtr m_defaultSettings;
//* exceptions
InternalSettingsList m_exceptions;
//* config object
KSharedConfigPtr m_config;
//* singleton
static SettingsProvider *s_self;
};
}
#endif

View File

@ -1,290 +0,0 @@
/*
* SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "breezesizegrip.h"
#include <KDecoration2/DecoratedClient>
#include <QPainter>
#include <QPolygon>
#include <QTimer>
#if BREEZE_HAVE_X11
#include <QX11Info>
#endif
namespace Breeze
{
//* scoped pointer convenience typedef
template <typename T> using ScopedPointer = QScopedPointer<T, QScopedPointerPodDeleter>;
//_____________________________________________
SizeGrip::SizeGrip( Decoration* decoration ):QWidget(nullptr)
,m_decoration( decoration )
{
setAttribute(Qt::WA_NoSystemBackground );
setAutoFillBackground( false );
// cursor
setCursor( Qt::SizeFDiagCursor );
// size
setFixedSize( QSize( GripSize, GripSize ) );
// mask
setMask( QRegion( QVector<QPoint>{
QPoint( 0, GripSize ),
QPoint( GripSize, 0 ),
QPoint( GripSize, GripSize ),
QPoint( 0, GripSize )} ) );
// embed
embed();
updatePosition();
// connections
auto c = decoration->client().data();
connect( c, &KDecoration2::DecoratedClient::widthChanged, this, &SizeGrip::updatePosition );
connect( c, &KDecoration2::DecoratedClient::heightChanged, this, &SizeGrip::updatePosition );
connect( c, &KDecoration2::DecoratedClient::activeChanged, this, &SizeGrip::updateActiveState );
// show
show();
}
//_____________________________________________
SizeGrip::~SizeGrip()
{}
//_____________________________________________
void SizeGrip::updateActiveState()
{
#if BREEZE_HAVE_X11
if( QX11Info::isPlatformX11() )
{
const quint32 value = XCB_STACK_MODE_ABOVE;
xcb_configure_window( QX11Info::connection(), winId(), XCB_CONFIG_WINDOW_STACK_MODE, &value );
xcb_map_window( QX11Info::connection(), winId() );
}
#endif
update();
}
//_____________________________________________
void SizeGrip::embed()
{
#if BREEZE_HAVE_X11
if( !QX11Info::isPlatformX11() ) return;
auto c = m_decoration.data()->client().data();
xcb_window_t windowId = c->windowId();
if( windowId )
{
/*
find client's parent
we want the size grip to be at the same level as the client in the stack
*/
xcb_window_t current = windowId;
auto connection = QX11Info::connection();
xcb_query_tree_cookie_t cookie = xcb_query_tree_unchecked( connection, current );
ScopedPointer<xcb_query_tree_reply_t> tree(xcb_query_tree_reply( connection, cookie, nullptr ) );
if( !tree.isNull() && tree->parent ) current = tree->parent;
// reparent
xcb_reparent_window( connection, winId(), current, 0, 0 );
setWindowTitle( "Breeze::SizeGrip" );
} else {
hide();
}
#endif
}
//_____________________________________________
void SizeGrip::paintEvent( QPaintEvent* )
{
if( !m_decoration ) return;
// get relevant colors
const QColor backgroundColor( m_decoration.data()->titleBarColor() );
// create and configure painter
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing );
painter.setPen( Qt::NoPen );
painter.setBrush( backgroundColor );
// polygon
painter.drawPolygon( QVector<QPoint> {
QPoint( 0, GripSize ),
QPoint( GripSize, 0 ),
QPoint( GripSize, GripSize ),
QPoint( 0, GripSize )} );
}
//_____________________________________________
void SizeGrip::mousePressEvent( QMouseEvent* event )
{
switch (event->button())
{
case Qt::RightButton:
{
hide();
QTimer::singleShot(5000, this, &QWidget::show);
break;
}
case Qt::MiddleButton:
{
hide();
break;
}
case Qt::LeftButton:
if( rect().contains( event->pos() ) )
{ sendMoveResizeEvent( event->pos() ); }
break;
default: break;
}
}
//_______________________________________________________________________________
void SizeGrip::updatePosition()
{
#if BREEZE_HAVE_X11
if( !QX11Info::isPlatformX11() ) return;
auto c = m_decoration.data()->client().data();
QPoint position(
c->width() - GripSize - Offset,
c->height() - GripSize - Offset );
quint32 values[2] = { quint32(position.x()), quint32(position.y()) };
xcb_configure_window( QX11Info::connection(), winId(), XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values );
#endif
}
//_____________________________________________
void SizeGrip::sendMoveResizeEvent( QPoint position )
{
#if BREEZE_HAVE_X11
if( !QX11Info::isPlatformX11() ) return;
// pointer to connection
auto connection( QX11Info::connection() );
// client
auto c = m_decoration.data()->client().data();
/*
get root position matching position
need to use xcb because the embedding of the widget
breaks QT's mapToGlobal and other methods
*/
QPoint rootPosition( position );
xcb_get_geometry_cookie_t cookie( xcb_get_geometry( connection, winId() ) );
ScopedPointer<xcb_get_geometry_reply_t> reply( xcb_get_geometry_reply( connection, cookie, nullptr ) );
if( reply )
{
// translate coordinates
xcb_translate_coordinates_cookie_t coordCookie( xcb_translate_coordinates(
connection, winId(), reply.data()->root,
-reply.data()->border_width,
-reply.data()->border_width ) );
ScopedPointer< xcb_translate_coordinates_reply_t> coordReply( xcb_translate_coordinates_reply( connection, coordCookie, nullptr ) );
if( coordReply )
{
rootPosition.rx() += coordReply.data()->dst_x;
rootPosition.ry() += coordReply.data()->dst_y;
}
}
// move/resize atom
if( !m_moveResizeAtom )
{
// create atom if not found
const QString atomName( "_NET_WM_MOVERESIZE" );
xcb_intern_atom_cookie_t cookie( xcb_intern_atom( connection, false, atomName.size(), qPrintable( atomName ) ) );
ScopedPointer<xcb_intern_atom_reply_t> reply( xcb_intern_atom_reply( connection, cookie, nullptr ) );
m_moveResizeAtom = reply ? reply->atom:0;
}
if( !m_moveResizeAtom ) return;
// button release event
xcb_button_release_event_t releaseEvent;
memset(&releaseEvent, 0, sizeof(releaseEvent));
releaseEvent.response_type = XCB_BUTTON_RELEASE;
releaseEvent.event = winId();
releaseEvent.child = XCB_WINDOW_NONE;
releaseEvent.root = QX11Info::appRootWindow();
releaseEvent.event_x = position.x();
releaseEvent.event_y = position.y();
releaseEvent.root_x = rootPosition.x();
releaseEvent.root_y = rootPosition.y();
releaseEvent.detail = XCB_BUTTON_INDEX_1;
releaseEvent.state = XCB_BUTTON_MASK_1;
releaseEvent.time = XCB_CURRENT_TIME;
releaseEvent.same_screen = true;
xcb_send_event( connection, false, winId(), XCB_EVENT_MASK_BUTTON_RELEASE, reinterpret_cast<const char*>(&releaseEvent));
xcb_ungrab_pointer( connection, XCB_TIME_CURRENT_TIME );
// move resize event
xcb_client_message_event_t clientMessageEvent;
memset(&clientMessageEvent, 0, sizeof(clientMessageEvent));
clientMessageEvent.response_type = XCB_CLIENT_MESSAGE;
clientMessageEvent.type = m_moveResizeAtom;
clientMessageEvent.format = 32;
clientMessageEvent.window = c->windowId();
clientMessageEvent.data.data32[0] = rootPosition.x();
clientMessageEvent.data.data32[1] = rootPosition.y();
clientMessageEvent.data.data32[2] = 4; // bottom right
clientMessageEvent.data.data32[3] = Qt::LeftButton;
clientMessageEvent.data.data32[4] = 0;
xcb_send_event( connection, false, QX11Info::appRootWindow(),
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
reinterpret_cast<const char*>(&clientMessageEvent) );
xcb_flush( connection );
#endif
}
}

View File

@ -1,87 +0,0 @@
/*
* SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef breezesizegrip_h
#define breezesizegrip_h
#include "breezedecoration.h"
#include "config-breeze.h"
#include <QMouseEvent>
#include <QPaintEvent>
#include <QWidget>
#include <QPointer>
#if BREEZE_HAVE_X11
#include <xcb/xcb.h>
#endif
namespace Breeze
{
//* implements size grip for all widgets
class SizeGrip: public QWidget
{
Q_OBJECT
public:
//* constructor
explicit SizeGrip( Decoration* );
//* constructor
virtual ~SizeGrip();
protected Q_SLOTS:
//* update background color
void updateActiveState();
//* update position
void updatePosition();
//* embed into parent widget
void embed();
protected:
//*@name event handlers
//@{
//* paint
virtual void paintEvent( QPaintEvent* ) override;
//* mouse press
virtual void mousePressEvent( QMouseEvent* ) override;
//@}
private:
//* send resize event
void sendMoveResizeEvent( QPoint );
//* grip size
enum {
Offset = 0,
GripSize = 14
};
//* decoration
QPointer<Decoration> m_decoration;
//* move/resize atom
#if BREEZE_HAVE_X11
xcb_atom_t m_moveResizeAtom = 0;
#endif
};
}
#endif

View File

@ -1,15 +0,0 @@
/* config-breeze.h. Generated by cmake from config-breeze.h.cmake */
/*
* SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef config_breeze_h
#define config_breeze_h
/* Define to 1 if XCB libraries are found */
#cmakedefine01 BREEZE_HAVE_X11
#endif

View File

@ -1,187 +0,0 @@
//////////////////////////////////////////////////////////////////////////////
// breezeconfigurationui.cpp
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "breezeconfigwidget.h"
#include "breezeexceptionlist.h"
#include <KLocalizedString>
#include <QDBusConnection>
#include <QDBusMessage>
namespace Breeze
{
//_________________________________________________________
ConfigWidget::ConfigWidget( QWidget* parent, const QVariantList &args ):
KCModule(parent, args),
m_configuration( KSharedConfig::openConfig( QStringLiteral( "breezerc" ) ) ),
m_changed( false )
{
// configuration
m_ui.setupUi( this );
// track ui changes
connect( m_ui.titleAlignment, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) );
connect( m_ui.buttonSize, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) );
connect( m_ui.outlineCloseButton, &QAbstractButton::clicked, this, &ConfigWidget::updateChanged );
connect( m_ui.drawBorderOnMaximizedWindows, &QAbstractButton::clicked, this, &ConfigWidget::updateChanged );
connect( m_ui.drawSizeGrip, &QAbstractButton::clicked, this, &ConfigWidget::updateChanged );
connect( m_ui.drawBackgroundGradient, &QAbstractButton::clicked, this, &ConfigWidget::updateChanged );
connect( m_ui.drawTitleBarSeparator, &QAbstractButton::clicked, this, &ConfigWidget::updateChanged );
// track shadows changes
connect( m_ui.shadowSize, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) );
connect( m_ui.shadowStrength, SIGNAL(valueChanged(int)), SLOT(updateChanged()) );
connect( m_ui.shadowColor, &KColorButton::changed, this, &ConfigWidget::updateChanged );
// track exception changes
connect( m_ui.exceptions, &ExceptionListWidget::changed, this, &ConfigWidget::updateChanged );
}
//_________________________________________________________
void ConfigWidget::load()
{
// create internal settings and load from rc files
m_internalSettings = InternalSettingsPtr( new InternalSettings() );
m_internalSettings->load();
// assign to ui
m_ui.titleAlignment->setCurrentIndex( m_internalSettings->titleAlignment() );
m_ui.buttonSize->setCurrentIndex( m_internalSettings->buttonSize() );
m_ui.drawBorderOnMaximizedWindows->setChecked( m_internalSettings->drawBorderOnMaximizedWindows() );
m_ui.outlineCloseButton->setChecked( m_internalSettings->outlineCloseButton() );
m_ui.drawSizeGrip->setChecked( m_internalSettings->drawSizeGrip() );
m_ui.drawBackgroundGradient->setChecked( m_internalSettings->drawBackgroundGradient() );
m_ui.drawTitleBarSeparator->setChecked( m_internalSettings->drawTitleBarSeparator() );
// load shadows
if( m_internalSettings->shadowSize() <= InternalSettings::ShadowVeryLarge ) m_ui.shadowSize->setCurrentIndex( m_internalSettings->shadowSize() );
else m_ui.shadowSize->setCurrentIndex( InternalSettings::ShadowLarge );
m_ui.shadowStrength->setValue( qRound(qreal(m_internalSettings->shadowStrength()*100)/255 ) );
m_ui.shadowColor->setColor( m_internalSettings->shadowColor() );
// load exceptions
ExceptionList exceptions;
exceptions.readConfig( m_configuration );
m_ui.exceptions->setExceptions( exceptions.get() );
setChanged( false );
}
//_________________________________________________________
void ConfigWidget::save()
{
// create internal settings and load from rc files
m_internalSettings = InternalSettingsPtr( new InternalSettings() );
m_internalSettings->load();
// apply modifications from ui
m_internalSettings->setTitleAlignment( m_ui.titleAlignment->currentIndex() );
m_internalSettings->setButtonSize( m_ui.buttonSize->currentIndex() );
m_internalSettings->setOutlineCloseButton( m_ui.outlineCloseButton->isChecked() );
m_internalSettings->setDrawBorderOnMaximizedWindows( m_ui.drawBorderOnMaximizedWindows->isChecked() );
m_internalSettings->setDrawSizeGrip( m_ui.drawSizeGrip->isChecked() );
m_internalSettings->setDrawBackgroundGradient( m_ui.drawBackgroundGradient->isChecked() );
m_internalSettings->setDrawTitleBarSeparator(m_ui.drawTitleBarSeparator->isChecked());
m_internalSettings->setShadowSize( m_ui.shadowSize->currentIndex() );
m_internalSettings->setShadowStrength( qRound( qreal(m_ui.shadowStrength->value()*255)/100 ) );
m_internalSettings->setShadowColor( m_ui.shadowColor->color() );
// save configuration
m_internalSettings->save();
// get list of exceptions and write
InternalSettingsList exceptions( m_ui.exceptions->exceptions() );
ExceptionList( exceptions ).writeConfig( m_configuration );
// sync configuration
m_configuration->sync();
setChanged( false );
// needed to tell kwin to reload when running from external kcmshell
{
QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
}
// needed for breeze style to reload shadows
{
QDBusMessage message( QDBusMessage::createSignal("/BreezeDecoration", "org.kde.Breeze.Style", "reparseConfiguration") );
QDBusConnection::sessionBus().send(message);
}
}
//_________________________________________________________
void ConfigWidget::defaults()
{
// create internal settings and load from rc files
m_internalSettings = InternalSettingsPtr( new InternalSettings() );
m_internalSettings->setDefaults();
// assign to ui
m_ui.titleAlignment->setCurrentIndex( m_internalSettings->titleAlignment() );
m_ui.buttonSize->setCurrentIndex( m_internalSettings->buttonSize() );
m_ui.outlineCloseButton->setChecked( m_internalSettings->outlineCloseButton() );
m_ui.drawBorderOnMaximizedWindows->setChecked( m_internalSettings->drawBorderOnMaximizedWindows() );
m_ui.drawSizeGrip->setChecked( m_internalSettings->drawSizeGrip() );
m_ui.drawBackgroundGradient->setChecked( m_internalSettings->drawBackgroundGradient() );
m_ui.drawTitleBarSeparator->setChecked( m_internalSettings->drawTitleBarSeparator() );
m_ui.shadowSize->setCurrentIndex( m_internalSettings->shadowSize() );
m_ui.shadowStrength->setValue( qRound(qreal(m_internalSettings->shadowStrength()*100)/255 ) );
m_ui.shadowColor->setColor( m_internalSettings->shadowColor() );
}
//_______________________________________________
void ConfigWidget::updateChanged()
{
// check configuration
if( !m_internalSettings ) return;
// track modifications
bool modified( false );
if (m_ui.drawTitleBarSeparator->isChecked() != m_internalSettings->drawTitleBarSeparator()) modified = true;
if( m_ui.titleAlignment->currentIndex() != m_internalSettings->titleAlignment() ) modified = true;
else if( m_ui.buttonSize->currentIndex() != m_internalSettings->buttonSize() ) modified = true;
else if( m_ui.outlineCloseButton->isChecked() != m_internalSettings->outlineCloseButton() ) modified = true;
else if( m_ui.drawBorderOnMaximizedWindows->isChecked() != m_internalSettings->drawBorderOnMaximizedWindows() ) modified = true;
else if( m_ui.drawSizeGrip->isChecked() != m_internalSettings->drawSizeGrip() ) modified = true;
else if( m_ui.drawBackgroundGradient->isChecked() != m_internalSettings->drawBackgroundGradient() ) modified = true;
// shadows
else if( m_ui.shadowSize->currentIndex() != m_internalSettings->shadowSize() ) modified = true;
else if( qRound( qreal(m_ui.shadowStrength->value()*255)/100 ) != m_internalSettings->shadowStrength() ) modified = true;
else if( m_ui.shadowColor->color() != m_internalSettings->shadowColor() ) modified = true;
// exceptions
else if( m_ui.exceptions->isChanged() ) modified = true;
setChanged( modified );
}
//_______________________________________________
void ConfigWidget::setChanged( bool value )
{
emit changed( value );
}
}

View File

@ -1,77 +0,0 @@
#ifndef breezeconfigwidget_h
#define breezeconfigwidget_h
//////////////////////////////////////////////////////////////////////////////
// breezeconfigurationui.h
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "ui_breezeconfigurationui.h"
#include "breezeexceptionlistwidget.h"
#include "breezesettings.h"
#include "breeze.h"
#include <KCModule>
#include <KSharedConfig>
#include <QWidget>
#include <QSharedPointer>
namespace Breeze
{
//_____________________________________________
class ConfigWidget: public KCModule
{
Q_OBJECT
public:
//* constructor
explicit ConfigWidget( QWidget*, const QVariantList& );
//* destructor
virtual ~ConfigWidget() = default;
//* default
void defaults() override;
//* load configuration
void load() override;
//* save configuration
void save() override;
protected Q_SLOTS:
//* update changed state
virtual void updateChanged();
protected:
//* set changed state
void setChanged( bool );
private:
//* ui
Ui_BreezeConfigurationUI m_ui;
//* kconfiguration object
KSharedConfig::Ptr m_configuration;
//* internal exception
InternalSettingsPtr m_internalSettings;
//* changed state
bool m_changed;
};
}
#endif

View File

@ -1,166 +0,0 @@
//////////////////////////////////////////////////////////////////////////////
// breezedetectwidget.cpp
// Note: this class is a stripped down version of
// /kdebase/workspace/kwin/kcmkwin/kwinrules/detectwidget.cpp
// SPDX-FileCopyrightText: 2004 Lubos Lunak <l.lunak@kde.org>
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "breezedetectwidget.h"
#include "breeze.h"
#include <KWindowInfo>
#include <QPushButton>
#include <QMouseEvent>
#include <config-breeze.h>
#if BREEZE_HAVE_X11
#include <QX11Info>
#include <xcb/xcb.h>
#endif
namespace Breeze
{
//_________________________________________________________
DetectDialog::DetectDialog( QWidget* parent ):
QDialog( parent )
{
// setup
m_ui.setupUi( this );
connect( m_ui.buttonBox->button( QDialogButtonBox::Cancel ), &QAbstractButton::clicked, this, &QWidget::close );
m_ui.windowClassCheckBox->setChecked( true );
#if BREEZE_HAVE_X11
if (QX11Info::isPlatformX11()) {
// create atom
xcb_connection_t* connection( QX11Info::connection() );
const QString atomName( QStringLiteral( "WM_STATE" ) );
xcb_intern_atom_cookie_t cookie( xcb_intern_atom( connection, false, atomName.size(), qPrintable( atomName ) ) );
QScopedPointer<xcb_intern_atom_reply_t, QScopedPointerPodDeleter> reply( xcb_intern_atom_reply( connection, cookie, nullptr) );
m_wmStateAtom = reply ? reply->atom : 0;
}
#endif
}
//_________________________________________________________
void DetectDialog::detect( WId window )
{
if( window == 0 ) selectWindow();
else readWindow( window );
}
//_________________________________________________________
void DetectDialog::readWindow( WId window )
{
if( window == 0 )
{
emit detectionDone( false );
return;
}
m_info.reset(new KWindowInfo( window, NET::WMAllProperties, NET::WM2AllProperties ));
if( !m_info->valid())
{
emit detectionDone( false );
return;
}
const QString wmClassClass( QString::fromUtf8( m_info->windowClassClass() ) );
const QString wmClassName( QString::fromUtf8( m_info->windowClassName() ) );
m_ui.windowClass->setText( QStringLiteral( "%1 (%2 %3)" ).arg( wmClassClass ).arg( wmClassName ).arg( wmClassClass ) );
m_ui.windowTitle->setText( m_info->name() );
emit detectionDone( exec() == QDialog::Accepted );
}
//_________________________________________________________
void DetectDialog::selectWindow()
{
// use a dialog, so that all user input is blocked
// use WX11BypassWM and moving away so that it's not actually visible
// grab only mouse, so that keyboard can be used e.g. for switching windows
m_grabber = new QDialog( nullptr, Qt::X11BypassWindowManagerHint );
m_grabber->move( -1000, -1000 );
m_grabber->setModal( true );
m_grabber->show();
// need to explicitly override cursor for Qt5
qApp->setOverrideCursor( Qt::CrossCursor );
m_grabber->grabMouse( Qt::CrossCursor );
m_grabber->installEventFilter( this );
}
//_________________________________________________________
bool DetectDialog::eventFilter( QObject* o, QEvent* e )
{
// check object and event type
if( o != m_grabber ) return false;
if( e->type() != QEvent::MouseButtonRelease ) return false;
// need to explicitly release cursor for Qt5
qApp->restoreOverrideCursor();
// delete old m_grabber
delete m_grabber;
m_grabber = nullptr;
// check button
if( static_cast< QMouseEvent* >( e )->button() != Qt::LeftButton ) return true;
// read window information
readWindow( findWindow() );
return true;
}
//_________________________________________________________
WId DetectDialog::findWindow()
{
#if BREEZE_HAVE_X11
if (!QX11Info::isPlatformX11()) {
return 0;
}
// check atom
if( !m_wmStateAtom ) return 0;
xcb_connection_t* connection( QX11Info::connection() );
xcb_window_t parent( QX11Info::appRootWindow() );
// why is there a loop of only 10 here
for( int i = 0; i < 10; ++i )
{
// query pointer
xcb_query_pointer_cookie_t pointerCookie( xcb_query_pointer( connection, parent ) );
QScopedPointer<xcb_query_pointer_reply_t, QScopedPointerPodDeleter> pointerReply( xcb_query_pointer_reply( connection, pointerCookie, nullptr ) );
if( !( pointerReply && pointerReply->child ) ) return 0;
const xcb_window_t child( pointerReply->child );
xcb_get_property_cookie_t cookie( xcb_get_property( connection, 0, child, m_wmStateAtom, XCB_GET_PROPERTY_TYPE_ANY, 0, 0 ) );
QScopedPointer<xcb_get_property_reply_t, QScopedPointerPodDeleter> reply( xcb_get_property_reply( connection, cookie, nullptr ) );
if( reply && reply->type ) return child;
else parent = child;
}
#endif
return 0;
}
}

View File

@ -1,97 +0,0 @@
#ifndef breezedetectwidget_h
#define breezedetectwidget_h
//////////////////////////////////////////////////////////////////////////////
// breezedetectwidget.h
// Note: this class is a stripped down version of
// /kdebase/workspace/kwin/kcmkwin/kwinrules/detectwidget.h
// SPDX-FileCopyrightText: 2004 Lubos Lunak <l.lunak@kde.org>
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "breezesettings.h"
#include "ui_breezedetectwidget.h"
#include <QByteArray>
#include <QCheckBox>
#include <QDialog>
#include <QEvent>
#include <QLabel>
#include <kwindowsystem.h>
namespace Breeze
{
class DetectDialog : public QDialog
{
Q_OBJECT
public:
//* constructor
explicit DetectDialog( QWidget* );
//* read window properties or select one from mouse grab
void detect( WId window );
//* selected class
QByteArray selectedClass() const;
//* window information
const KWindowInfo& windowInfo() const
{ return *(m_info.data()); }
//* exception type
InternalSettings::EnumExceptionType exceptionType() const
{
if( m_ui.windowClassCheckBox->isChecked() ) return InternalSettings::ExceptionWindowClassName;
else if( m_ui.windowTitleCheckBox->isChecked() ) return InternalSettings::ExceptionWindowTitle;
else return InternalSettings::ExceptionWindowClassName;
}
Q_SIGNALS:
void detectionDone( bool );
protected:
bool eventFilter( QObject* o, QEvent* e ) override;
private:
//* select window from grab
void selectWindow();
//* read window properties
void readWindow( WId window );
//* find window under cursor
WId findWindow();
//* execute
void executeDialog();
//* ui
Ui::BreezeDetectWidget m_ui;
//* invisible dialog used to grab mouse
QDialog* m_grabber = nullptr;
//* current window information
QScopedPointer<KWindowInfo> m_info;
//* wm state atom
quint32 m_wmStateAtom = 0;
};
} // namespace
#endif

View File

@ -1,168 +0,0 @@
//////////////////////////////////////////////////////////////////////////////
// breezeexceptiondialog.cpp
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "breezeexceptiondialog.h"
#include "breezedetectwidget.h"
#include "config-breeze.h"
#if BREEZE_HAVE_X11
#include <QX11Info>
#endif
namespace Breeze
{
//___________________________________________
ExceptionDialog::ExceptionDialog( QWidget* parent ):
QDialog( parent )
{
m_ui.setupUi( this );
connect( m_ui.buttonBox->button( QDialogButtonBox::Cancel ), &QAbstractButton::clicked, this, &QWidget::close );
// store checkboxes from ui into list
m_checkboxes.insert( BorderSize, m_ui.borderSizeCheckBox );
// detect window properties
connect( m_ui.detectDialogButton, &QAbstractButton::clicked, this, &ExceptionDialog::selectWindowProperties );
// connections
connect( m_ui.exceptionType, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) );
connect( m_ui.exceptionEditor, &QLineEdit::textChanged, this, &ExceptionDialog::updateChanged );
connect( m_ui.borderSizeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) );
for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter )
{ connect( iter.value(), &QAbstractButton::clicked, this, &ExceptionDialog::updateChanged ); }
connect( m_ui.hideTitleBar, &QAbstractButton::clicked, this, &ExceptionDialog::updateChanged );
// hide detection dialog on non X11 platforms
#if BREEZE_HAVE_X11
if( !QX11Info::isPlatformX11() ) m_ui.detectDialogButton->hide();
#else
m_ui.detectDialogButton->hide();
#endif
}
//___________________________________________
void ExceptionDialog::setException( InternalSettingsPtr exception )
{
// store exception internally
m_exception = exception;
// type
m_ui.exceptionType->setCurrentIndex(m_exception->exceptionType() );
m_ui.exceptionEditor->setText( m_exception->exceptionPattern() );
m_ui.borderSizeComboBox->setCurrentIndex( m_exception->borderSize() );
m_ui.hideTitleBar->setChecked( m_exception->hideTitleBar() );
// mask
for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter )
{ iter.value()->setChecked( m_exception->mask() & iter.key() ); }
setChanged( false );
}
//___________________________________________
void ExceptionDialog::save()
{
m_exception->setExceptionType( m_ui.exceptionType->currentIndex() );
m_exception->setExceptionPattern( m_ui.exceptionEditor->text() );
m_exception->setBorderSize( m_ui.borderSizeComboBox->currentIndex() );
m_exception->setHideTitleBar( m_ui.hideTitleBar->isChecked() );
// mask
unsigned int mask = None;
for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter )
{ if( iter.value()->isChecked() ) mask |= iter.key(); }
m_exception->setMask( mask );
setChanged( false );
}
//___________________________________________
void ExceptionDialog::updateChanged()
{
bool modified( false );
if( m_exception->exceptionType() != m_ui.exceptionType->currentIndex() ) modified = true;
else if( m_exception->exceptionPattern() != m_ui.exceptionEditor->text() ) modified = true;
else if( m_exception->borderSize() != m_ui.borderSizeComboBox->currentIndex() ) modified = true;
else if( m_exception->hideTitleBar() != m_ui.hideTitleBar->isChecked() ) modified = true;
else
{
// check mask
for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter )
{
if( iter.value()->isChecked() != (bool)( m_exception->mask() & iter.key() ) )
{
modified = true;
break;
}
}
}
setChanged( modified );
}
//___________________________________________
void ExceptionDialog::selectWindowProperties()
{
// create widget
if( !m_detectDialog )
{
m_detectDialog = new DetectDialog( this );
connect( m_detectDialog, &DetectDialog::detectionDone, this, &ExceptionDialog::readWindowProperties );
}
m_detectDialog->detect(0);
}
//___________________________________________
void ExceptionDialog::readWindowProperties( bool valid )
{
Q_CHECK_PTR( m_detectDialog );
if( valid )
{
// type
m_ui.exceptionType->setCurrentIndex( m_detectDialog->exceptionType() );
// window info
const KWindowInfo& info( m_detectDialog->windowInfo() );
switch( m_detectDialog->exceptionType() )
{
default:
case InternalSettings::ExceptionWindowClassName:
m_ui.exceptionEditor->setText( QString::fromUtf8( info.windowClassClass() ) );
break;
case InternalSettings::ExceptionWindowTitle:
m_ui.exceptionEditor->setText( info.name() );
break;
}
}
delete m_detectDialog;
m_detectDialog = nullptr;
}
}

View File

@ -1,98 +0,0 @@
#ifndef breezeexceptiondialog_h
#define breezeexceptiondialog_h
//////////////////////////////////////////////////////////////////////////////
// breezeexceptiondialog.h
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "ui_breezeexceptiondialog.h"
#include "breeze.h"
#include <QCheckBox>
#include <QMap>
namespace Breeze
{
class DetectDialog;
//* breeze exceptions list
class ExceptionDialog: public QDialog
{
Q_OBJECT
public:
//* constructor
explicit ExceptionDialog( QWidget* parent );
//* destructor
virtual ~ExceptionDialog()
{}
//* set exception
void setException( InternalSettingsPtr );
//* save exception
void save();
//* true if changed
virtual bool isChanged() const
{ return m_changed; }
Q_SIGNALS:
//* emitted when changed
void changed( bool );
protected:
//* set changed state
virtual void setChanged( bool value )
{
m_changed = value;
emit changed( value );
}
protected Q_SLOTS:
//* check whether configuration is changed and emit appropriate signal if yes
virtual void updateChanged();
private Q_SLOTS:
//* select window properties from grabbed pointers
void selectWindowProperties();
//* read properties of selected window
void readWindowProperties( bool );
private:
//* map mask and checkbox
using CheckBoxMap=QMap< ExceptionMask, QCheckBox*>;
Ui::BreezeExceptionDialog m_ui;
//* map mask and checkbox
CheckBoxMap m_checkboxes;
//* internal exception
InternalSettingsPtr m_exception;
//* detection dialog
DetectDialog* m_detectDialog = nullptr;
//* changed state
bool m_changed = false;
};
}
#endif

View File

@ -1,329 +0,0 @@
//////////////////////////////////////////////////////////////////////////////
// breezeexceptionlistwidget.cpp
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "breezeexceptionlistwidget.h"
#include "breezeexceptiondialog.h"
#include <KLocalizedString>
#include <QMessageBox>
#include <QPointer>
#include <QIcon>
//__________________________________________________________
namespace Breeze
{
//__________________________________________________________
ExceptionListWidget::ExceptionListWidget( QWidget* parent ):
QWidget( parent )
{
// ui
m_ui.setupUi( this );
// list
m_ui.exceptionListView->setAllColumnsShowFocus( true );
m_ui.exceptionListView->setRootIsDecorated( false );
m_ui.exceptionListView->setSortingEnabled( false );
m_ui.exceptionListView->setModel( &model() );
m_ui.exceptionListView->sortByColumn( ExceptionModel::ColumnType, Qt::AscendingOrder );
m_ui.exceptionListView->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Ignored ) );
m_ui.moveUpButton->setIcon( QIcon::fromTheme( QStringLiteral( "arrow-up" ) ) );
m_ui.moveDownButton->setIcon( QIcon::fromTheme( QStringLiteral( "arrow-down" ) ) );
m_ui.addButton->setIcon( QIcon::fromTheme( QStringLiteral( "list-add" ) ) );
m_ui.removeButton->setIcon( QIcon::fromTheme( QStringLiteral( "list-remove" ) ) );
m_ui.editButton->setIcon( QIcon::fromTheme( QStringLiteral( "edit-rename" ) ) );
connect( m_ui.addButton, &QAbstractButton::clicked, this, &ExceptionListWidget::add );
connect( m_ui.editButton, &QAbstractButton::clicked, this, &ExceptionListWidget::edit );
connect( m_ui.removeButton, &QAbstractButton::clicked, this, &ExceptionListWidget::remove );
connect( m_ui.moveUpButton, &QAbstractButton::clicked, this, &ExceptionListWidget::up );
connect( m_ui.moveDownButton, &QAbstractButton::clicked, this, &ExceptionListWidget::down );
connect( m_ui.exceptionListView, &QAbstractItemView::activated, this, &ExceptionListWidget::edit );
connect( m_ui.exceptionListView, &QAbstractItemView::clicked, this, &ExceptionListWidget::toggle );
connect( m_ui.exceptionListView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ExceptionListWidget::updateButtons );
updateButtons();
resizeColumns();
}
//__________________________________________________________
void ExceptionListWidget::setExceptions( const InternalSettingsList& exceptions )
{
model().set( exceptions );
resizeColumns();
setChanged( false );
}
//__________________________________________________________
InternalSettingsList ExceptionListWidget::exceptions()
{
return model().get();
setChanged( false );
}
//__________________________________________________________
void ExceptionListWidget::updateButtons()
{
bool hasSelection( !m_ui.exceptionListView->selectionModel()->selectedRows().empty() );
m_ui.removeButton->setEnabled( hasSelection );
m_ui.editButton->setEnabled( hasSelection );
m_ui.moveUpButton->setEnabled( hasSelection && !m_ui.exceptionListView->selectionModel()->isRowSelected( 0, QModelIndex() ) );
m_ui.moveDownButton->setEnabled( hasSelection && !m_ui.exceptionListView->selectionModel()->isRowSelected( model().rowCount()-1, QModelIndex() ) );
}
//_______________________________________________________
void ExceptionListWidget::add()
{
QPointer<ExceptionDialog> dialog = new ExceptionDialog( this );
dialog->setWindowTitle( i18n( "New Exception - Breeze Settings" ) );
InternalSettingsPtr exception( new InternalSettings() );
exception->load();
dialog->setException( exception );
// run dialog and check existence
if( !dialog->exec() )
{
delete dialog;
return;
}
dialog->save();
delete dialog;
// check exceptions
if( !checkException( exception ) ) return;
// create new item
model().add( exception );
setChanged( true );
// make sure item is selected
QModelIndex index( model().index( exception ) );
if( index != m_ui.exceptionListView->selectionModel()->currentIndex() )
{
m_ui.exceptionListView->selectionModel()->select( index, QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Rows );
m_ui.exceptionListView->selectionModel()->setCurrentIndex( index, QItemSelectionModel::Current|QItemSelectionModel::Rows );
}
resizeColumns();
}
//_______________________________________________________
void ExceptionListWidget::edit()
{
// retrieve selection
QModelIndex current( m_ui.exceptionListView->selectionModel()->currentIndex() );
if( ! model().contains( current ) ) return;
InternalSettingsPtr exception( model().get( current ) );
// create dialog
QPointer<ExceptionDialog> dialog( new ExceptionDialog( this ) );
dialog->setWindowTitle( i18n( "Edit Exception - Breeze Settings" ) );
dialog->setException( exception );
// map dialog
if( !dialog->exec() )
{
delete dialog;
return;
}
// check modifications
if( !dialog->isChanged() ) return;
// retrieve exception
dialog->save();
delete dialog;
// check new exception validity
checkException( exception );
resizeColumns();
setChanged( true );
}
//_______________________________________________________
void ExceptionListWidget::remove()
{
// confirmation dialog
{
QMessageBox messageBox( QMessageBox::Question, i18n("Question - Breeze Settings" ), i18n("Remove selected exception?"), QMessageBox::Yes | QMessageBox::Cancel );
messageBox.button( QMessageBox::Yes )->setText( i18n("Remove") );
messageBox.setDefaultButton( QMessageBox::Cancel );
if( messageBox.exec() == QMessageBox::Cancel ) return;
}
// remove
model().remove( model().get( m_ui.exceptionListView->selectionModel()->selectedRows() ) );
resizeColumns();
updateButtons();
setChanged( true );
}
//_______________________________________________________
void ExceptionListWidget::toggle( const QModelIndex& index )
{
if( !model().contains( index ) ) return;
if( index.column() != ExceptionModel::ColumnEnabled ) return;
// get matching exception
InternalSettingsPtr exception( model().get( index ) );
exception->setEnabled( !exception->enabled() );
setChanged( true );
}
//_______________________________________________________
void ExceptionListWidget::up()
{
InternalSettingsList selection( model().get( m_ui.exceptionListView->selectionModel()->selectedRows() ) );
if( selection.empty() ) { return; }
// retrieve selected indexes in list and store in model
QModelIndexList selectedIndices( m_ui.exceptionListView->selectionModel()->selectedRows() );
InternalSettingsList selectedExceptions( model().get( selectedIndices ) );
InternalSettingsList currentException( model().get() );
InternalSettingsList newExceptions;
for( InternalSettingsList::const_iterator iter = currentException.constBegin(); iter != currentException.constEnd(); ++iter )
{
// check if new list is not empty, current index is selected and last index is not.
// if yes, move.
if(
!( newExceptions.empty() ||
selectedIndices.indexOf( model().index( *iter ) ) == -1 ||
selectedIndices.indexOf( model().index( newExceptions.back() ) ) != -1
) )
{
InternalSettingsPtr last( newExceptions.back() );
newExceptions.removeLast();
newExceptions.append( *iter );
newExceptions.append( last );
} else newExceptions.append( *iter );
}
model().set( newExceptions );
// restore selection
m_ui.exceptionListView->selectionModel()->select( model().index( selectedExceptions.front() ), QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Rows );
for( InternalSettingsList::const_iterator iter = selectedExceptions.constBegin(); iter != selectedExceptions.constEnd(); ++iter )
{ m_ui.exceptionListView->selectionModel()->select( model().index( *iter ), QItemSelectionModel::Select|QItemSelectionModel::Rows ); }
setChanged( true );
}
//_______________________________________________________
void ExceptionListWidget::down()
{
InternalSettingsList selection( model().get( m_ui.exceptionListView->selectionModel()->selectedRows() ) );
if( selection.empty() )
{ return; }
// retrieve selected indexes in list and store in model
QModelIndexList selectedIndices( m_ui.exceptionListView->selectionModel()->selectedIndexes() );
InternalSettingsList selectedExceptions( model().get( selectedIndices ) );
InternalSettingsList currentExceptions( model().get() );
InternalSettingsList newExceptions;
InternalSettingsListIterator iter( currentExceptions );
iter.toBack();
while( iter.hasPrevious() )
{
InternalSettingsPtr current( iter.previous() );
// check if new list is not empty, current index is selected and last index is not.
// if yes, move.
if(
!( newExceptions.empty() ||
selectedIndices.indexOf( model().index( current ) ) == -1 ||
selectedIndices.indexOf( model().index( newExceptions.front() ) ) != -1
) )
{
InternalSettingsPtr first( newExceptions.front() );
newExceptions.removeFirst();
newExceptions.prepend( current );
newExceptions.prepend( first );
} else newExceptions.prepend( current );
}
model().set( newExceptions );
// restore selection
m_ui.exceptionListView->selectionModel()->select( model().index( selectedExceptions.front() ), QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Rows );
for( InternalSettingsList::const_iterator iter = selectedExceptions.constBegin(); iter != selectedExceptions.constEnd(); ++iter )
{ m_ui.exceptionListView->selectionModel()->select( model().index( *iter ), QItemSelectionModel::Select|QItemSelectionModel::Rows ); }
setChanged( true );
}
//_______________________________________________________
void ExceptionListWidget::resizeColumns() const
{
m_ui.exceptionListView->resizeColumnToContents( ExceptionModel::ColumnEnabled );
m_ui.exceptionListView->resizeColumnToContents( ExceptionModel::ColumnType );
m_ui.exceptionListView->resizeColumnToContents( ExceptionModel::ColumnRegExp );
}
//_______________________________________________________
bool ExceptionListWidget::checkException( InternalSettingsPtr exception )
{
while( exception->exceptionPattern().isEmpty() || !QRegExp( exception->exceptionPattern() ).isValid() )
{
QMessageBox::warning( this, i18n( "Warning - Breeze Settings" ), i18n("Regular Expression syntax is incorrect") );
QPointer<ExceptionDialog> dialog( new ExceptionDialog( this ) );
dialog->setException( exception );
if( dialog->exec() == QDialog::Rejected )
{
delete dialog;
return false;
}
dialog->save();
delete dialog;
}
return true;
}
}

View File

@ -1,108 +0,0 @@
#ifndef breezeexceptionlistwidget_h
#define breezeexceptionlistwidget_h
//////////////////////////////////////////////////////////////////////////////
// breezeexceptionlistwidget.h
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "ui_breezeexceptionlistwidget.h"
#include "breezeexceptionmodel.h"
//* QDialog used to commit selected files
namespace Breeze
{
class ExceptionListWidget: public QWidget
{
//* Qt meta object
Q_OBJECT
public:
//* constructor
explicit ExceptionListWidget( QWidget* = nullptr );
//* set exceptions
void setExceptions( const InternalSettingsList& );
//* get exceptions
InternalSettingsList exceptions();
//* true if changed
virtual bool isChanged() const
{ return m_changed; }
Q_SIGNALS:
//* emitted when changed
void changed( bool );
protected:
//* model
const ExceptionModel& model() const
{ return m_model; }
//* model
ExceptionModel& model()
{ return m_model; }
protected Q_SLOTS:
//* update button states
virtual void updateButtons();
//* add
virtual void add();
//* edit
virtual void edit();
//* remove
virtual void remove();
//* toggle
virtual void toggle( const QModelIndex& );
//* move up
virtual void up();
//* move down
virtual void down();
protected:
//* resize columns
void resizeColumns() const;
//* check exception
bool checkException( InternalSettingsPtr );
//* set changed state
virtual void setChanged( bool value )
{
m_changed = value;
emit changed( value );
}
private:
//* model
ExceptionModel m_model;
//* ui
Ui_BreezeExceptionListWidget m_ui;
//* changed state
bool m_changed = false;
};
}
#endif

View File

@ -1,91 +0,0 @@
//////////////////////////////////////////////////////////////////////////////
// breezeexceptionmodel.cpp
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "breezeexceptionmodel.h"
#include <KLocalizedString>
namespace Breeze
{
//_______________________________________________
const QString ExceptionModel::m_columnTitles[ ExceptionModel::nColumns ] =
{
QStringLiteral( "" ),
i18n("Exception Type"),
i18n("Regular Expression")
};
//__________________________________________________________________
QVariant ExceptionModel::data( const QModelIndex& index, int role ) const
{
// check index, role and column
if( !index.isValid() ) return QVariant();
// retrieve associated file info
const InternalSettingsPtr& configuration( get(index) );
// return text associated to file and column
if( role == Qt::DisplayRole )
{
switch( index.column() )
{
case ColumnType:
{
switch( configuration->exceptionType() )
{
case InternalSettings::ExceptionWindowTitle:
return i18n( "Window Title" );
default:
case InternalSettings::ExceptionWindowClassName:
return i18n( "Window Class Name" );
}
}
case ColumnRegExp: return configuration->exceptionPattern();
default: return QVariant();
break;
}
} else if( role == Qt::CheckStateRole && index.column() == ColumnEnabled ) {
return configuration->enabled() ? Qt::Checked : Qt::Unchecked;
} else if( role == Qt::ToolTipRole && index.column() == ColumnEnabled ) {
return i18n("Enable/disable this exception");
}
return QVariant();
}
//__________________________________________________________________
QVariant ExceptionModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(
orientation == Qt::Horizontal &&
role == Qt::DisplayRole &&
section >= 0 &&
section < nColumns )
{ return m_columnTitles[section]; }
// return empty
return QVariant();
}
}

View File

@ -1,65 +0,0 @@
#ifndef breezeexceptionmodel_h
#define breezeexceptionmodel_h
//////////////////////////////////////////////////////////////////////////////
// breezeexceptionmodel.h
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "breezelistmodel.h"
#include "breezesettings.h"
#include "breeze.h"
namespace Breeze
{
//* qlistview for object counters
class ExceptionModel: public ListModel<InternalSettingsPtr>
{
public:
//* number of columns
enum { nColumns = 3 };
//* column type enumeration
enum ColumnType {
ColumnEnabled,
ColumnType,
ColumnRegExp
};
//*@name methods reimplemented from base class
//@{
//* return data for a given index
QVariant data(const QModelIndex &index, int role) const override;
//* header data
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
//* number of columns for a given index
int columnCount(const QModelIndex& ) const override
{ return nColumns; }
//@}
protected:
//* sort
void privateSort( int, Qt::SortOrder ) override
{}
private:
//* column titles
static const QString m_columnTitles[ nColumns ];
};
}
#endif

View File

@ -1,52 +0,0 @@
//////////////////////////////////////////////////////////////////////////////
// itemmodel.cpp
// -------------------
//
// SPDX-FileCopyrightText: 2009-2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "breezeitemmodel.h"
namespace Breeze
{
//_______________________________________________________________
ItemModel::ItemModel( QObject* parent ):
QAbstractItemModel( parent )
{}
//____________________________________________________________
void ItemModel::sort( int column, Qt::SortOrder order )
{
// store column and order
m_sortColumn = column;
m_sortOrder = order;
// emit signals and call private methods
emit layoutAboutToBeChanged();
privateSort( column, order );
emit layoutChanged();
}
//____________________________________________________________
QModelIndexList ItemModel::indexes( int column, const QModelIndex& parent ) const
{
QModelIndexList out;
int rows( rowCount( parent ) );
for( int row = 0; row < rows; row++ )
{
QModelIndex index( this->index( row, column, parent ) );
if( !index.isValid() ) continue;
out.append( index );
out += indexes( column, index );
}
return out;
}
}

View File

@ -1,97 +0,0 @@
#ifndef ItemModel_h
#define ItemModel_h
//////////////////////////////////////////////////////////////////////////////
// itemmodel.h
// -------------------
//
// SPDX-FileCopyrightText: 2009-2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include <QAbstractItemModel>
namespace Breeze
{
//* Job model. Stores job information for display in lists
class ItemModel : public QAbstractItemModel
{
public:
//* constructor
explicit ItemModel(QObject *parent = nullptr);
//* destructor
virtual ~ItemModel()
{}
//* return all indexes in model starting from parent [recursive]
QModelIndexList indexes( int column = 0, const QModelIndex& parent = QModelIndex() ) const;
//*@name sorting
//@{
//* sort
virtual void sort()
{ sort( sortColumn(), sortOrder() ); }
//* sort
void sort( int column, Qt::SortOrder order = Qt::AscendingOrder ) override;
//* current sorting column
const int& sortColumn() const
{ return m_sortColumn; }
//* current sort order
const Qt::SortOrder& sortOrder() const
{ return m_sortOrder; }
//@}
protected:
//* this sort columns without calling the layout changed callbacks
void privateSort()
{ privateSort( m_sortColumn, m_sortOrder ); }
//* private sort, with no signals emitted
virtual void privateSort( int column, Qt::SortOrder order ) = 0;
//* used to sort items in list
class SortFTor
{
public:
//* constructor
explicit SortFTor( const int& type, Qt::SortOrder order = Qt::AscendingOrder ):
_type( type ),
_order( order )
{}
protected:
//* column
int _type;
//* order
Qt::SortOrder _order;
};
private:
//* sorting column
int m_sortColumn = 0;
//* sorting order
Qt::SortOrder m_sortOrder = Qt::AscendingOrder;
};
}
#endif

View File

@ -1,349 +0,0 @@
#ifndef ListModel_h
#define ListModel_h
//////////////////////////////////////////////////////////////////////////////
// listmodel.h
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "breezeitemmodel.h"
#include <QSet>
#include <QList>
#include <algorithm>
namespace Breeze
{
//! Job model. Stores job information for display in lists
template<class T> class ListModel : public ItemModel
{
public:
//! value type
typedef T ValueType;
//! reference
typedef T& Reference;
//! pointer
typedef T* Pointer;
//! value list and iterators
typedef QList<ValueType> List;
typedef QListIterator<ValueType> ListIterator;
typedef QMutableListIterator<ValueType> MutableListIterator;
//! list of vector
// typedef QSet<ValueType> Set;
//! constructor
ListModel(QObject *parent = nullptr):
ItemModel( parent )
{}
//! destructor
virtual ~ListModel()
{}
//!@name methods reimplemented from base class
//@{
//! flags
Qt::ItemFlags flags(const QModelIndex &index) const override
{
if (!index.isValid()) return Qt::NoItemFlags;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
//! unique index for given row, column and parent index
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override
{
// check if index is valid
if( !hasIndex( row, column, parent ) ) return QModelIndex();
// return invalid index if parent is valid
if( parent.isValid() ) return QModelIndex();
// check against _values
return ( row < (int) _values.size() ) ? createIndex( row, column ):QModelIndex();
}
//! index of parent
QModelIndex parent(const QModelIndex &) const override
{ return QModelIndex(); }
//! number of rows below given index
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{ return parent.isValid() ? 0:_values.size(); }
//@}
//!@name selection
//@{
//! clear internal list selected items
virtual void clearSelectedIndexes()
{ _selection.clear(); }
//! store index internal selection state
virtual void setIndexSelected( const QModelIndex& index, bool value )
{
if( value ) _selection.push_back( get(index) );
else _selection.erase( std::remove( _selection.begin(), _selection.end(), get(index) ), _selection.end() );
}
//! get list of internal selected items
virtual QModelIndexList selectedIndexes() const
{
QModelIndexList out;
for( typename List::const_iterator iter = _selection.begin(); iter != _selection.end(); iter++ )
{
QModelIndex index( ListModel::index( *iter ) );
if( index.isValid() ) out.push_back( index );
}
return out;
}
//@}
//!@name interface
//@{
//! add value
virtual void add( const ValueType& value )
{
emit layoutAboutToBeChanged();
_add( value );
privateSort();
emit layoutChanged();
}
//! add values
virtual void add( const List& values )
{
// check if not empty
// this avoids sending useless signals
if( values.empty() ) return;
emit layoutAboutToBeChanged();
for( typename List::const_iterator iter = values.begin(); iter != values.end(); iter++ )
{ _add( *iter ); }
privateSort();
emit layoutChanged();
}
//! insert values
virtual void insert( const QModelIndex& index, const ValueType& value )
{
emit layoutAboutToBeChanged();
_insert( index, value );
emit layoutChanged();
}
//! insert values
virtual void insert( const QModelIndex& index, const List& values )
{
emit layoutAboutToBeChanged();
// need to loop in reverse order so that the "values" ordering is preserved
ListIterator iter( values );
iter.toBack();
while( iter.hasPrevious() )
{ _insert( index, iter.previous() ); }
emit layoutChanged();
}
//! insert values
virtual void replace( const QModelIndex& index, const ValueType& value )
{
if( !index.isValid() ) add( value );
else {
emit layoutAboutToBeChanged();
setIndexSelected( index, false );
_values[index.row()] = value;
setIndexSelected( index, true );
emit layoutChanged();
}
}
//! remove
virtual void remove( const ValueType& value )
{
emit layoutAboutToBeChanged();
_remove( value );
emit layoutChanged();
}
//! remove
virtual void remove( const List& values )
{
// check if not empty
// this avoids sending useless signals
if( values.empty() ) return;
emit layoutAboutToBeChanged();
for( typename List::const_iterator iter = values.begin(); iter != values.end(); iter++ )
{ _remove( *iter ); }
emit layoutChanged();
}
//! clear
virtual void clear()
{ set( List() ); }
//! update values from list
/*!
values that are not found in current are removed
new values are set to the end.
This is slower than the "set" method, but the selection is not cleared in the process
*/
virtual void update( List values )
{
emit layoutAboutToBeChanged();
// store values to be removed
List removed_values;
// update values that are common to both lists
for( typename List::iterator iter = _values.begin(); iter != _values.end(); iter++ )
{
// see if iterator is in list
typename List::iterator found_iter( std::find( values.begin(), values.end(), *iter ) );
if( found_iter == values.end() ) removed_values.push_back( *iter );
else {
*iter = *found_iter;
values.erase( found_iter );
}
}
// remove values that have not been found in new list
for( typename List::const_iterator iter = removed_values.constBegin(); iter != removed_values.constEnd(); iter++ )
{ _remove( *iter ); }
// add remaining values
for( typename List::const_iterator iter = values.constBegin(); iter != values.constEnd(); iter++ )
{ _add( *iter ); }
privateSort();
emit layoutChanged();
}
//! set all values
virtual void set( const List& values )
{
emit layoutAboutToBeChanged();
_values = values;
_selection.clear();
privateSort();
emit layoutChanged();
}
//! return all values
const List& get( void ) const
{ return _values; }
//! return value for given index
virtual ValueType get( const QModelIndex& index ) const
{ return (index.isValid() && index.row() < int(_values.size()) ) ? _values[index.row()]:ValueType(); }
//! return value for given index
virtual ValueType& get( const QModelIndex& index )
{
Q_ASSERT( index.isValid() && index.row() < int( _values.size() ) );
return _values[index.row()];
}
//! return all values
List get( const QModelIndexList& indexes ) const
{
List out;
for( QModelIndexList::const_iterator iter = indexes.begin(); iter != indexes.end(); iter++ )
{ if( iter->isValid() && iter->row() < int(_values.size()) ) out.push_back( get( *iter ) ); }
return out;
}
//! return index associated to a given value
virtual QModelIndex index( const ValueType& value, int column = 0 ) const
{
for( int row = 0; row < _values.size(); ++row )
{ if( value == _values[row] ) return index( row, column ); }
return QModelIndex();
}
//@}
//! return true if model contains given index
virtual bool contains( const QModelIndex& index ) const
{ return index.isValid() && index.row() < _values.size(); }
protected:
//! return all values
List& _get( void )
{ return _values; }
//! add, without update
virtual void _add( const ValueType& value )
{
typename List::iterator iter = std::find( _values.begin(), _values.end(), value );
if( iter == _values.end() ) _values.push_back( value );
else *iter = value;
}
//! add, without update
virtual void _insert( const QModelIndex& index, const ValueType& value )
{
if( !index.isValid() ) add( value );
int row = 0;
typename List::iterator iter( _values.begin() );
for( ;iter != _values.end() && row != index.row(); iter++, row++ )
{}
_values.insert( iter, value );
}
//! remove, without update
virtual void _remove( const ValueType& value )
{
_values.erase( std::remove( _values.begin(), _values.end(), value ), _values.end() );
_selection.erase( std::remove( _selection.begin(), _selection.end(), value ), _selection.end() );
}
private:
//! values
List _values;
//! selection
List _selection;
};
}
#endif

View File

@ -1,341 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BreezeConfigurationUI</class>
<widget class="QWidget" name="BreezeConfigurationUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>428</width>
<height>418</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>General</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Tit&amp;le alignment:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>titleAlignment</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>B&amp;utton size:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>buttonSize</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="buttonSize">
<item>
<property name="text">
<string>Tiny</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Button size:">Small</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Button size:">Medium</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Button size:">Large</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Button size:">Very Large</string>
</property>
</item>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="titleAlignment">
<item>
<property name="text">
<string>Left</string>
</property>
</item>
<item>
<property name="text">
<string>Center</string>
</property>
</item>
<item>
<property name="text">
<string>Center (Full Width)</string>
</property>
</item>
<item>
<property name="text">
<string>Right</string>
</property>
</item>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="7" column="0" colspan="3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0" colspan="3">
<widget class="QCheckBox" name="drawSizeGrip">
<property name="text">
<string>Add handle to resize windows with no border</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="3">
<widget class="QCheckBox" name="drawTitleBarSeparator">
<property name="text">
<string>Draw separator under active window's titlebar</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QCheckBox" name="drawBorderOnMaximizedWindows">
<property name="text">
<string>Allow resizing maximized windows from window edges</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<widget class="QCheckBox" name="outlineCloseButton">
<property name="text">
<string>Draw a circle around close button</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QCheckBox" name="drawBackgroundGradient">
<property name="text">
<string>Draw titlebar background gradient</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_4">
<attribute name="title">
<string>Shadows</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Si&amp;ze:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>shadowSize</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="shadowSize">
<item>
<property name="text">
<string comment="@item:inlistbox Button size:">None</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Button size:">Small</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Button size:">Medium</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Button size:">Large</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Button size:">Very Large</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string comment="strength of the shadow (from transparent to opaque)">S&amp;trength:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>shadowStrength</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="shadowStrength">
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Color:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="KColorButton" name="shadowColor"/>
</item>
<item row="3" column="0" colspan="3">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Window-Specific Overrides</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="Breeze::ExceptionListWidget" name="exceptions" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KColorButton</class>
<extends>QPushButton</extends>
<header>kcolorbutton.h</header>
</customwidget>
<customwidget>
<class>Breeze::ExceptionListWidget</class>
<extends>QWidget</extends>
<header>config/breezeexceptionlistwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>titleAlignment</tabstop>
<tabstop>buttonSize</tabstop>
<tabstop>outlineCloseButton</tabstop>
<tabstop>drawBorderOnMaximizedWindows</tabstop>
<tabstop>drawBackgroundGradient</tabstop>
<tabstop>drawSizeGrip</tabstop>
<tabstop>drawTitleBarSeparator</tabstop>
<tabstop>shadowSize</tabstop>
<tabstop>shadowStrength</tabstop>
<tabstop>shadowColor</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -1,146 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BreezeDetectWidget</class>
<widget class="QDialog" name="BreezeDetectWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>239</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Information about Selected Window</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Class: </string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="windowClass">
<property name="text">
<string notr="true">TextLabel</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Title: </string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="windowTitle">
<property name="text">
<string notr="true">TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Window Property Selection</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QRadioButton" name="windowClassCheckBox">
<property name="text">
<string>Use window class (whole application)</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="windowTitleCheckBox">
<property name="locale">
<locale language="French" country="France"/>
</property>
<property name="text">
<string>Use window title</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>BreezeDetectWidget</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>BreezeDetectWidget</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,231 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BreezeExceptionDialog</class>
<widget class="QDialog" name="BreezeExceptionDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>362</width>
<height>321</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Window Identification</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Matching window property: </string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>exceptionType</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Regular expression &amp;to match: </string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>exceptionEditor</cstring>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="detectDialogButton">
<property name="text">
<string>Detect Window Properties</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QLineEdit" name="exceptionEditor">
<property name="showClearButton" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="exceptionType">
<item>
<property name="text">
<string>Window Class Name</string>
</property>
</item>
<item>
<property name="text">
<string>Window Title</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Decoration Options</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QCheckBox" name="borderSizeCheckBox">
<property name="text">
<string>Border size:</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="hideTitleBar">
<property name="text">
<string>Hide window title bar</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="borderSizeComboBox">
<property name="enabled">
<bool>false</bool>
</property>
<item>
<property name="text">
<string comment="@item:inlistbox Border size:">No Border</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Border size:">No Side Borders</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Border size:">Tiny</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Border size:">Normal</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Border size:">Large</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Border size:">Very Large</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Border size:">Huge</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Border size:">Very Huge</string>
</property>
</item>
<item>
<property name="text">
<string comment="@item:inlistbox Border size:">Oversized</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>BreezeExceptionDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>252</x>
<y>342</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>BreezeExceptionDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>320</x>
<y>342</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>borderSizeCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>borderSizeComboBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>125</x>
<y>162</y>
</hint>
<hint type="destinationlabel">
<x>316</x>
<y>163</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,114 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BreezeExceptionListWidget</class>
<widget class="QWidget" name="BreezeExceptionListWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>473</width>
<height>182</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0" rowspan="6">
<widget class="QTreeView" name="exceptionListView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
</widget>
</item>
<item row="5" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="moveUpButton">
<property name="text">
<string>Move Up</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="moveDownButton">
<property name="text">
<string>Move Down</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="addButton">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="removeButton">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QPushButton" name="editButton">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>exceptionListView</tabstop>
<tabstop>moveUpButton</tabstop>
<tabstop>moveDownButton</tabstop>
<tabstop>addButton</tabstop>
<tabstop>removeButton</tabstop>
<tabstop>editButton</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -1,19 +0,0 @@
################# dependencies #################
### Qt/KDE
find_package(Qt5 REQUIRED CONFIG COMPONENTS Widgets)
################# breezestyle target #################
set(breezecommon_LIB_SRCS
breezeboxshadowrenderer.cpp
)
add_library(kali-breezecommon5 ${breezecommon_LIB_SRCS})
generate_export_header(kali-breezecommon5
BASE_NAME breezecommon
EXPORT_FILE_NAME breezecommon_export.h)
target_link_libraries(kali-breezecommon5
PUBLIC
Qt5::Core
Qt5::Gui)

View File

@ -1,350 +0,0 @@
/*
* SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
*
* The box blur implementation is based on AlphaBoxBlur from Firefox.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* 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
*/
// own
#include "breezeboxshadowrenderer.h"
// Qt
#include <QPainter>
#include <QtMath>
namespace Breeze
{
static inline int calculateBlurRadius(qreal stdDev)
{
// See https://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement
const qreal gaussianScaleFactor = (3.0 * qSqrt(2.0 * M_PI) / 4.0) * 1.5;
return qMax(2, qFloor(stdDev * gaussianScaleFactor + 0.5));
}
static inline qreal calculateBlurStdDev(int radius)
{
// See https://www.w3.org/TR/css-backgrounds-3/#shadow-blur
return radius * 0.5;
}
static inline QSize calculateBlurExtent(int radius)
{
const int blurRadius = calculateBlurRadius(calculateBlurStdDev(radius));
return QSize(blurRadius, blurRadius);
}
struct BoxLobes
{
int left; ///< how many pixels sample to the left
int right; ///< how many pixels sample to the right
};
/**
* Compute box filter parameters.
*
* @param radius The blur radius.
* @returns Parameters for three box filters.
**/
static QVector<BoxLobes> computeLobes(int radius)
{
const int blurRadius = calculateBlurRadius(calculateBlurStdDev(radius));
const int z = blurRadius / 3;
int major;
int minor;
int final;
switch (blurRadius % 3) {
case 0:
major = z;
minor = z;
final = z;
break;
case 1:
major = z + 1;
minor = z;
final = z;
break;
case 2:
major = z + 1;
minor = z;
final = z + 1;
break;
default:
Q_UNREACHABLE();
}
Q_ASSERT(major + minor + final == blurRadius);
return {
{major, minor},
{minor, major},
{final, final}
};
}
/**
* Process a row with a box filter.
*
* @param src The start of the row.
* @param dst The destination.
* @param width The width of the row, in pixels.
* @param horizontalStride The number of bytes from one alpha value to the
* next alpha value.
* @param verticalStride The number of bytes from one row to the next row.
* @param lobes Params of the box filter.
* @param transposeInput Whether the input is transposed.
* @param transposeOutput Whether the output should be transposed.
**/
static inline void boxBlurRowAlpha(const uint8_t *src, uint8_t *dst, int width, int horizontalStride,
int verticalStride, const BoxLobes &lobes, bool transposeInput,
bool transposeOutput)
{
const int inputStep = transposeInput ? verticalStride : horizontalStride;
const int outputStep = transposeOutput ? verticalStride : horizontalStride;
const int boxSize = lobes.left + 1 + lobes.right;
const int reciprocal = (1 << 24) / boxSize;
uint32_t alphaSum = (boxSize + 1) / 2;
const uint8_t *left = src;
const uint8_t *right = src;
uint8_t *out = dst;
const uint8_t firstValue = src[0];
const uint8_t lastValue = src[(width - 1) * inputStep];
alphaSum += firstValue * lobes.left;
const uint8_t *initEnd = src + (boxSize - lobes.left) * inputStep;
while (right < initEnd) {
alphaSum += *right;
right += inputStep;
}
const uint8_t *leftEnd = src + boxSize * inputStep;
while (right < leftEnd) {
*out = (alphaSum * reciprocal) >> 24;
alphaSum += *right - firstValue;
right += inputStep;
out += outputStep;
}
const uint8_t *centerEnd = src + width * inputStep;
while (right < centerEnd) {
*out = (alphaSum * reciprocal) >> 24;
alphaSum += *right - *left;
left += inputStep;
right += inputStep;
out += outputStep;
}
const uint8_t *rightEnd = dst + width * outputStep;
while (out < rightEnd) {
*out = (alphaSum * reciprocal) >> 24;
alphaSum += lastValue - *left;
left += inputStep;
out += outputStep;
}
}
/**
* Blur the alpha channel of a given image.
*
* @param image The input image.
* @param radius The blur radius.
* @param rect Specifies what part of the image to blur. If nothing is provided, then
* the whole alpha channel of the input image will be blurred.
**/
static inline void boxBlurAlpha(QImage &image, int radius, const QRect &rect = {})
{
if (radius < 2) {
return;
}
const QVector<BoxLobes> lobes = computeLobes(radius);
const QRect blurRect = rect.isNull() ? image.rect() : rect;
const int alphaOffset = QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3;
const int width = blurRect.width();
const int height = blurRect.height();
const int rowStride = image.bytesPerLine();
const int pixelStride = image.depth() >> 3;
const int bufferStride = qMax(width, height) * pixelStride;
QScopedPointer<uint8_t, QScopedPointerArrayDeleter<uint8_t> > buf(new uint8_t[2 * bufferStride]);
uint8_t *buf1 = buf.data();
uint8_t *buf2 = buf1 + bufferStride;
// Blur the image in horizontal direction.
for (int i = 0; i < height; ++i) {
uint8_t *row = image.scanLine(blurRect.y() + i) + blurRect.x() * pixelStride + alphaOffset;
boxBlurRowAlpha(row, buf1, width, pixelStride, rowStride, lobes[0], false, false);
boxBlurRowAlpha(buf1, buf2, width, pixelStride, rowStride, lobes[1], false, false);
boxBlurRowAlpha(buf2, row, width, pixelStride, rowStride, lobes[2], false, false);
}
// Blur the image in vertical direction.
for (int i = 0; i < width; ++i) {
uint8_t *column = image.scanLine(blurRect.y()) + (blurRect.x() + i) * pixelStride + alphaOffset;
boxBlurRowAlpha(column, buf1, height, pixelStride, rowStride, lobes[0], true, false);
boxBlurRowAlpha(buf1, buf2, height, pixelStride, rowStride, lobes[1], false, false);
boxBlurRowAlpha(buf2, column, height, pixelStride, rowStride, lobes[2], false, true);
}
}
static inline void mirrorTopLeftQuadrant(QImage &image)
{
const int width = image.width();
const int height = image.height();
const int centerX = qCeil(width * 0.5);
const int centerY = qCeil(height * 0.5);
const int alphaOffset = QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3;
const int stride = image.depth() >> 3;
for (int y = 0; y < centerY; ++y) {
uint8_t *in = image.scanLine(y) + alphaOffset;
uint8_t *out = in + (width - 1) * stride;
for (int x = 0; x < centerX; ++x, in += stride, out -= stride) {
*out = *in;
}
}
for (int y = 0; y < centerY; ++y) {
const uint8_t *in = image.scanLine(y) + alphaOffset;
uint8_t *out = image.scanLine(width - y - 1) + alphaOffset;
for (int x = 0; x < width; ++x, in += stride, out += stride) {
*out = *in;
}
}
}
static void renderShadow(QPainter *painter, const QRect &rect, qreal borderRadius, const QPoint &offset, int radius, const QColor &color)
{
const QSize inflation = calculateBlurExtent(radius);
const QSize size = rect.size() + 2 * inflation;
const qreal dpr = painter->device()->devicePixelRatioF();
QImage shadow(size * dpr, QImage::Format_ARGB32_Premultiplied);
shadow.setDevicePixelRatio(dpr);
shadow.fill(Qt::transparent);
QRect boxRect(QPoint(0, 0), rect.size());
boxRect.moveCenter(QRect(QPoint(0, 0), size).center());
const qreal xRadius = 2.0 * borderRadius / boxRect.width();
const qreal yRadius = 2.0 * borderRadius / boxRect.height();
QPainter shadowPainter;
shadowPainter.begin(&shadow);
shadowPainter.setRenderHint(QPainter::Antialiasing);
shadowPainter.setPen(Qt::NoPen);
shadowPainter.setBrush(Qt::black);
shadowPainter.drawRoundedRect(boxRect, xRadius, yRadius);
shadowPainter.end();
// Because the shadow texture is symmetrical, that's enough to blur
// only the top-left quadrant and then mirror it.
const QRect blurRect(0, 0, qCeil(shadow.width() * 0.5), qCeil(shadow.height() * 0.5));
const int scaledRadius = qRound(radius * dpr);
boxBlurAlpha(shadow, scaledRadius, blurRect);
mirrorTopLeftQuadrant(shadow);
// Give the shadow a tint of the desired color.
shadowPainter.begin(&shadow);
shadowPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
shadowPainter.fillRect(shadow.rect(), color);
shadowPainter.end();
// Actually, present the shadow.
QRect shadowRect = shadow.rect();
shadowRect.setSize(shadowRect.size() / dpr);
shadowRect.moveCenter(rect.center() + offset);
painter->drawImage(shadowRect, shadow);
}
void BoxShadowRenderer::setBoxSize(const QSize &size)
{
m_boxSize = size;
}
void BoxShadowRenderer::setBorderRadius(qreal radius)
{
m_borderRadius = radius;
}
void BoxShadowRenderer::setDevicePixelRatio(qreal dpr)
{
m_dpr = dpr;
}
void BoxShadowRenderer::addShadow(const QPoint &offset, int radius, const QColor &color)
{
Shadow shadow = {};
shadow.offset = offset;
shadow.radius = radius;
shadow.color = color;
m_shadows.append(shadow);
}
QImage BoxShadowRenderer::render() const
{
if (m_shadows.isEmpty()) {
return {};
}
QSize canvasSize;
for (const Shadow &shadow : qAsConst(m_shadows)) {
canvasSize = canvasSize.expandedTo(
calculateMinimumShadowTextureSize(m_boxSize, shadow.radius, shadow.offset));
}
QImage canvas(canvasSize * m_dpr, QImage::Format_ARGB32_Premultiplied);
canvas.setDevicePixelRatio(m_dpr);
canvas.fill(Qt::transparent);
QRect boxRect(QPoint(0, 0), m_boxSize);
boxRect.moveCenter(QRect(QPoint(0, 0), canvasSize).center());
QPainter painter(&canvas);
for (const Shadow &shadow : qAsConst(m_shadows)) {
renderShadow(&painter, boxRect, m_borderRadius, shadow.offset, shadow.radius, shadow.color);
}
painter.end();
return canvas;
}
QSize BoxShadowRenderer::calculateMinimumBoxSize(int radius)
{
const QSize blurExtent = calculateBlurExtent(radius);
return 2 * blurExtent + QSize(1, 1);
}
QSize BoxShadowRenderer::calculateMinimumShadowTextureSize(const QSize &boxSize, int radius, const QPoint &offset)
{
return boxSize + 2 * calculateBlurExtent(radius) + QSize(qAbs(offset.x()), qAbs(offset.y()));
}
} // namespace Breeze

View File

@ -1,93 +0,0 @@
/*
* SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
// own
#include "breezecommon_export.h"
// Qt
#include <QColor>
#include <QImage>
#include <QPoint>
#include <QSize>
namespace Breeze
{
class BREEZECOMMON_EXPORT BoxShadowRenderer
{
public:
// Compiler generated constructors & destructor are fine.
/**
* Set the size of the box.
* @param size The size of the box.
**/
void setBoxSize(const QSize &size);
/**
* Set the radius of box' corners.
* @param radius The border radius, in pixels.
**/
void setBorderRadius(qreal radius);
/**
* Set the device pixel ratio of the resulting shadow texture.
* @param dpr The device pixel ratio.
**/
void setDevicePixelRatio(qreal dpr);
/**
* Add a shadow.
* @param offset The offset of the shadow.
* @param radius The blur radius.
* @param color The color of the shadow.
**/
void addShadow(const QPoint &offset, int radius, const QColor &color);
/**
* Render the shadow.
**/
QImage render() const;
/**
* Calculate the minimum size of the box.
*
* This helper computes the minimum size of the box so the shadow behind it has
* full its strength.
*
* @param radius The blur radius of the shadow.
**/
static QSize calculateMinimumBoxSize(int radius);
/**
* Calculate the minimum size of the shadow texture.
*
* This helper computes the minimum size of the resulting texture so the shadow
* is not clipped.
*
* @param boxSize The size of the box.
* @param radius The blur radius.
* @param offset The offset of the shadow.
**/
static QSize calculateMinimumShadowTextureSize(const QSize &boxSize, int radius, const QPoint &offset);
private:
QSize m_boxSize;
qreal m_borderRadius = 0.0;
qreal m_dpr = 1.0;
struct Shadow {
QPoint offset;
int radius;
QColor color;
};
QVector<Shadow> m_shadows;
};
} // namespace Breeze

View File

@ -1,4 +1,4 @@
SUBDIRS=emblems kali-logos KDE-themes
SUBDIRS=emblems kali-logos
DESKTOP_BACKGROUND=kali-nova
LOGIN_BACKGROUND=kali-contours

19
debian/control vendored
View File

@ -3,17 +3,8 @@ Section: misc
Priority: optional
Maintainer: Kali Developers <devel@kali.org>
Uploaders: Daniel Ruiz de Alegría <daniel@drasite.com>, Raphaël Hertzog <raphael@offensive-security.com>
Build-Depends: cmake,
Build-Depends:
debhelper-compat (= 12),
extra-cmake-modules,
libkdecorations2-dev,
libkf5configwidgets-dev,
libkf5coreaddons-dev,
libkf5guiaddons-dev,
libkf5i18n-dev,
libkf5iconthemes-dev,
libkf5windowsystem-dev,
libqt5x11extras5-dev,
librsvg2-bin,
optipng,
Standards-Version: 4.5.1
@ -87,14 +78,6 @@ Description: Configure all desktops to use the Kali theme
provides configuration files and other settings for each desktop so that
they use the Kali theme by default.
Package: kwin-style-kali
Architecture: any
Depends:
${misc:Depends},
${shlibs:Depends}
Description: Kali theme for KWin
Kali's window manager theme for KDE Plasma 5 desktop
Package: gnome-theme-kali
Architecture: all
Depends: kali-themes,

View File

@ -1,2 +0,0 @@
# Created by "make install"
usr/lib/*/qt5/