From fa337b1f5b8a9dc774785fd432b439e12da3d448 Mon Sep 17 00:00:00 2001 From: alex47 Date: Sun, 11 Mar 2018 13:48:04 +0100 Subject: [PATCH] Add files via upload --- CMakeLists.txt | 128 ++++ Messages.sh | 4 + breeze.h | 62 ++ breeze.json | 69 +++ breezebutton.cpp | 475 +++++++++++++++ breezebutton.h | 140 +++++ breezedecoration.cpp | 776 +++++++++++++++++++++++++ breezedecoration.h | 202 +++++++ breezeexceptionlist.cpp | 128 ++++ breezeexceptionlist.h | 79 +++ breezesettings.kcfgc | 6 + breezesettingsdata.kcfg | 141 +++++ breezesettingsprovider.cpp | 130 +++++ breezesettingsprovider.h | 76 +++ breezesizegrip.cpp | 308 ++++++++++ breezesizegrip.h | 100 ++++ config-breeze.h.cmake | 28 + config/breezeblurconfig.desktop | 17 + config/breezeconfigwidget.cpp | 222 +++++++ config/breezeconfigwidget.h | 93 +++ config/breezedecorationconfig.desktop | 128 ++++ config/breezedetectwidget.cpp | 184 ++++++ config/breezedetectwidget.h | 113 ++++ config/breezeexceptiondialog.cpp | 184 ++++++ config/breezeexceptiondialog.h | 114 ++++ config/breezeexceptionlistwidget.cpp | 355 +++++++++++ config/breezeexceptionlistwidget.h | 124 ++++ config/breezeexceptionmodel.cpp | 107 ++++ config/breezeexceptionmodel.h | 81 +++ config/breezeitemmodel.cpp | 68 +++ config/breezeitemmodel.h | 113 ++++ config/breezelistmodel.h | 369 ++++++++++++ config/ui/breezeconfigurationui.ui | 475 +++++++++++++++ config/ui/breezedetectwidget.ui | 146 +++++ config/ui/breezeexceptiondialog.ui | 231 ++++++++ config/ui/breezeexceptionlistwidget.ui | 114 ++++ 36 files changed, 6090 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 Messages.sh create mode 100644 breeze.h create mode 100644 breeze.json create mode 100644 breezebutton.cpp create mode 100644 breezebutton.h create mode 100644 breezedecoration.cpp create mode 100644 breezedecoration.h create mode 100644 breezeexceptionlist.cpp create mode 100644 breezeexceptionlist.h create mode 100644 breezesettings.kcfgc create mode 100644 breezesettingsdata.kcfg create mode 100644 breezesettingsprovider.cpp create mode 100644 breezesettingsprovider.h create mode 100644 breezesizegrip.cpp create mode 100644 breezesizegrip.h create mode 100644 config-breeze.h.cmake create mode 100644 config/breezeblurconfig.desktop create mode 100644 config/breezeconfigwidget.cpp create mode 100644 config/breezeconfigwidget.h create mode 100644 config/breezedecorationconfig.desktop create mode 100644 config/breezedetectwidget.cpp create mode 100644 config/breezedetectwidget.h create mode 100644 config/breezeexceptiondialog.cpp create mode 100644 config/breezeexceptiondialog.h create mode 100644 config/breezeexceptionlistwidget.cpp create mode 100644 config/breezeexceptionlistwidget.h create mode 100644 config/breezeexceptionmodel.cpp create mode 100644 config/breezeexceptionmodel.h create mode 100644 config/breezeitemmodel.cpp create mode 100644 config/breezeitemmodel.h create mode 100644 config/breezelistmodel.h create mode 100644 config/ui/breezeconfigurationui.ui create mode 100644 config/ui/breezedetectwidget.ui create mode 100644 config/ui/breezeexceptiondialog.ui create mode 100644 config/ui/breezeexceptionlistwidget.ui diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..fbde4b5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,128 @@ + +project(breezeblur) +set(PROJECT_VERSION "0.1") +set(PROJECT_VERSION_MAJOR 0) + +cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) + +include(WriteBasicConfigVersionFile) +include(FeatureSummary) + +find_package(ECM 0.0.9 REQUIRED NO_MODULE) + +set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_SOURCE_DIR}/cmake) +include(ECMInstallIcons) +include(KDEInstallDirs) +include(KDECMakeSettings) +include(KDECompilerSettings NO_POLICY_SCOPE) +include(GenerateExportHeader) +# include(GtkUpdateIconCache) + +find_package(KDecoration2 REQUIRED) + + +# old stuff +add_definitions(-DTRANSLATION_DOMAIN="breeze_kwin_deco") + +find_package(KF5 REQUIRED COMPONENTS CoreAddons GuiAddons ConfigWidgets WindowSystem I18n) +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 "http://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 ) + +################# newt target ################# +### plugin classes +# set(breezedecoration_SRCS +set(breezeblur_SRCS + breezebutton.cpp + breezedecoration.cpp + breezeexceptionlist.cpp + breezesettingsprovider.cpp + breezesizegrip.cpp) + +# kconfig_add_kcfg_files(breezedecoration_SRCS breezesettings.kcfgc) +kconfig_add_kcfg_files(breezeblur_SRCS breezesettings.kcfgc) + +### config classes +### they are kept separately because they might move in a separate library in the future +# set(breezedecoration_config_SRCS +set(breezeblur_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 +set(breezeblur_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}) +ki18n_wrap_ui(breezeblur_config_PART_FORMS_HEADERS ${breezeblur_config_PART_FORMS}) + +### build library +# add_library(breezedecoration MODULE + # ${breezedecoration_SRCS} + # ${breezedecoration_config_SRCS} + # ${breezedecoration_config_PART_FORMS_HEADERS}) +add_library(breezeblur MODULE + ${breezeblur_SRCS} + ${breezeblur_config_SRCS} + ${breezeblur_config_PART_FORMS_HEADERS}) + +# target_link_libraries(breezedecoration +target_link_libraries(breezeblur + PUBLIC + Qt5::Core + Qt5::Gui + Qt5::DBus + PRIVATE + KDecoration2::KDecoration + KF5::ConfigCore + KF5::CoreAddons + KF5::ConfigWidgets + KF5::GuiAddons + KF5::I18n + KF5::WindowSystem) + +if(BREEZE_HAVE_X11) + # target_link_libraries(breezedecoration + target_link_libraries(breezeblur + PUBLIC + Qt5::X11Extras + XCB::XCB) +endif() + + +install(TARGETS breezeblur DESTINATION ${PLUGIN_INSTALL_DIR}/org.kde.kdecoration2) +install(FILES config/breezeblurconfig.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +# install(TARGETS breezedecoration DESTINATION ${PLUGIN_INSTALL_DIR}/org.kde.kdecoration2) +# install(FILES config/breezedecorationconfig.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/Messages.sh b/Messages.sh new file mode 100644 index 0000000..4f38b6d --- /dev/null +++ b/Messages.sh @@ -0,0 +1,4 @@ +#!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 diff --git a/breeze.h b/breeze.h new file mode 100644 index 0000000..24f4bd4 --- /dev/null +++ b/breeze.h @@ -0,0 +1,62 @@ +#ifndef breeze_h +#define breeze_h + +/* + * Copyright 2014 Hugo Pereira Da Costa + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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, see . + */ + +#include "breezesettings.h" + +#include +#include + +namespace Breeze +{ + //* convenience typedefs + using InternalSettingsPtr = QSharedPointer; + using InternalSettingsList = QList; + using InternalSettingsListIterator = QListIterator; + + //* metrics + enum Metrics + { + + //* corner radius (pixels) + Frame_FrameRadius = 3, + + //* titlebar metrics, in units of small spacing + TitleBar_TopMargin = 2, + TitleBar_BottomMargin = 2, + TitleBar_SideMargin = 2, + TitleBar_ButtonSpacing = 2, + + // shadow dimensions (pixels) + Shadow_Overlap = 3, + + }; + + //* exception + enum ExceptionMask + { + None = 0, + BorderSize = 1<<4 + }; +} + +#endif diff --git a/breeze.json b/breeze.json new file mode 100644 index 0000000..c6ce464 --- /dev/null +++ b/breeze.json @@ -0,0 +1,69 @@ +{ + "KPlugin": { + "Description": "Window decoration using the Breeze visual style for the Plasma Desktop", + "Description[ar]": "زخرفة نوافذ تستخدم نمط «نسيم» المرئيّ لسطح مكتب «بلازما»", + "Description[ca@valencia]": "Decoració de les finestres que usa l'estil visual Brisa per a l'escriptori del Plasma", + "Description[ca]": "Decoració de les finestres que usa l'estil visual Brisa per a l'escriptori del Plasma", + "Description[cs]": "Dekorace oken pro pracovní plochu Plasma využívající styl Breeze", + "Description[da]": "Vinduesdekoration som bruger den visuelle stil Breeze til Plasma-skrivebordet", + "Description[de]": "Fensterdekoration im Breeze-Design für die Plasma-Arbeitsfläche", + "Description[el]": "Διακοσμήσεις παραθύρων με το στιλ του Breeze για την επιφάνεια εργασίας Plasma", + "Description[es]": "Decoración de ventanas que usa el estilo visual Brisa para el escritorio Plasma", + "Description[et]": "Plasma töölaua akende dekoratsioon Breeze'i visuaalse stiiliga", + "Description[eu]": "Leiho apainketa Plasma mahaigainerako Breeze ikus-estiloa erabiliz", + "Description[fi]": "Breeze-tyyliä käyttävä ikkunan kehys Plasma-työpöydälle", + "Description[fr]": "Décorations de fenêtres utilisant le style visuel Brise pour le bureau Plasma", + "Description[gl]": "Decoración de xanelas que usa o estilo visual Breeze para o escritorio Plasma.", + "Description[hu]": "A Breeze vizuális stílusát használó ablakdekoráció", + "Description[ia]": "Decoration de fenestra usante le stylo visual Breeze (Brisa) per le scriptorio de Plasma", + "Description[it]": "Decorazione per finestre che usa lo stile visuale di Brezza per il desktop Plasma", + "Description[ko]": "Plasma 데스크톱의 Breeze 시각 스타일을 사용하는 창 장식", + "Description[nl]": "Vensterdecoratie met gebruik van de visuele stijl Breeze voor het Plasma bureaublad", + "Description[nn]": "Vindaugspynt som brukar Breeze-stilen for Plasma-skrivebordet", + "Description[pl]": "Wystrój okien przy użyciu stylu wizualnego Bryzy dla Pulpitu Plazmy", + "Description[pt]": "Decoração de janelas que usa o estilo visual Brisa para a Área de Trabalho Plasma", + "Description[pt_BR]": "Decoração de janelas que usa o estilo visual Breeze para o Plasma Desktop", + "Description[ru]": "Оформление окон Breeze", + "Description[sk]": "Dekorácia okien pomocou vizuálneho štýlu Vánok pre plochu Plasma", + "Description[sl]": "Okraski oken, ki uporabljajo vidni slog teme Sapica za namizje Plasma", + "Description[sr@ijekavian]": "Декорација прозора са Поветарцем као визуелним стилом за плазма површ.", + "Description[sr@ijekavianlatin]": "Dekoracija prozora sa Povetarcem kao vizuelnim stilom za plasma površ.", + "Description[sr@latin]": "Dekoracija prozora sa Povetarcem kao vizuelnim stilom za plasma površ.", + "Description[sr]": "Декорација прозора са Поветарцем као визуелним стилом за плазма површ.", + "Description[sv]": "Fönsterdekoration med den visuella stilen Breeze för Plasma skrivbord", + "Description[tr]": "Breeze görsel biçemini Plasma Masaüstü için kullanan pencere dekorasyonu", + "Description[uk]": "Обрамлення вікон з використанням візуального стилю Breeze для стільничного середовища Плазми", + "Description[x-test]": "xxWindow decoration using the Breeze visual style for the Plasma Desktopxx", + "Description[zh_CN]": "窗口装饰使用等离子桌面微风视觉主题", + "Description[zh_TW]": "使用 Plasma 桌面 Breeze 視覺樣式的視窗裝飾", + "EnabledByDefault": true, + "Id": "org.kde.breezeblur", + "Name": "BreezeBlur", + "Name[ar]": "نسيم", + "Name[ca@valencia]": "Brisa", + "Name[ca]": "Brisa", + "Name[es]": "Brisa", + "Name[fr]": "Brise", + "Name[ia]": "Brisa (Breeze)", + "Name[it]": "Brezza", + "Name[pl]": "Bryza", + "Name[pt]": "Brisa", + "Name[sk]": "Vánok", + "Name[sl]": "Sapica", + "Name[sr@ijekavian]": "Поветарац", + "Name[sr@ijekavianlatin]": "Povetarac", + "Name[sr@latin]": "Povetarac", + "Name[sr]": "Поветарац", + "Name[tr]": "Esinti", + "Name[x-test]": "xxBreezexx", + "Name[zh_CN]": "微风", + "ServiceTypes": [ + "org.kde.kdecoration2" + ] + }, + "org.kde.kdecoration2": { + "blur": false, + "defaultTheme": "BreezeBlur", + "kcmodule": true + } +} diff --git a/breezebutton.cpp b/breezebutton.cpp new file mode 100644 index 0000000..2ae2ea6 --- /dev/null +++ b/breezebutton.cpp @@ -0,0 +1,475 @@ +/* + * Copyright 2014 Martin Gräßlin + * Copyright 2014 Hugo Pereira Da Costa + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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, see . + */ +#include "breezebutton.h" + +#include +#include + +#include + +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 QPropertyAnimation( this ) ) + { + + // setup animation + m_animation->setStartValue( 0 ); + m_animation->setEndValue( 1.0 ); + m_animation->setTargetObject( this ); + m_animation->setPropertyName( "opacity" ); + m_animation->setEasingCurve( QEasingCurve::InOutQuad ); + + // 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) + : DecorationButton(args.at(0).value(), args.at(1).value(), parent) + , m_flag(FlagStandalone) + , m_animation( new QPropertyAnimation( this ) ) + {} + + //__________________________________________________________________ + Button *Button::create(DecorationButtonType type, KDecoration2::Decoration *decoration, QObject *parent) + { + if (auto d = qobject_cast(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 ); + 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( 1.1*qMax((qreal)1.0, 20/width ) ); + + painter->setPen( pen ); + painter->setBrush( Qt::NoBrush ); + + switch( type() ) + { + + case DecorationButtonType::Close: + { + painter->drawLine( QPointF( 5, 5 ), QPointF( 13, 13 ) ); + painter->drawLine( 13, 5, 5, 13 ); + break; + } + + case DecorationButtonType::Maximize: + { + if( isChecked() ) + { + pen.setJoinStyle( Qt::RoundJoin ); + painter->setPen( pen ); + + painter->drawPolygon( QPolygonF() + << QPointF( 4, 9 ) + << QPointF( 9, 4 ) + << QPointF( 14, 9 ) + << QPointF( 9, 14 ) ); + + } else { + painter->drawPolyline( QPolygonF() + << QPointF( 4, 11 ) + << QPointF( 9, 6 ) + << QPointF( 14, 11 ) ); + } + break; + } + + case DecorationButtonType::Minimize: + { + painter->drawPolyline( QPolygonF() + << QPointF( 4, 7 ) + << QPointF( 9, 12 ) + << QPointF( 14, 7 ) ); + 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() ); + if( !backgroundColor.isValid() && d ) backgroundColor = d->titleBarColor(); + + if( backgroundColor.isValid() ) + { + painter->setBrush( backgroundColor ); + painter->drawEllipse( QRectF( 8, 8, 2, 2 ) ); + } + + } else { + + painter->drawPolygon( QPolygonF() + << 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( 4, 5, 14, 5 ); + painter->drawPolyline( QPolygonF() + << QPointF( 4, 8 ) + << QPointF( 9, 13 ) + << QPointF( 14, 8 ) ); + + } else { + + painter->drawLine( 4, 5, 14, 5 ); + painter->drawPolyline( QPolygonF() + << QPointF( 4, 13 ) + << QPointF( 9, 8 ) + << QPointF( 14, 13 ) ); + } + + break; + + } + + case DecorationButtonType::KeepBelow: + { + + painter->drawPolyline( QPolygonF() + << QPointF( 4, 5 ) + << QPointF( 9, 10 ) + << QPointF( 14, 5 ) ); + + painter->drawPolyline( QPolygonF() + << QPointF( 4, 9 ) + << QPointF( 9, 14 ) + << QPointF( 14, 9 ) ); + break; + + } + + case DecorationButtonType::KeepAbove: + { + painter->drawPolyline( QPolygonF() + << QPointF( 4, 9 ) + << QPointF( 9, 4 ) + << QPointF( 14, 9 ) ); + + painter->drawPolyline( QPolygonF() + << QPointF( 4, 13 ) + << QPointF( 9, 8 ) + << QPointF( 14, 13 ) ); + break; + } + + + case DecorationButtonType::ApplicationMenu: + { + painter->drawLine( QPointF( 3.5, 5 ), QPointF( 14.5, 5 ) ); + painter->drawLine( QPointF( 3.5, 9 ), QPointF( 14.5, 9 ) ); + painter->drawLine( QPointF( 3.5, 13 ), QPointF( 14.5, 13 ) ); + 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->drawPoint( 9, 15 ); + + break; + } + + default: break; + + } + + } + + } + + //__________________________________________________________________ + QColor Button::foregroundColor( void ) const + { + auto d = qobject_cast( 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 ) && isChecked() ) { + + return d->titleBarColor(); + + } else if( m_animation->state() == QPropertyAnimation::Running ) { + + return KColorUtils::mix( d->fontColor(), d->titleBarColor(), m_opacity ); + + } else if( isHovered() ) { + + return d->titleBarColor(); + + } else { + + return d->fontColor(); + + } + + } + + //__________________________________________________________________ + QColor Button::backgroundColor( void ) const + { + auto d = qobject_cast( decoration() ); + if( !d ) { + + return QColor(); + + } + + auto c = d->client().data(); + if( isPressed() ) { + + if( type() == DecorationButtonType::Close ) return c->color( ColorGroup::Warning, ColorRole::Foreground ); + else return KColorUtils::mix( d->titleBarColor(), d->fontColor(), 0.3 ); + + } else if( ( type() == DecorationButtonType::KeepBelow || type() == DecorationButtonType::KeepAbove ) && isChecked() ) { + + return d->fontColor(); + + } else if( m_animation->state() == QPropertyAnimation::Running ) { + + if( type() == DecorationButtonType::Close ) + { + if( d->internalSettings()->outlineCloseButton() ) + { + + return KColorUtils::mix( d->fontColor(), c->color( ColorGroup::Warning, ColorRole::Foreground ).lighter(), m_opacity ); + + } else { + + QColor color( c->color( ColorGroup::Warning, ColorRole::Foreground ).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->color( ColorGroup::Warning, ColorRole::Foreground ).lighter(); + else return d->fontColor(); + + } else if( type() == DecorationButtonType::Close && d->internalSettings()->outlineCloseButton() ) { + + return d->fontColor(); + + } else { + + return QColor(); + + } + + } + + //________________________________________________________________ + void Button::reconfigure() + { + + // animation + auto d = qobject_cast(decoration()); + if( d ) m_animation->setDuration( d->internalSettings()->animationsDuration() ); + + } + + //__________________________________________________________________ + void Button::updateAnimationState( bool hovered ) + { + + auto d = qobject_cast(decoration()); + if( !(d && d->internalSettings()->animationsEnabled() ) ) return; + + m_animation->setDirection( hovered ? QPropertyAnimation::Forward : QPropertyAnimation::Backward ); + if( m_animation->state() != QPropertyAnimation::Running ) m_animation->start(); + + } + +} // namespace diff --git a/breezebutton.h b/breezebutton.h new file mode 100644 index 0000000..fd28e77 --- /dev/null +++ b/breezebutton.h @@ -0,0 +1,140 @@ +#ifndef BREEZE_BUTTONS_H +#define BREEZE_BUTTONS_H + +/* +* Copyright 2014 Martin Gräßlin +* Copyright 2014 Hugo Pereira Da Costa +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see . +*/ +#include +#include "breezedecoration.h" + +#include +#include +#include + +namespace Breeze +{ + + class Button : public KDecoration2::DecorationButton + { + Q_OBJECT + + //* declare active state opacity + Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity ) + + 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( void ) 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( void ) const; + QColor backgroundColor( void ) const; + //@} + + Flag m_flag = FlagNone; + + //* active state change animation + QPropertyAnimation *m_animation; + + //* vertical offset (for rendering) + QPointF m_offset; + + //* icon size + QSize m_iconSize; + + //* active state change opacity + qreal m_opacity = 0; + }; + +} // namespace + +#endif diff --git a/breezedecoration.cpp b/breezedecoration.cpp new file mode 100644 index 0000000..26e6729 --- /dev/null +++ b/breezedecoration.cpp @@ -0,0 +1,776 @@ +/* +* Copyright 2014 Martin Gräßlin +* Copyright 2014 Hugo Pereira Da Costa +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see . +*/ + +#include "breezedecoration.h" + +#include "breeze.h" +#include "breezesettingsprovider.h" +#include "config-breeze.h" +#include "config/breezeconfigwidget.h" + +#include "breezebutton.h" +#include "breezesizegrip.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#if BREEZE_HAVE_X11 +#include +#endif + +#include + +K_PLUGIN_FACTORY_WITH_JSON( + BreezeDecoFactory, + "breeze.json", + registerPlugin(); + registerPlugin(QStringLiteral("button")); + registerPlugin(QStringLiteral("kcmodule")); +) + +namespace Breeze +{ + + using KDecoration2::ColorRole; + using KDecoration2::ColorGroup; + + //________________________________________________________________ + static int g_sDecoCount = 0; + static int g_shadowSizeEnum = InternalSettings::ShadowLarge; + static int g_shadowStrength = 90; + static QColor g_shadowColor = Qt::black; + static QSharedPointer g_sShadow; + + //________________________________________________________________ + Decoration::Decoration(QObject *parent, const QVariantList &args) + : KDecoration2::Decoration(parent, args) + , m_animation( new QPropertyAnimation( 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() == QPropertyAnimation::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() == QPropertyAnimation::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() == QPropertyAnimation::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 + m_animation->setStartValue( 0 ); + m_animation->setEndValue( 1.0 ); + m_animation->setTargetObject( this ); + m_animation->setPropertyName( "opacity" ); + m_animation->setEasingCurve( QEasingCurve::InOutQuad ); + + 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(); + createShadow(); + } + + //________________________________________________________________ + 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_internalSettings->animationsEnabled() ) + { + + auto c = client().data(); + m_animation->setDirection( c->isActive() ? QPropertyAnimation::Forward : QPropertyAnimation::Backward ); + if( m_animation->state() != QPropertyAnimation::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(); + if( m_internalSettings && (m_internalSettings->mask() & BorderSize ) ) + { + switch (m_internalSettings->borderSize()) { + case InternalSettings::BorderNone: return 0; + case InternalSettings::BorderNoSides: return bottom ? qMax(4, baseSize) : 0; + default: + case InternalSettings::BorderTiny: return bottom ? qMax(4, baseSize) : baseSize; + case InternalSettings::BorderNormal: return baseSize*2; + case InternalSettings::BorderLarge: return baseSize*3; + case InternalSettings::BorderVeryLarge: return baseSize*4; + case InternalSettings::BorderHuge: return baseSize*5; + case InternalSettings::BorderVeryHuge: return baseSize*6; + case InternalSettings::BorderOversized: return baseSize*10; + } + + } else { + + switch (settings()->borderSize()) { + case KDecoration2::BorderSize::None: return 0; + case KDecoration2::BorderSize::NoSides: return bottom ? qMax(4, baseSize) : 0; + default: + case KDecoration2::BorderSize::Tiny: return bottom ? qMax(4, baseSize) : baseSize; + case KDecoration2::BorderSize::Normal: return baseSize*2; + case KDecoration2::BorderSize::Large: return baseSize*3; + case KDecoration2::BorderSize::VeryLarge: return baseSize*4; + case KDecoration2::BorderSize::Huge: return baseSize*5; + case KDecoration2::BorderSize::VeryHuge: return baseSize*6; + case KDecoration2::BorderSize::Oversized: return baseSize*10; + + } + + } + } + + //________________________________________________________________ + void Decoration::reconfigure() + { + + m_internalSettings = SettingsProvider::self()->internalSettings( this ); + + // animation + m_animation->setDuration( m_internalSettings->animationsDuration() ); + + // borders + recalculateBorders(); + + // shadow + createShadow(); + + // size grip + if( hasNoBorders() && m_internalSettings->drawSizeGrip() ) createSizeGrip(); + else deleteSizeGrip(); + + } + + //________________________________________________________________ + void Decoration::recalculateBorders() + { + auto c = client().data(); + auto s = settings(); + + // left, right and bottom borders + const int left = isLeftEdge() ? 0 : borderSize(); + const int right = isRightEdge() ? 0 : borderSize(); + const int bottom = (c->isShaded() || isBottomEdge()) ? 0 : borderSize(true); + + 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; + if( hasNoBorders() ) + { + extSides = extSize; + extBottom = extSize; + + } else if( hasNoSideBorders() ) { + + extSides = extSize; + + } + + 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& button, m_leftButtons->buttons() + m_rightButtons->buttons() ) + { + button.data()->setGeometry( QRectF( QPoint( 0, 0 ), QSizeF( bWidth, bHeight ) ) ); + static_cast( button.data() )->setOffset( QPointF( 0, verticalOffset ) ); + static_cast( button.data() )->setIconSize( QSize( bWidth, bWidth ) ); + } + + // left buttons + if( !m_leftButtons->buttons().isEmpty() ) + { + + // spacing + m_leftButtons->setSpacing(s->smallSpacing()*Metrics::TitleBar_ButtonSpacing); + + // padding + const int vPadding = isTopEdge() ? 0 : s->smallSpacing()*Metrics::TitleBar_TopMargin; + const int hPadding = s->smallSpacing()*Metrics::TitleBar_SideMargin; + if( isLeftEdge() ) + { + // add offsets on the side buttons, to preserve padding, but satisfy Fitts law + auto button = static_cast( m_leftButtons->buttons().front().data() ); + button->setGeometry( QRectF( QPoint( 0, 0 ), QSizeF( bWidth + hPadding, bHeight ) ) ); + button->setFlag( Button::FlagFirstInList ); + button->setHorizontalOffset( hPadding ); + + m_leftButtons->setPos(QPointF(0, vPadding)); + + } else m_leftButtons->setPos(QPointF(hPadding + borderLeft(), vPadding)); + + } + + // right buttons + if( !m_rightButtons->buttons().isEmpty() ) + { + + // spacing + m_rightButtons->setSpacing(s->smallSpacing()*Metrics::TitleBar_ButtonSpacing); + + // padding + const int vPadding = isTopEdge() ? 0 : s->smallSpacing()*Metrics::TitleBar_TopMargin; + const int hPadding = s->smallSpacing()*Metrics::TitleBar_SideMargin; + if( isRightEdge() ) + { + + auto button = static_cast( m_rightButtons->buttons().back().data() ); + button->setGeometry( QRectF( QPoint( 0, 0 ), QSizeF( bWidth + hPadding, bHeight ) ) ); + button->setFlag( Button::FlagLastInList ); + + m_rightButtons->setPos(QPointF(size().width() - m_rightButtons->geometry().width(), vPadding)); + + } else 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(); + + // paint background + if( !c->isShaded() ) + { + painter->fillRect(rect(), Qt::transparent); + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + painter->setPen(Qt::NoPen); + + QColor windowColor( this->titleBarColor() ); + windowColor.setAlpha( m_internalSettings->opacitySlider() * 25.5 ); + painter->setBrush( windowColor ); + + // clip away the top part + if( !hideTitleBar() ) painter->setClipRect(0, borderTop(), size().width(), size().height() - borderTop(), Qt::IntersectClip); + + if( s->isAlphaChannelSupported() ) { + painter->drawRoundedRect(rect(), Metrics::Frame_FrameRadius, Metrics::Frame_FrameRadius); + } else { + painter->drawRect( rect() ); + } + + painter->restore(); + } + + if( !hideTitleBar() ) paintTitleBar(painter, repaintRegion); + + if( hasBorders() && !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() ) + { + + QColor titleBarColor( this->titleBarColor() ); + titleBarColor.setAlpha( m_internalSettings->opacitySlider() * 25.5 ); + + QLinearGradient gradient( 0, 0, 0, titleRect.height() ); + gradient.setColorAt(0.0, titleBarColor.lighter( 120 ) ); + gradient.setColorAt(0.8, titleBarColor); + + painter->setBrush(gradient); + + } else { + + QColor titleBarColor = this->titleBarColor(); + titleBarColor.setAlpha( m_internalSettings->opacitySlider() * 25.5 ); + + painter->setBrush( titleBarColor ); + + } + + auto s = settings(); + if( isMaximized() || !s->isAlphaChannelSupported() ) + { + + painter->drawRect(titleRect); + + } else if( c->isShaded() ) { + + painter->drawRoundedRect(titleRect, Metrics::Frame_FrameRadius, Metrics::Frame_FrameRadius); + + } 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() ? -Metrics::Frame_FrameRadius:0, + isTopEdge() ? -Metrics::Frame_FrameRadius:0, + isRightEdge() ? Metrics::Frame_FrameRadius:0, + Metrics::Frame_FrameRadius), + Metrics::Frame_FrameRadius, Metrics::Frame_FrameRadius); + + } + + 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 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::createShadow() + { + + // assign global shadow if exists and parameters match + if( + !g_sShadow || + g_shadowSizeEnum != m_internalSettings->shadowSize() || + g_shadowStrength != m_internalSettings->shadowStrength() || + g_shadowColor != m_internalSettings->shadowColor() + ) + { + // assign parameters + g_shadowSizeEnum = m_internalSettings->shadowSize(); + g_shadowStrength = m_internalSettings->shadowStrength(); + g_shadowColor = m_internalSettings->shadowColor(); + + // shadow size from enum + int shadowSize = 0; + switch( g_shadowSizeEnum ) + { + default: + case InternalSettings::ShadowLarge: shadowSize = 64; break; + + case InternalSettings::ShadowNone: shadowSize = Metrics::Shadow_Overlap + 1; break; + case InternalSettings::ShadowSmall: shadowSize = 16; break; + case InternalSettings::ShadowMedium: shadowSize = 32; break; + case InternalSettings::ShadowVeryLarge: shadowSize = 96; break; + } + + // offset + int shadowOffset = (g_shadowSizeEnum == InternalSettings::ShadowNone) ? 0 : qMax( 6*shadowSize/16, Metrics::Shadow_Overlap*2 ); + + // create image + QImage image(2*shadowSize, 2*shadowSize, QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::transparent); + + // painter + QPainter painter(&image); + painter.setRenderHint( QPainter::Antialiasing, true ); + + // color calculation delta function + auto gradientStopColor = [](QColor color, int alpha) + { + color.setAlpha(alpha); + return color; + }; + + // create gradient + if( g_shadowSizeEnum != InternalSettings::ShadowNone ) + { + + // gaussian lambda function + auto alpha = [](qreal x) { return std::exp( -x*x/0.15 ); }; + + QRadialGradient radialGradient( shadowSize, shadowSize, shadowSize ); + for( int i = 0; i < 10; ++i ) + { + const qreal x( qreal( i )/9 ); + radialGradient.setColorAt(x, gradientStopColor( g_shadowColor, alpha(x)*g_shadowStrength ) ); + } + + radialGradient.setColorAt(1, gradientStopColor( g_shadowColor, 0 ) ); + + // fill + painter.fillRect( image.rect(), radialGradient); + + } + + // contrast pixel + QRectF innerRect = QRectF( + shadowSize - Metrics::Shadow_Overlap, shadowSize - shadowOffset - Metrics::Shadow_Overlap, + 2*Metrics::Shadow_Overlap, shadowOffset + 2*Metrics::Shadow_Overlap ); + + painter.setPen( gradientStopColor( g_shadowColor, (g_shadowSizeEnum == InternalSettings::ShadowNone) ? g_shadowStrength:(g_shadowStrength*0.5) ) ); + painter.setBrush( Qt::NoBrush ); + painter.drawRoundedRect( innerRect, -0.5 + Metrics::Frame_FrameRadius, -0.5 + Metrics::Frame_FrameRadius ); + + // mask out inner rect + painter.setPen( Qt::NoPen ); + painter.setBrush( Qt::black ); + painter.setCompositionMode(QPainter::CompositionMode_DestinationOut ); + painter.drawRoundedRect( innerRect, 0.5 + Metrics::Frame_FrameRadius, 0.5 + Metrics::Frame_FrameRadius ); + + painter.end(); + + g_sShadow = QSharedPointer::create(); + g_sShadow->setPadding( QMargins( + shadowSize - Metrics::Shadow_Overlap, + shadowSize - shadowOffset - Metrics::Shadow_Overlap, + shadowSize - Metrics::Shadow_Overlap, + shadowSize - Metrics::Shadow_Overlap ) ); + + g_sShadow->setInnerShadowRect(QRect( shadowSize, shadowSize, 1, 1) ); + + // assign image + g_sShadow->setShadow(image); + + } + + setShadow(g_sShadow); + + } + + //_________________________________________________________________ + void Decoration::createSizeGrip( void ) + { + + // 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( void ) + { + if( m_sizeGrip ) + { + m_sizeGrip->deleteLater(); + m_sizeGrip = nullptr; + } + } + +} // namespace + + +#include "breezedecoration.moc" diff --git a/breezedecoration.h b/breezedecoration.h new file mode 100644 index 0000000..5907995 --- /dev/null +++ b/breezedecoration.h @@ -0,0 +1,202 @@ +#ifndef BREEZE_DECORATION_H +#define BREEZE_DECORATION_H + +/* + * Copyright 2014 Martin Gräßlin + * Copyright 2014 Hugo Pereira Da Costa + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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, see . + */ + +#include "breeze.h" +#include "breezesettings.h" + +#include +#include +#include +#include + +#include +#include +#include + +namespace KDecoration2 +{ + class DecorationButton; + class DecorationButtonGroup; +} + + +namespace Breeze +{ + class SizeGrip; + class Decoration : public KDecoration2::Decoration + { + Q_OBJECT + + //* declare active state opacity + Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity ) + + 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; } + + //* caption height + int captionHeight() const; + + //* button height + int buttonHeight() const; + + //*@name active state change animation + //@{ + void setOpacity( qreal ); + + qreal opacity( void ) const + { return m_opacity; } + + //@} + + //*@name colors + //@{ + QColor titleBarColor( void ) const; + QColor outlineColor( void ) const; + QColor fontColor( void ) const; + //@} + + //*@name maximization modes + //@{ + inline bool isMaximized( void ) const; + inline bool isMaximizedHorizontally( void ) const; + inline bool isMaximizedVertically( void ) const; + + inline bool isLeftEdge( void ) const; + inline bool isRightEdge( void ) const; + inline bool isTopEdge( void ) const; + inline bool isBottomEdge( void ) const; + + inline bool hideTitleBar( void ) 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 captionRect( void ) const; + + void createButtons(); + void paintTitleBar(QPainter *painter, const QRect &repaintRegion); + void createShadow(); + + //*@name border size + //@{ + int borderSize(bool bottom = false) const; + inline bool hasBorders( void ) const; + inline bool hasNoBorders( void ) const; + inline bool hasNoSideBorders( void ) const; + //@} + + //*@name size grip + //@{ + void createSizeGrip( void ); + void deleteSizeGrip( void ); + SizeGrip* sizeGrip( void ) const + { return m_sizeGrip; } + //@} + + InternalSettingsPtr m_internalSettings; + QList m_buttons; + KDecoration2::DecorationButtonGroup *m_leftButtons = nullptr; + KDecoration2::DecorationButtonGroup *m_rightButtons = nullptr; + + //* size grip widget + SizeGrip *m_sizeGrip = nullptr; + + //* active state change animation + QPropertyAnimation *m_animation; + + //* active state change opacity + qreal m_opacity = 0; + + }; + + bool Decoration::hasBorders( void ) const + { + if( m_internalSettings && m_internalSettings->mask() & BorderSize ) return m_internalSettings->borderSize() > InternalSettings::BorderNoSides; + else return settings()->borderSize() > KDecoration2::BorderSize::NoSides; + } + + bool Decoration::hasNoBorders( void ) const + { + if( m_internalSettings && m_internalSettings->mask() & BorderSize ) return m_internalSettings->borderSize() == InternalSettings::BorderNone; + else return settings()->borderSize() == KDecoration2::BorderSize::None; + } + + bool Decoration::hasNoSideBorders( void ) const + { + if( m_internalSettings && m_internalSettings->mask() & BorderSize ) return m_internalSettings->borderSize() == InternalSettings::BorderNoSides; + else return settings()->borderSize() == KDecoration2::BorderSize::NoSides; + } + + bool Decoration::isMaximized( void ) const + { return client().data()->isMaximized() && !m_internalSettings->drawBorderOnMaximizedWindows(); } + + bool Decoration::isMaximizedHorizontally( void ) const + { return client().data()->isMaximizedHorizontally() && !m_internalSettings->drawBorderOnMaximizedWindows(); } + + bool Decoration::isMaximizedVertically( void ) const + { return client().data()->isMaximizedVertically() && !m_internalSettings->drawBorderOnMaximizedWindows(); } + + bool Decoration::isLeftEdge( void ) const + { return (client().data()->isMaximizedHorizontally() || client().data()->adjacentScreenEdges().testFlag( Qt::LeftEdge ) ) && !m_internalSettings->drawBorderOnMaximizedWindows(); } + + bool Decoration::isRightEdge( void ) const + { return (client().data()->isMaximizedHorizontally() || client().data()->adjacentScreenEdges().testFlag( Qt::RightEdge ) ) && !m_internalSettings->drawBorderOnMaximizedWindows(); } + + bool Decoration::isTopEdge( void ) const + { return (client().data()->isMaximizedVertically() || client().data()->adjacentScreenEdges().testFlag( Qt::TopEdge ) ) && !m_internalSettings->drawBorderOnMaximizedWindows(); } + + bool Decoration::isBottomEdge( void ) const + { return (client().data()->isMaximizedVertically() || client().data()->adjacentScreenEdges().testFlag( Qt::BottomEdge ) ) && !m_internalSettings->drawBorderOnMaximizedWindows(); } + + bool Decoration::hideTitleBar( void ) const + { return m_internalSettings->hideTitleBar() && !client().data()->isShaded(); } + +} + +#endif diff --git a/breezeexceptionlist.cpp b/breezeexceptionlist.cpp new file mode 100644 index 0000000..5b4622c --- /dev/null +++ b/breezeexceptionlist.cpp @@ -0,0 +1,128 @@ +////////////////////////////////////////////////////////////////////////////// +// breezeexceptionlist.cpp +// window decoration exceptions +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#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 ); + } + + } + +} diff --git a/breezeexceptionlist.h b/breezeexceptionlist.h new file mode 100644 index 0000000..dbb0876 --- /dev/null +++ b/breezeexceptionlist.h @@ -0,0 +1,79 @@ +#ifndef breezeexceptionlist_h +#define breezeexceptionlist_h + +////////////////////////////////////////////////////////////////////////////// +// breezeexceptionlist.h +// window decoration exceptions +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "breezesettings.h" +#include "breeze.h" + +#include + +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 diff --git a/breezesettings.kcfgc b/breezesettings.kcfgc new file mode 100644 index 0000000..d1d452e --- /dev/null +++ b/breezesettings.kcfgc @@ -0,0 +1,6 @@ +File=breezesettingsdata.kcfg +ClassName=InternalSettings +NameSpace=Breeze +Singleton=false +Mutators=true +GlobalEnums=true diff --git a/breezesettingsdata.kcfg b/breezesettingsdata.kcfg new file mode 100644 index 0000000..6d1b531 --- /dev/null +++ b/breezesettingsdata.kcfg @@ -0,0 +1,141 @@ + + + + + + + + + + 90 + 25 + 255 + + + + + + + + + + + + ShadowLarge + + + + 35, 38, 41 + + + + + true + + + + + + + + + + + + + + + + + + + + + BorderNoSides + + + + + + + + + + + AlignCenterFullWidth + + + + + + + + + + + + ButtonDefault + + + + + false + + + + true + + + + 6 + + + + + true + + + + + true + + + + + true + + + + 150 + + + + + false + + + + + + + + + ExceptionWindowClassName + + + + + + true + + + + 0 + + + + + diff --git a/breezesettingsprovider.cpp b/breezesettingsprovider.cpp new file mode 100644 index 0000000..96d6578 --- /dev/null +++ b/breezesettingsprovider.cpp @@ -0,0 +1,130 @@ +/* + * Copyright 2014 Hugo Pereira Da Costa + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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, see . + */ + +#include "breezesettingsprovider.h" + +#include "breezeexceptionlist.h" + +#include + +#include + +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( void ) + { + 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(), 0, 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; + + } + +} diff --git a/breezesettingsprovider.h b/breezesettingsprovider.h new file mode 100644 index 0000000..e6362a1 --- /dev/null +++ b/breezesettingsprovider.h @@ -0,0 +1,76 @@ +#ifndef breezesettingsprovider_h +#define breezesettingsprovider_h +/* + * Copyright 2014 Hugo Pereira Da Costa + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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, see . + */ + +#include "breezedecoration.h" +#include "breezesettings.h" +#include "breeze.h" + +#include + +#include + +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( void ); + + private: + + //* contructor + SettingsProvider( void ); + + //* default configuration + InternalSettingsPtr m_defaultSettings; + + //* exceptions + InternalSettingsList m_exceptions; + + //* config object + KSharedConfigPtr m_config; + + //* singleton + static SettingsProvider *s_self; + + }; + +} + +#endif diff --git a/breezesizegrip.cpp b/breezesizegrip.cpp new file mode 100644 index 0000000..d5dfb6f --- /dev/null +++ b/breezesizegrip.cpp @@ -0,0 +1,308 @@ +/************************************************************************* + * Copyright (C) 2014 by Hugo Pereira Da Costa * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + *************************************************************************/ + + +#include "breezesizegrip.h" + +#include + +#include +#include +#include + +#if BREEZE_HAVE_X11 +#include +#endif + +namespace Breeze +{ + + //* scoped pointer convenience typedef + template using ScopedPointer = QScopedPointer; + + //_____________________________________________ + 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 + QPolygon p; + p << QPoint( 0, GripSize ) + << QPoint( GripSize, 0 ) + << QPoint( GripSize, GripSize ) + << QPoint( 0, GripSize ); + + setMask( QRegion( p ) ); + + // 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 ) + {} + + //_____________________________________________ + void SizeGrip::updateActiveState( void ) + { + #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( void ) + { + + #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 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 + QPolygon p; + p << QPoint( 0, GripSize ) + << QPoint( GripSize, 0 ) + << QPoint( GripSize, GripSize ) + << QPoint( 0, GripSize ); + painter.drawPolygon( p ); + + } + + //_____________________________________________ + void SizeGrip::mousePressEvent( QMouseEvent* event ) + { + + switch (event->button()) + { + + case Qt::RightButton: + { + hide(); + QTimer::singleShot(5000, this, SLOT(show())); + break; + } + + case Qt::MidButton: + { + hide(); + break; + } + + case Qt::LeftButton: + if( rect().contains( event->pos() ) ) + { sendMoveResizeEvent( event->pos() ); } + break; + + default: break; + + } + + return; + + } + + //_______________________________________________________________________________ + void SizeGrip::updatePosition( void ) + { + + #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 reply( xcb_get_geometry_reply( connection, cookie, 0x0 ) ); + 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, 0x0 ) ); + + 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 reply( xcb_intern_atom_reply( connection, cookie, 0x0 ) ); + 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(&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(&clientMessageEvent) ); + + xcb_flush( connection ); + #endif + + } + +} diff --git a/breezesizegrip.h b/breezesizegrip.h new file mode 100644 index 0000000..cb28fcb --- /dev/null +++ b/breezesizegrip.h @@ -0,0 +1,100 @@ +#ifndef breezesizegrip_h +#define breezesizegrip_h + +/************************************************************************* + * Copyright (C) 2014 by Hugo Pereira Da Costa * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + *************************************************************************/ + +#include "breezedecoration.h" +#include "config-breeze.h" + +#include +#include +#include +#include + +#if BREEZE_HAVE_X11 +#include +#endif + +namespace Breeze +{ + + //* implements size grip for all widgets + class SizeGrip: public QWidget + { + + Q_OBJECT + + public: + + //* constructor + explicit SizeGrip( Decoration* ); + + //* constructor + virtual ~SizeGrip( void ); + + protected Q_SLOTS: + + //* update background color + void updateActiveState( void ); + + //* update position + void updatePosition( void ); + + //* embed into parent widget + void embed( void ); + + 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 m_decoration; + + //* move/resize atom + #if BREEZE_HAVE_X11 + xcb_atom_t m_moveResizeAtom = 0; + #endif + + }; + + +} + +#endif diff --git a/config-breeze.h.cmake b/config-breeze.h.cmake new file mode 100644 index 0000000..bee0f79 --- /dev/null +++ b/config-breeze.h.cmake @@ -0,0 +1,28 @@ +/* config-breeze.h. Generated by cmake from config-breeze.h.cmake */ + +/************************************************************************* + * Copyright (C) 2014 by Hugo Pereira Da Costa * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + *************************************************************************/ + +#ifndef config_breeze_h +#define config_breeze_h + +/* Define to 1 if XCB libraries are found */ +#cmakedefine01 BREEZE_HAVE_X11 + +#endif diff --git a/config/breezeblurconfig.desktop b/config/breezeblurconfig.desktop new file mode 100644 index 0000000..225384e --- /dev/null +++ b/config/breezeblurconfig.desktop @@ -0,0 +1,17 @@ +[Desktop Entry] +# Exec=kcmshell5 breezedecorationconfig +Exec=kcmshell5 breezeblurconfig +Icon=preferences-system-windows +Type=Service +X-KDE-ServiceTypes=KCModule + +# X-KDE-Library=org.kde.kdecoration2/breezedecoration +X-KDE-Library=org.kde.kdecoration2/breezeblur +X-KDE-PluginKeyword=kcmodule +X-KDE-ParentApp=kcontrol +X-KDE-Weight=60 +X-KDE-PluginInfo-Name=BreezeBlur + +Name=BreezeBlur +Comment=Modify the appearance of window decorations +X-KDE-Keywords=breezeblur,decoration diff --git a/config/breezeconfigwidget.cpp b/config/breezeconfigwidget.cpp new file mode 100644 index 0000000..78929a2 --- /dev/null +++ b/config/breezeconfigwidget.cpp @@ -0,0 +1,222 @@ +////////////////////////////////////////////////////////////////////////////// +// breezeconfigurationui.cpp +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "breezeconfigwidget.h" +#include "breezeexceptionlist.h" +#include "breezesettings.h" + +#include + +#include +#include + +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, SIGNAL(clicked()), SLOT(updateChanged()) ); + connect( m_ui.drawBorderOnMaximizedWindows, SIGNAL(clicked()), SLOT(updateChanged()) ); + connect( m_ui.drawSizeGrip, SIGNAL(clicked()), SLOT(updateChanged()) ); + connect( m_ui.drawBackgroundGradient, SIGNAL(clicked()), SLOT(updateChanged()) ); + connect( m_ui.drawTitleBarSeparator, SIGNAL(clicked()), SLOT(updateChanged()) ); + connect( m_ui.opacitySlider, SIGNAL(valueChanged(int)), SLOT(updateChanged()) ); + + // track animations changes + connect( m_ui.animationsEnabled, SIGNAL(clicked()), SLOT(updateChanged()) ); + connect( m_ui.animationsDuration, SIGNAL(valueChanged(int)), SLOT(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, SIGNAL(changed(QColor)), SLOT(updateChanged()) ); + + // track exception changes + connect( m_ui.exceptions, SIGNAL(changed(bool)), SLOT(updateChanged()) ); + + } + + //_________________________________________________________ + void ConfigWidget::load( void ) + { + + // 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.animationsEnabled->setChecked( m_internalSettings->animationsEnabled() ); + m_ui.animationsDuration->setValue( m_internalSettings->animationsDuration() ); + m_ui.drawTitleBarSeparator->setChecked( m_internalSettings->drawTitleBarSeparator() ); + m_ui.opacitySlider->setValue( m_internalSettings->opacitySlider() ); + + // 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( void ) + { + + // 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->setAnimationsEnabled( m_ui.animationsEnabled->isChecked() ); + m_internalSettings->setAnimationsDuration( m_ui.animationsDuration->value() ); + m_internalSettings->setDrawTitleBarSeparator(m_ui.drawTitleBarSeparator->isChecked()); + m_internalSettings->setOpacitySlider(m_ui.opacitySlider->value()); + + 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( void ) + { + + // 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.drawBorderOnMaximizedWindows->setChecked( m_internalSettings->drawBorderOnMaximizedWindows() ); + m_ui.drawSizeGrip->setChecked( m_internalSettings->drawSizeGrip() ); + m_ui.drawBackgroundGradient->setChecked( m_internalSettings->drawBackgroundGradient() ); + m_ui.animationsEnabled->setChecked( m_internalSettings->animationsEnabled() ); + m_ui.animationsDuration->setValue( m_internalSettings->animationsDuration() ); + m_ui.drawTitleBarSeparator->setChecked( m_internalSettings->drawTitleBarSeparator() ); + m_ui.opacitySlider->setValue( m_internalSettings->opacitySlider() ); + + 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( void ) + { + + // 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; + else if( m_ui.opacitySlider->value() != m_internalSettings->opacitySlider() ) modified = true; + + // animations + else if( m_ui.animationsEnabled->isChecked() != m_internalSettings->animationsEnabled() ) modified = true; + else if( m_ui.animationsDuration->value() != m_internalSettings->animationsDuration() ) 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 ); + } + +} diff --git a/config/breezeconfigwidget.h b/config/breezeconfigwidget.h new file mode 100644 index 0000000..fda0de9 --- /dev/null +++ b/config/breezeconfigwidget.h @@ -0,0 +1,93 @@ +#ifndef breezeconfigwidget_h +#define breezeconfigwidget_h +////////////////////////////////////////////////////////////////////////////// +// breezeconfigurationui.h +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "ui_breezeconfigurationui.h" +#include "breezeexceptionlistwidget.h" +#include "breezesettings.h" +#include "breeze.h" + +#include +#include + +#include +#include + +namespace Breeze +{ + + //_____________________________________________ + class ConfigWidget: public KCModule + { + + Q_OBJECT + + public: + + //* constructor + explicit ConfigWidget( QWidget*, const QVariantList& ); + + //* destructor + virtual ~ConfigWidget( void ) = default; + + //* default + void defaults() override; + + //* load configuration + void load( void ) override; + + //* save configuration + void save( void ) 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 diff --git a/config/breezedecorationconfig.desktop b/config/breezedecorationconfig.desktop new file mode 100644 index 0000000..a4b7f06 --- /dev/null +++ b/config/breezedecorationconfig.desktop @@ -0,0 +1,128 @@ +[Desktop Entry] +Exec=kcmshell5 breezedecorationconfig +Icon=preferences-system-windows +Type=Service +X-KDE-ServiceTypes=KCModule + +X-KDE-Library=org.kde.kdecoration2/breezedecoration +X-KDE-PluginKeyword=kcmodule +X-KDE-ParentApp=kcontrol +X-KDE-Weight=60 + +Name=Breeze Window Decoration +Name[ca]=Decoració de les finestres Brisa +Name[ca@valencia]=Decoració de les finestres Brisa +Name[cs]=Dekorace oken Breeze +Name[da]=Breeze vinduesdekoration +Name[de]=Breeze-Fensterdekoration +Name[el]=Διακοσμήσεις παραθύρου Breeze +Name[en_GB]=Breeze Window Decoration +Name[es]=Decoración de ventanas Brisa +Name[eu]=Breeze leihoen apaindura +Name[fi]=Breeze-ikkunankehys +Name[fr]=Décoration de fenêtre Brise +Name[gl]=Decoración de xanela de Breeze +Name[hu]=Breeze ablakdekoráció +Name[ia]=Decoration de fenestra Breeze +Name[it]=Decorazione delle finestre di Brezza +Name[ko]=Breeze 창 장식 +Name[nl]=Breeze vensterdecoratie +Name[nn]=Breeze-vindaugsdekorasjon +Name[pl]=Wygląd okien Bryzy +Name[pt]=Decoração de Janelas Brisa +Name[pt_BR]=Decorações da janela Breeze +Name[ru]=Оформление окон Breeze +Name[sk]=Dekorácie okien Breeze +Name[sl]=Okraski oken Sapica +Name[sr]=Поветарчева декорација прозора +Name[sr@ijekavian]=Поветарчева декорација прозора +Name[sr@ijekavianlatin]=Povetarčeva dekoracija prozora +Name[sr@latin]=Povetarčeva dekoracija prozora +Name[sv]=Breeze fönsterdekoration +Name[tr]=Breeze Pencere Dekorasyonu +Name[uk]=Декорації вікон Breeze +Name[x-test]=xxBreeze Window Decorationxx +Name[zh_CN]=微风窗口装饰 +Name[zh_TW]=Breeze 視窗裝飾 +Comment=Modify the appearance of window decorations +Comment[ar]=عدّل مظهر زخرفات النّوافذ +Comment[ca]=Modifica l'aparença de les decoracions de les finestres +Comment[ca@valencia]=Modifica l'aparença de les decoracions de les finestres +Comment[cs]=Změnit vzhled dekorace oken +Comment[da]=Ændr vinduesdekorationers udseende +Comment[de]=Das Erscheinungsbild der Fensterdekorationen ändern +Comment[el]=Τροποποίηση εμφάνισης της διακόσμησης παραθύρου +Comment[en_GB]=Modify the appearance of window decorations +Comment[es]=Modificar el aspecto de las decoraciones de las ventanas +Comment[et]=Akna dekoratsioonide välimuse muutmine +Comment[eu]=Aldatu leiho apainduren itxura +Comment[fi]=Muuta ikkunoiden kehysten ulkoasua +Comment[fr]=Modifier l'apparence des décorations des fenêtres +Comment[gl]=Modifica a aparencia da decoración da xanela +Comment[he]=התאם את מראה מסגרות החלונות +Comment[hu]=Az ablakdekorációk megjelenésének módosítása +Comment[ia]=Modifica le apparentia de decorationes de fenestra +Comment[it]=Modifica l'aspetto delle decorazioni delle finestre +Comment[ko]=창 장식의 모습을 수정합니다 +Comment[lt]=Keisti lango dekoracijų išvaizdą +Comment[nb]=Endre utseende for vindusdekorasjoner +Comment[nl]=Wijzig het uiterlijk van vensterdecoraties +Comment[nn]=Endra utsjånad på vindaugspynt +Comment[pl]=Zmień wygląd i wystrój okien +Comment[pt]=Modificar a aparência das decorações das janelas +Comment[pt_BR]=Modifica a aparência das decorações da janela +Comment[ro]=Modifică aspectul decorațiilor pentru ferestre +Comment[ru]=Настройка заголовков окон в стиле Breeze +Comment[sk]=Zmena vzhľadu dekorácie okien +Comment[sl]=Spremenite videz okraskov oken +Comment[sr]=Измените изглед декорација прозора +Comment[sr@ijekavian]=Измијените изглед декорација прозора +Comment[sr@ijekavianlatin]=Izmijenite izgled dekoracija prozora +Comment[sr@latin]=Izmenite izgled dekoracija prozora +Comment[sv]=Ändra utseendet hos fönsterdekorationer +Comment[tr]=Pencere dekorasyonlarının görünümünü değiştir +Comment[uk]=Зміна вигляду декорацій вікон +Comment[x-test]=xxModify the appearance of window decorationsxx +Comment[zh_CN]=修改窗口装饰外观 +Comment[zh_TW]=變更視窗裝飾外觀 +X-KDE-Keywords=breeze,decoration +X-KDE-Keywords[ar]=نسيم,زخرفة +X-KDE-Keywords[ca]=breeze,brisa,decoració +X-KDE-Keywords[ca@valencia]=breeze,brisa,decoració +X-KDE-Keywords[cs]=breeze,dekorace +X-KDE-Keywords[da]=breeze,dekoration +X-KDE-Keywords[de]=Breeze-Dekoration +X-KDE-Keywords[el]=breeze,διακόσμηση +X-KDE-Keywords[en_GB]=breeze,decoration +X-KDE-Keywords[es]=breeze,brisa,decoración +X-KDE-Keywords[et]=breeze,dekoratsioon +X-KDE-Keywords[eu]=breeze,apainketa,apaindura +X-KDE-Keywords[fi]=breeze,decoration,kehys,koriste,koristus,ikkunakehys +X-KDE-Keywords[fr]=breeze,décoration +X-KDE-Keywords[gl]=breeze,decoración +X-KDE-Keywords[he]=breeze,decoration,מסגרת +X-KDE-Keywords[hu]=breeze,dekoráció +X-KDE-Keywords[ia]=breeze,decoration +X-KDE-Keywords[it]=brezza,decorazione +X-KDE-Keywords[ko]=breeze,decoration,장식 +X-KDE-Keywords[lt]=breeze,kekoracija +X-KDE-Keywords[nb]=beeze,dekorasjon +X-KDE-Keywords[nl]=breeze,decoratie +X-KDE-Keywords[nn]=breeze,dekorasjonar,pynt +X-KDE-Keywords[pl]=breeze,dekoracja,bryza,wystrój +X-KDE-Keywords[pt]=brisa,decoração +X-KDE-Keywords[pt_BR]=breeze,decoração +X-KDE-Keywords[ro]=briză,breeze,decorare,decorație +X-KDE-Keywords[ru]=breeze,бриз,decoration,декорации окон,оформление окон +X-KDE-Keywords[sk]=breeze,dekorácia +X-KDE-Keywords[sl]=sapica,okraski +X-KDE-Keywords[sr]=breeze,decoration,Поветарац,декорација +X-KDE-Keywords[sr@ijekavian]=breeze,decoration,Поветарац,декорација +X-KDE-Keywords[sr@ijekavianlatin]=breeze,decoration,Povetarac,dekoracija +X-KDE-Keywords[sr@latin]=breeze,decoration,Povetarac,dekoracija +X-KDE-Keywords[sv]=breeze,dekoration +X-KDE-Keywords[tr]=esinti,dekorasyon +X-KDE-Keywords[uk]=breeze,decoration,бриз,декорації,декорація,обрамлення +X-KDE-Keywords[x-test]=xxbreezexx,xxdecorationxx +X-KDE-Keywords[zh_CN]=breeze,decoration,微风,装饰 +X-KDE-Keywords[zh_TW]=breeze,decoration diff --git a/config/breezedetectwidget.cpp b/config/breezedetectwidget.cpp new file mode 100644 index 0000000..e603cce --- /dev/null +++ b/config/breezedetectwidget.cpp @@ -0,0 +1,184 @@ + +////////////////////////////////////////////////////////////////////////////// +// breezedetectwidget.cpp +// Note: this class is a stripped down version of +// /kdebase/workspace/kwin/kcmkwin/kwinrules/detectwidget.cpp +// Copyright (c) 2004 Lubos Lunak +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "breezedetectwidget.h" + +#include "breeze.h" + +#include + +#include +#include +#include +#if BREEZE_HAVE_X11 +#include +#include +#endif + +namespace Breeze +{ + + //_________________________________________________________ + DetectDialog::DetectDialog( QWidget* parent ): + QDialog( parent ) + { + + // setup + m_ui.setupUi( this ); + + connect( m_ui.buttonBox->button( QDialogButtonBox::Cancel ), SIGNAL(clicked()), this, SLOT(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 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 ); + + return; + + } + + //_________________________________________________________ + 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( 0, 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 explicitely release cursor for Qt5 + qApp->restoreOverrideCursor(); + + // delete old m_grabber + delete m_grabber; + m_grabber = 0; + + // 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 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 reply( xcb_get_property_reply( connection, cookie, nullptr ) ); + if( reply && reply->type ) return child; + else parent = child; + + } + #endif + + return 0; + + } + +} diff --git a/config/breezedetectwidget.h b/config/breezedetectwidget.h new file mode 100644 index 0000000..83b92d8 --- /dev/null +++ b/config/breezedetectwidget.h @@ -0,0 +1,113 @@ +#ifndef breezedetectwidget_h +#define breezedetectwidget_h + +////////////////////////////////////////////////////////////////////////////// +// breezedetectwidget.h +// Note: this class is a stripped down version of +// /kdebase/workspace/kwin/kcmkwin/kwinrules/detectwidget.h +// Copyright (c) 2004 Lubos Lunak + +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "breezesettings.h" +#include "ui_breezedetectwidget.h" + +#include +#include +#include +#include +#include + +#include + +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( void ); + + //* ui + Ui::BreezeDetectWidget m_ui; + + //* invisible dialog used to grab mouse + QDialog* m_grabber = nullptr; + + //* current window information + QScopedPointer m_info; + + //* wm state atom + quint32 m_wmStateAtom = 0; + + }; + +} // namespace + +#endif diff --git a/config/breezeexceptiondialog.cpp b/config/breezeexceptiondialog.cpp new file mode 100644 index 0000000..f491e0c --- /dev/null +++ b/config/breezeexceptiondialog.cpp @@ -0,0 +1,184 @@ +////////////////////////////////////////////////////////////////////////////// +// breezeexceptiondialog.cpp +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "breezeexceptiondialog.h" +#include "breezedetectwidget.h" +#include "config-breeze.h" + +#if BREEZE_HAVE_X11 +#include +#endif + +namespace Breeze +{ + + //___________________________________________ + ExceptionDialog::ExceptionDialog( QWidget* parent ): + QDialog( parent ) + { + + m_ui.setupUi( this ); + + connect( m_ui.buttonBox->button( QDialogButtonBox::Cancel ), SIGNAL(clicked()), this, SLOT(close()) ); + + // store checkboxes from ui into list + m_checkboxes.insert( BorderSize, m_ui.borderSizeCheckBox ); + + // detect window properties + connect( m_ui.detectDialogButton, SIGNAL(clicked()), SLOT(selectWindowProperties()) ); + + // connections + connect( m_ui.exceptionType, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) ); + connect( m_ui.exceptionEditor, SIGNAL(textChanged(QString)), SLOT(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(), SIGNAL(clicked()), SLOT(updateChanged()) ); } + + connect( m_ui.hideTitleBar, SIGNAL(clicked()), SLOT(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( void ) + { + 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( void ) + { + 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( void ) + { + + // create widget + if( !m_detectDialog ) + { + m_detectDialog = new DetectDialog( this ); + connect( m_detectDialog, SIGNAL(detectionDone(bool)), SLOT(readWindowProperties(bool)) ); + } + + 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 = 0; + + } + +} diff --git a/config/breezeexceptiondialog.h b/config/breezeexceptiondialog.h new file mode 100644 index 0000000..37fc478 --- /dev/null +++ b/config/breezeexceptiondialog.h @@ -0,0 +1,114 @@ +#ifndef breezeexceptiondialog_h +#define breezeexceptiondialog_h +////////////////////////////////////////////////////////////////////////////// +// breezeexceptiondialog.h +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "ui_breezeexceptiondialog.h" +#include "breeze.h" + +#include +#include + +namespace Breeze +{ + + class DetectDialog; + + //* breeze exceptions list + class ExceptionDialog: public QDialog + { + + Q_OBJECT + + public: + + //* constructor + explicit ExceptionDialog( QWidget* parent ); + + //* destructor + virtual ~ExceptionDialog( void ) + {} + + //* set exception + void setException( InternalSettingsPtr ); + + //* save exception + void save( void ); + + //* true if changed + virtual bool isChanged( void ) const + { return m_changed; } + + Q_SIGNALS: + + //* emmited 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( void ); + + //* 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 diff --git a/config/breezeexceptionlistwidget.cpp b/config/breezeexceptionlistwidget.cpp new file mode 100644 index 0000000..3d3703d --- /dev/null +++ b/config/breezeexceptionlistwidget.cpp @@ -0,0 +1,355 @@ +////////////////////////////////////////////////////////////////////////////// +// breezeexceptionlistwidget.cpp +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "breezeexceptionlistwidget.h" +#include "breezeexceptiondialog.h" + +#include + +#include +#include +#include + +//__________________________________________________________ +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 ); + 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, SIGNAL(clicked()), SLOT(add()) ); + connect( m_ui.editButton, SIGNAL(clicked()), SLOT(edit()) ); + connect( m_ui.removeButton, SIGNAL(clicked()), SLOT(remove()) ); + connect( m_ui.moveUpButton, SIGNAL(clicked()), SLOT(up()) ); + connect( m_ui.moveDownButton, SIGNAL(clicked()), SLOT(down()) ); + + connect( m_ui.exceptionListView, SIGNAL(activated(QModelIndex)), SLOT(edit()) ); + connect( m_ui.exceptionListView, SIGNAL(clicked(QModelIndex)), SLOT(toggle(QModelIndex)) ); + connect( m_ui.exceptionListView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(updateButtons()) ); + + updateButtons(); + resizeColumns(); + + + } + + //__________________________________________________________ + void ExceptionListWidget::setExceptions( const InternalSettingsList& exceptions ) + { + model().set( exceptions ); + resizeColumns(); + setChanged( false ); + } + + //__________________________________________________________ + InternalSettingsList ExceptionListWidget::exceptions( void ) + { + return model().get(); + setChanged( false ); + } + + //__________________________________________________________ + void ExceptionListWidget::updateButtons( void ) + { + + 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( void ) + { + + + QPointer 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(); + return; + + } + + //_______________________________________________________ + void ExceptionListWidget::edit( void ) + { + + // retrieve selection + QModelIndex current( m_ui.exceptionListView->selectionModel()->currentIndex() ); + if( ! model().contains( current ) ) return; + + InternalSettingsPtr exception( model().get( current ) ); + + // create dialog + QPointer 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 ); + + return; + + } + + //_______________________________________________________ + void ExceptionListWidget::remove( void ) + { + + // 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 ); + + return; + + } + + //_______________________________________________________ + 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 ); + return; + + } + + //_______________________________________________________ + void ExceptionListWidget::up( void ) + { + + 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 ); + + return; + + } + + //_______________________________________________________ + void ExceptionListWidget::down( void ) + { + + 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 ); + + return; + + } + + //_______________________________________________________ + void ExceptionListWidget::resizeColumns( void ) 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 dialog( new ExceptionDialog( this ) ); + dialog->setException( exception ); + if( dialog->exec() == QDialog::Rejected ) + { + delete dialog; + return false; + } + + dialog->save(); + delete dialog; + } + + return true; + } + +} diff --git a/config/breezeexceptionlistwidget.h b/config/breezeexceptionlistwidget.h new file mode 100644 index 0000000..94b90d4 --- /dev/null +++ b/config/breezeexceptionlistwidget.h @@ -0,0 +1,124 @@ +#ifndef breezeexceptionlistwidget_h +#define breezeexceptionlistwidget_h +////////////////////////////////////////////////////////////////////////////// +// breezeexceptionlistwidget.h +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#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* = 0 ); + + //* set exceptions + void setExceptions( const InternalSettingsList& ); + + //* get exceptions + InternalSettingsList exceptions( void ); + + //* true if changed + virtual bool isChanged( void ) 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( void ); + + //* add + virtual void add( void ); + + //* edit + virtual void edit( void ); + + //* remove + virtual void remove( void ); + + //* toggle + virtual void toggle( const QModelIndex& ); + + //* move up + virtual void up( void ); + + //* move down + virtual void down( void ); + + protected: + + //* resize columns + void resizeColumns( void ) 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 diff --git a/config/breezeexceptionmodel.cpp b/config/breezeexceptionmodel.cpp new file mode 100644 index 0000000..db5cce4 --- /dev/null +++ b/config/breezeexceptionmodel.cpp @@ -0,0 +1,107 @@ +////////////////////////////////////////////////////////////////////////////// +// breezeexceptionmodel.cpp +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "breezeexceptionmodel.h" + +#include + +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(); + + } + +} diff --git a/config/breezeexceptionmodel.h b/config/breezeexceptionmodel.h new file mode 100644 index 0000000..767e288 --- /dev/null +++ b/config/breezeexceptionmodel.h @@ -0,0 +1,81 @@ +#ifndef breezeexceptionmodel_h +#define breezeexceptionmodel_h +////////////////////////////////////////////////////////////////////////////// +// breezeexceptionmodel.h +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "breezelistmodel.h" +#include "breezesettings.h" +#include "breeze.h" + +namespace Breeze +{ + + //* qlistview for object counters + class ExceptionModel: public ListModel + { + + 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 diff --git a/config/breezeitemmodel.cpp b/config/breezeitemmodel.cpp new file mode 100644 index 0000000..7ca71a3 --- /dev/null +++ b/config/breezeitemmodel.cpp @@ -0,0 +1,68 @@ +////////////////////////////////////////////////////////////////////////////// +// itemmodel.cpp +// ------------------- +// +// Copyright (c) 2009-2010 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#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; + + } + +} diff --git a/config/breezeitemmodel.h b/config/breezeitemmodel.h new file mode 100644 index 0000000..a50ab8f --- /dev/null +++ b/config/breezeitemmodel.h @@ -0,0 +1,113 @@ +#ifndef ItemModel_h +#define ItemModel_h + +////////////////////////////////////////////////////////////////////////////// +// itemmodel.h +// ------------------- +// +// Copyright (c) 2009-2010 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include + +namespace Breeze +{ + + //* Job model. Stores job information for display in lists + class ItemModel : public QAbstractItemModel + { + + public: + + //* constructor + explicit ItemModel(QObject *parent = 0); + + //* 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( void ) + { sort( sortColumn(), sortOrder() ); } + + //* sort + void sort( int column, Qt::SortOrder order = Qt::AscendingOrder ) override; + + //* current sorting column + const int& sortColumn( void ) const + { return m_sortColumn; } + + //* current sort order + const Qt::SortOrder& sortOrder( void ) const + { return m_sortOrder; } + + //@} + + protected: + + //* this sort columns without calling the layout changed callbacks + void privateSort( void ) + { privateSort( m_sortColumn, m_sortOrder ); } + + //* private sort, with no signals emmitted + 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 diff --git a/config/breezelistmodel.h b/config/breezelistmodel.h new file mode 100644 index 0000000..267c78d --- /dev/null +++ b/config/breezelistmodel.h @@ -0,0 +1,369 @@ +#ifndef ListModel_h +#define ListModel_h +////////////////////////////////////////////////////////////////////////////// +// listmodel.h +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "breezeitemmodel.h" + +#include +#include + +#include + +namespace Breeze +{ + //! Job model. Stores job information for display in lists + template class ListModel : public ItemModel + { + + public: + + //! value type + typedef T ValueType; + + //! reference + typedef T& Reference; + + //! pointer + typedef T* Pointer; + + //! value list and iterators + typedef QList List; + typedef QListIterator ListIterator; + typedef QMutableListIterator MutableListIterator; + + //! list of vector + // typedef QSet Set; + + //! constructor + ListModel(QObject *parent = 0): + ItemModel( parent ) + {} + + //! destructor + virtual ~ListModel() + {} + + //!@name methods reimplemented from base class + //@{ + + //! flags + Qt::ItemFlags flags(const QModelIndex &index) const override + { + if (!index.isValid()) return 0; + 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( void ) + { _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( void ) 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(); + return; + + } + + //! 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(); + return; + + } + + //! clear + virtual void clear( void ) + { 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; + } + + //! 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 diff --git a/config/ui/breezeconfigurationui.ui b/config/ui/breezeconfigurationui.ui new file mode 100644 index 0000000..5fad196 --- /dev/null +++ b/config/ui/breezeconfigurationui.ui @@ -0,0 +1,475 @@ + + + BreezeConfigurationUI + + + + 0 + 0 + 445 + 418 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + General + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Add handle to resize windows with no border + + + + + + + Tit&le alignment: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + titleAlignment + + + + + + + B&utton size: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + buttonSize + + + + + + + + Tiny + + + + + Small + + + + + Medium + + + + + Large + + + + + Very Large + + + + + + + + + Left + + + + + Center + + + + + Center (Full Width) + + + + + Right + + + + + + + + Draw separator between Title Bar and Window + + + + + + + Allow resizing maximized windows from window edges + + + + + + + Draw a circle around close button + + + + + + + Draw window background gradient + + + + + + + + + Opacity: + + + + + + + 10 + + + 1 + + + 1 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + + + + + + + + Animations + + + + + + false + + + Anima&tions duration: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + animationsDuration + + + + + + + false + + + ms + + + 500 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Enable animations + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Shadows + + + + + + Si&ze: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + shadowSize + + + + + + + + None + + + + + Small + + + + + Medium + + + + + Large + + + + + Very Large + + + + + + + + S&trength: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + shadowStrength + + + + + + + % + + + 10 + + + 100 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Color: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Window-Specific Overrides + + + + + + + 0 + 0 + + + + + + + + + + + + + KColorButton + QPushButton +
kcolorbutton.h
+
+ + Breeze::ExceptionListWidget + QWidget +
config/breezeexceptionlistwidget.h
+ 1 +
+
+ + tabWidget + titleAlignment + buttonSize + outlineCloseButton + drawBorderOnMaximizedWindows + drawBackgroundGradient + drawSizeGrip + drawTitleBarSeparator + animationsEnabled + animationsDuration + shadowSize + shadowStrength + shadowColor + + + + + animationsEnabled + toggled(bool) + animationsDurationLabel + setEnabled(bool) + + + 34 + 194 + + + 84 + 221 + + + + + animationsEnabled + toggled(bool) + animationsDuration + setEnabled(bool) + + + 108 + 194 + + + 141 + 229 + + + + +
diff --git a/config/ui/breezedetectwidget.ui b/config/ui/breezedetectwidget.ui new file mode 100644 index 0000000..5db36c8 --- /dev/null +++ b/config/ui/breezedetectwidget.ui @@ -0,0 +1,146 @@ + + + BreezeDetectWidget + + + + 0 + 0 + 400 + 239 + + + + Dialog + + + + + + Information about Selected Window + + + + + + Class: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + TextLabel + + + + + + + Title: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + TextLabel + + + + + + + + + + Window Property Selection + + + + + + Use window class (whole application) + + + + + + + + + + Use window title + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + BreezeDetectWidget + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + BreezeDetectWidget + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/config/ui/breezeexceptiondialog.ui b/config/ui/breezeexceptiondialog.ui new file mode 100644 index 0000000..3f78a44 --- /dev/null +++ b/config/ui/breezeexceptiondialog.ui @@ -0,0 +1,231 @@ + + + BreezeExceptionDialog + + + + 0 + 0 + 362 + 321 + + + + Dialog + + + + + + Window Identification + + + + + + &Matching window property: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + exceptionType + + + + + + + Regular expression &to match: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + exceptionEditor + + + + + + + Detect Window Properties + + + + + + + true + + + + + + + + Window Class Name + + + + + Window Title + + + + + + + + + + + Decoration Options + + + + + + Border size: + + + + + + + Hide window title bar + + + + + + + false + + + + No Border + + + + + No Side Borders + + + + + Tiny + + + + + Normal + + + + + Large + + + + + Very Large + + + + + Huge + + + + + Very Huge + + + + + Oversized + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + BreezeExceptionDialog + accept() + + + 252 + 342 + + + 157 + 274 + + + + + buttonBox + rejected() + BreezeExceptionDialog + reject() + + + 320 + 342 + + + 286 + 274 + + + + + borderSizeCheckBox + toggled(bool) + borderSizeComboBox + setEnabled(bool) + + + 125 + 162 + + + 316 + 163 + + + + + diff --git a/config/ui/breezeexceptionlistwidget.ui b/config/ui/breezeexceptionlistwidget.ui new file mode 100644 index 0000000..bf08c76 --- /dev/null +++ b/config/ui/breezeexceptionlistwidget.ui @@ -0,0 +1,114 @@ + + + BreezeExceptionListWidget + + + + 0 + 0 + 473 + 182 + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 100 + 100 + + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + + + + + Move Up + + + + + + + Move Down + + + + + + + Add + + + + + + + Remove + + + + + + + Edit + + + + + + + exceptionListView + moveUpButton + moveDownButton + addButton + removeButton + editButton + + + +