├── NEWS ├── screenshots ├── Buttons.png ├── Animation.gif ├── Exception.png └── Settings.png ├── breezesettings.kcfgc ├── config ├── kcm_breezeenhanced.cpp ├── CMakeLists.txt ├── kcm_breezeenhanced.json ├── breezedetectwidget.h ├── breezedetectwidget.cpp ├── breezeitemmodel.cpp ├── breezeexceptionmodel.h ├── breezeconfigwidget.h ├── ui │ ├── breezeexceptionlistwidget.ui │ ├── breezeexceptiondialog.ui │ └── breezeconfigurationui.ui ├── breezeexceptiondialog.h ├── breezeitemmodel.h ├── breezeexceptionlistwidget.h ├── breezeexceptionmodel.cpp ├── breezeexceptiondialog.cpp ├── breezelistmodel.h ├── breezeexceptionlistwidget.cpp └── breezeconfigwidget.cpp ├── breeze.json ├── breezeenhanced.json ├── libbreezecommon ├── CMakeLists.txt ├── breezeboxshadowrenderer.h └── breezeboxshadowrenderer.cpp ├── breezesettingsprovider.h ├── breeze.h ├── breezeexceptionlist.h ├── README.md ├── CMakeLists.txt ├── ChangeLog ├── breezebutton.h ├── breezesettingsprovider.cpp ├── breezesettingsdata.kcfg ├── breezeexceptionlist.cpp ├── breezedecoration.h └── LICENSE /NEWS: -------------------------------------------------------------------------------- 1 | Latest version: 2 | 3 | 7 Nov 2025, V6.5 4 | 5 | See "ChangeLog" for changes. 6 | -------------------------------------------------------------------------------- /screenshots/Buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsujan/BreezeEnhanced/HEAD/screenshots/Buttons.png -------------------------------------------------------------------------------- /screenshots/Animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsujan/BreezeEnhanced/HEAD/screenshots/Animation.gif -------------------------------------------------------------------------------- /screenshots/Exception.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsujan/BreezeEnhanced/HEAD/screenshots/Exception.png -------------------------------------------------------------------------------- /screenshots/Settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsujan/BreezeEnhanced/HEAD/screenshots/Settings.png -------------------------------------------------------------------------------- /breezesettings.kcfgc: -------------------------------------------------------------------------------- 1 | File=breezesettingsdata.kcfg 2 | ClassName=InternalSettings 3 | NameSpace=Breeze 4 | Singleton=false 5 | Mutators=true 6 | GlobalEnums=true 7 | -------------------------------------------------------------------------------- /config/kcm_breezeenhanced.cpp: -------------------------------------------------------------------------------- 1 | #include "breezeconfigwidget.h" 2 | #include 3 | 4 | K_PLUGIN_CLASS_WITH_JSON(Breeze::ConfigWidget, "kcm_breezeenhanced.json") 5 | 6 | #include "kcm_breezeenhanced.moc" 7 | -------------------------------------------------------------------------------- /breeze.json: -------------------------------------------------------------------------------- 1 | { 2 | "KPlugin": { 3 | "Description": "Window decoration using the Breeze visual style for the Plasma Desktop", 4 | "EnabledByDefault": true, 5 | "Name": "BreezeEnhanced", 6 | }, 7 | "X-KDE-ConfigModule": "kcm_breezeenhanced", 8 | "org.kde.kdecoration3": { 9 | "blur": true, 10 | "recommendedBorderSize": "None" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /config/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | kcoreaddons_add_plugin(kcm_breezeenhanced SOURCES kcm_breezeenhanced.cpp INSTALL_NAMESPACE "${KDECORATION_KCM_PLUGIN_DIR}") 2 | target_include_directories(kcm_breezeenhanced PRIVATE ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}/) 3 | target_link_libraries(kcm_breezeenhanced breezeenhancedcommon6 breezeenhanced_STATIC KF6::I18n KF6::KCMUtils Qt::DBus) 4 | kcmutils_generate_desktop_file(kcm_breezeenhanced) 5 | -------------------------------------------------------------------------------- /config/kcm_breezeenhanced.json: -------------------------------------------------------------------------------- 1 | { 2 | "KPlugin": { 3 | "Description": "Modify the appearance of window decorations", 4 | "Icon": "preferences-system-windows", 5 | "Name": "BreezeEnhanced Window Decoration", 6 | "ServiceTypes": [ 7 | "KCModule" 8 | ] 9 | }, 10 | "X-KDE-Keywords": "BreezeEnhanced,decoration", 11 | "X-KDE-ParentApp": "kcontrol", 12 | "X-KDE-Weight": 60 13 | } 14 | -------------------------------------------------------------------------------- /breezeenhanced.json: -------------------------------------------------------------------------------- 1 | { 2 | "KPlugin": { 3 | "Description": "Window decoration using the Breeze visual style for the Plasma Desktop", 4 | "EnabledByDefault": true, 5 | "Id": "org.kde.breezeenhanced", 6 | "Name": "BreezeEnhanced", 7 | "ServiceTypes": [ 8 | "org.kde.kdecoration2" 9 | ] 10 | }, 11 | "X-KDE-ConfigModule": "kcm_breezeenhanced", 12 | "org.kde.kdecoration2": { 13 | "blur": true, 14 | "recommendedBorderSize": "None" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libbreezecommon/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ################# dependencies ################# 2 | ### Qt/KDE 3 | find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} REQUIRED CONFIG COMPONENTS Widgets) 4 | 5 | ################# breezestyle target ################# 6 | set(breezeenhancedcommon_LIB_SRCS 7 | breezeboxshadowrenderer.cpp 8 | ) 9 | 10 | add_library(breezeenhancedcommon6 ${breezeenhancedcommon_LIB_SRCS}) 11 | 12 | generate_export_header(breezeenhancedcommon6 13 | BASE_NAME breezecommon 14 | EXPORT_FILE_NAME breezecommon_export.h) 15 | 16 | target_link_libraries(breezeenhancedcommon6 17 | PUBLIC 18 | Qt::Core 19 | Qt::Gui) 20 | 21 | set_target_properties(breezeenhancedcommon6 PROPERTIES 22 | VERSION ${PROJECT_VERSION} 23 | SOVERSION ${PROJECT_VERSION_MAJOR}) 24 | 25 | install(TARGETS breezeenhancedcommon6 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP) 26 | -------------------------------------------------------------------------------- /config/breezedetectwidget.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // breezedetectwidget.h 3 | // Note: this class is a stripped down version of 4 | // /kdebase/workspace/kwin/kcmkwin/kwinrules/detectwidget.h 5 | // SPDX-FileCopyrightText: 2004 Lubos Lunak 6 | 7 | // ------------------- 8 | // 9 | // SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa 10 | // 11 | // SPDX-License-Identifier: MIT 12 | ////////////////////////////////////////////////////////////////////////////// 13 | 14 | #pragma once 15 | 16 | #include 17 | #include 18 | 19 | namespace Breeze 20 | { 21 | class DetectDialog : public QObject 22 | { 23 | Q_OBJECT 24 | 25 | public: 26 | //* constructor 27 | explicit DetectDialog(QObject *parent = nullptr); 28 | 29 | //* read window properties or select one from mouse grab 30 | void detect(); 31 | 32 | //* window properties 33 | QVariantMap properties() const; 34 | 35 | Q_SIGNALS: 36 | void detectionDone(bool); 37 | 38 | private: 39 | //* properties 40 | QVariantMap m_properties; 41 | }; 42 | 43 | } // namespace 44 | 45 | -------------------------------------------------------------------------------- /breezesettingsprovider.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Hugo Pereira Da Costa 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | 22 | #pragma once 23 | 24 | #include "breeze.h" 25 | #include "breezedecoration.h" 26 | #include "breezesettings.h" 27 | 28 | #include 29 | 30 | #include 31 | 32 | namespace Breeze 33 | { 34 | 35 | class SettingsProvider: public QObject 36 | { 37 | 38 | Q_OBJECT 39 | 40 | public: 41 | 42 | //* destructor 43 | ~SettingsProvider(); 44 | 45 | //* singleton 46 | static SettingsProvider *self(); 47 | 48 | //* internal settings for given decoration 49 | InternalSettingsPtr internalSettings(Decoration *) const; 50 | 51 | public Q_SLOTS: 52 | 53 | //* reconfigure 54 | void reconfigure(); 55 | 56 | private: 57 | 58 | //* constructor 59 | SettingsProvider(); 60 | 61 | //* default configuration 62 | InternalSettingsPtr m_defaultSettings; 63 | 64 | //* exceptions 65 | InternalSettingsList m_exceptions; 66 | 67 | //* config object 68 | KSharedConfigPtr m_config; 69 | 70 | //* singleton 71 | static SettingsProvider *s_self; 72 | 73 | }; 74 | 75 | } 76 | 77 | -------------------------------------------------------------------------------- /config/breezedetectwidget.cpp: -------------------------------------------------------------------------------- 1 | 2 | ////////////////////////////////////////////////////////////////////////////// 3 | // breezedetectwidget.cpp 4 | // Note: this class is a stripped down version of 5 | // /kdebase/workspace/kwin/kcmkwin/kwinrules/detectwidget.cpp 6 | // SPDX-FileCopyrightText: 2004 Lubos Lunak 7 | // ------------------- 8 | // 9 | // SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa 10 | // 11 | // SPDX-License-Identifier: MIT 12 | ////////////////////////////////////////////////////////////////////////////// 13 | 14 | #include "breezedetectwidget.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace Breeze 22 | { 23 | //_________________________________________________________ 24 | DetectDialog::DetectDialog(QObject *parent) 25 | : QObject(parent) 26 | { 27 | } 28 | 29 | //_________________________________________________________ 30 | void DetectDialog::detect() 31 | { 32 | QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KWin"), 33 | QStringLiteral("/KWin"), 34 | QStringLiteral("org.kde.KWin"), 35 | QStringLiteral("queryWindowInfo")); 36 | 37 | QDBusPendingReply asyncReply = QDBusConnection::sessionBus().asyncCall(message); 38 | QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncReply, this); 39 | connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *self) { 40 | QDBusPendingReply reply = *self; 41 | self->deleteLater(); 42 | if (!reply.isValid()) { 43 | Q_EMIT detectionDone(false); 44 | return; 45 | } 46 | m_properties = reply.value(); 47 | Q_EMIT detectionDone(true); 48 | }); 49 | } 50 | 51 | //_________________________________________________________ 52 | QVariantMap DetectDialog::properties() const 53 | { 54 | return m_properties; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /breeze.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Hugo Pereira Da Costa 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "breezesettings.h" 24 | 25 | #include 26 | #include 27 | 28 | namespace Breeze 29 | { 30 | //* convenience typedefs 31 | using InternalSettingsPtr = QSharedPointer; 32 | using InternalSettingsList = QList; 33 | using InternalSettingsListIterator = QListIterator; 34 | 35 | //* metrics 36 | namespace Metrics 37 | { 38 | //* corner radius, in units of small spacing 39 | static constexpr qreal Frame_FrameRadius = 2; 40 | 41 | //* titlebar metrics, in units of small spacing 42 | static constexpr int TitleBar_TopMargin = 2; 43 | static constexpr int TitleBar_BottomMargin = 2; 44 | static constexpr int TitleBar_SideMargin = 2; 45 | static constexpr int TitleBar_ButtonSpacing = 2; 46 | 47 | // shadow dimensions (pixels) 48 | static constexpr int Shadow_Overlap = 3; 49 | } 50 | 51 | //* standard pen widths 52 | namespace PenWidth 53 | { 54 | /* Using 1 instead of slightly more than 1 causes symbols drawn with 55 | * pen strokes to look skewed. The exact amount added does not matter 56 | * as long as it isn't too visible. 57 | */ 58 | // The standard pen stroke width for symbols. 59 | static constexpr qreal Symbol = 1.01; 60 | } 61 | 62 | //* exception 63 | enum ExceptionMask 64 | { 65 | None = 0, 66 | BorderSize = 1<<4 67 | }; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /config/breezeitemmodel.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // itemmodel.cpp 3 | // ------------------- 4 | // 5 | // Copyright (c) 2009-2010 Hugo Pereira Da Costa 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including without limitation the 10 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | // sell copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | // IN THE SOFTWARE. 24 | ////////////////////////////////////////////////////////////////////////////// 25 | 26 | #include "breezeitemmodel.h" 27 | 28 | namespace Breeze 29 | { 30 | 31 | //_______________________________________________________________ 32 | ItemModel::ItemModel( QObject* parent ): 33 | QAbstractItemModel( parent ) 34 | {} 35 | 36 | //____________________________________________________________ 37 | void ItemModel::sort( int column, Qt::SortOrder order ) 38 | { 39 | 40 | // store column and order 41 | m_sortColumn = column; 42 | m_sortOrder = order; 43 | 44 | // emit signals and call private methods 45 | Q_EMIT layoutAboutToBeChanged(); 46 | privateSort( column, order ); 47 | Q_EMIT layoutChanged(); 48 | 49 | } 50 | 51 | //____________________________________________________________ 52 | QModelIndexList ItemModel::indexes( int column, const QModelIndex& parent ) const 53 | { 54 | QModelIndexList out; 55 | int rows( rowCount( parent ) ); 56 | for( int row = 0; row < rows; row++ ) 57 | { 58 | QModelIndex index( this->index( row, column, parent ) ); 59 | if( !index.isValid() ) continue; 60 | out.append( index ); 61 | out += indexes( column, index ); 62 | } 63 | 64 | return out; 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /breezeexceptionlist.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // breezeexceptionlist.h 3 | // window decoration exceptions 4 | // ------------------- 5 | // 6 | // Copyright (c) 2009 Hugo Pereira Da Costa 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to 10 | // deal in the Software without restriction, including without limitation the 11 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 12 | // sell copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 24 | // IN THE SOFTWARE. 25 | ////////////////////////////////////////////////////////////////////////////// 26 | 27 | #pragma once 28 | 29 | #include "breezesettings.h" 30 | #include "breeze.h" 31 | 32 | #include 33 | 34 | namespace Breeze 35 | { 36 | 37 | //! breeze exceptions list 38 | class ExceptionList 39 | { 40 | 41 | public: 42 | 43 | //! constructor from list 44 | explicit ExceptionList(const InternalSettingsList& exceptions = InternalSettingsList()): 45 | _exceptions(exceptions) 46 | {} 47 | 48 | //! exceptions 49 | const InternalSettingsList& get(void) const {return _exceptions;} 50 | 51 | //! read from KConfig 52 | void readConfig(KSharedConfig::Ptr); 53 | 54 | //! write to kconfig 55 | void writeConfig(KSharedConfig::Ptr); 56 | 57 | protected: 58 | 59 | //! generate exception group name for given exception index 60 | static QString exceptionGroupName(int index); 61 | 62 | //! read configuration 63 | static void readConfig(KCoreConfigSkeleton*, KConfig*, const QString&); 64 | 65 | //! write configuration 66 | static void writeConfig(KCoreConfigSkeleton*, KConfig*, const QString&); 67 | 68 | private: 69 | 70 | //! exceptions 71 | InternalSettingsList _exceptions; 72 | 73 | }; 74 | 75 | } 76 | 77 | -------------------------------------------------------------------------------- /config/breezeexceptionmodel.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // breezeexceptionmodel.h 3 | // ------------------- 4 | // 5 | // Copyright (c) 2009 Hugo Pereira Da Costa 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including without limitation the 10 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | // sell copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | // IN THE SOFTWARE. 24 | ////////////////////////////////////////////////////////////////////////////// 25 | 26 | #pragma once 27 | 28 | #include "breeze.h" 29 | #include "breezelistmodel.h" 30 | #include "breezesettings.h" 31 | 32 | namespace Breeze 33 | { 34 | 35 | //* qlistview for object counters 36 | class ExceptionModel: public ListModel 37 | { 38 | 39 | public: 40 | 41 | //* number of columns 42 | enum { nColumns = 3 }; 43 | 44 | //* column type enumeration 45 | enum ColumnType { 46 | ColumnEnabled, 47 | ColumnType, 48 | ColumnRegExp 49 | }; 50 | 51 | 52 | //*@name methods reimplemented from base class 53 | //@{ 54 | 55 | //* return data for a given index 56 | QVariant data(const QModelIndex &index, int role) const override; 57 | 58 | //* header data 59 | QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; 60 | 61 | //* number of columns for a given index 62 | int columnCount(const QModelIndex& ) const override 63 | { return nColumns; } 64 | 65 | //@} 66 | 67 | protected: 68 | 69 | //* sort 70 | void privateSort( int, Qt::SortOrder ) override 71 | {} 72 | 73 | private: 74 | 75 | //* column titles 76 | static const QString m_columnTitles[ nColumns ]; 77 | 78 | }; 79 | 80 | } 81 | 82 | -------------------------------------------------------------------------------- /config/breezeconfigwidget.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // breezeconfigurationui.h 3 | // ------------------- 4 | // 5 | // Copyright (c) 2009 Hugo Pereira Da Costa 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including without limitation the 10 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | // sell copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | // IN THE SOFTWARE. 24 | ////////////////////////////////////////////////////////////////////////////// 25 | 26 | #pragma once 27 | 28 | #include "breeze.h" 29 | #include "breezeexceptionlistwidget.h" 30 | #include "breezesettings.h" 31 | #include "ui_breezeconfigurationui.h" 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | 39 | namespace Breeze 40 | { 41 | 42 | //_____________________________________________ 43 | class ConfigWidget: public KCModule 44 | { 45 | 46 | Q_OBJECT 47 | 48 | public: 49 | 50 | //* constructor 51 | explicit ConfigWidget(QObject *parent, const KPluginMetaData &data, const QVariantList &args); 52 | 53 | //* destructor 54 | virtual ~ConfigWidget() = default; 55 | 56 | //* default 57 | void defaults() override; 58 | 59 | //* load configuration 60 | void load() override; 61 | 62 | //* save configuration 63 | void save() override; 64 | 65 | protected Q_SLOTS: 66 | 67 | //* update changed state 68 | virtual void updateChanged(); 69 | 70 | private: 71 | 72 | //* ui 73 | Ui_BreezeConfigurationUI m_ui; 74 | 75 | //* kconfiguration object 76 | KSharedConfig::Ptr m_configuration; 77 | 78 | //* internal exception 79 | InternalSettingsPtr m_internalSettings; 80 | 81 | //* changed state 82 | bool m_changed; 83 | 84 | }; 85 | 86 | } 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BreezeEnhanced 2 | 3 | ## Overview 4 | 5 | BreezeEnhanced is a fork of KDE Breeze decoration with the following changes: 6 | 7 | * The optional title-bar gradient is smooth and has a configurable intensity. 8 | * The title-bar opacity is configurable. 9 | * A very mild light line is added to the top of title-bar (especially for dark color schemes) and the separator between title-bar and window is removed. 10 | * By default, the close, minimize and maximize buttons are macOS-like and their sizes change on mouse-over when animation is enabled. 11 | * The spacing between buttons is configurable. 12 | * Opaqueness, opacity override and flatness are added to the exception list properties. 13 | * The title-bar font is set independently of the KDE font settings (for use outside KDE). 14 | 15 | Please note that BreezeEnhanced is not related to the Breeze widget style. In fact, it is made to match various themes of the [Kvantum](https://github.com/tsujan/Kvantum) widget style but it works with all styles. 16 | 17 | ## Credits: 18 | 19 | BreezeEnhanced was started from [BreezeBlurred](https://github.com/alex47/BreezeBlurred), a former fork of Breeze with title-bar translucency and blurring. 20 | 21 | Needless to say, the main work behind BreezeEnhanced is the Breeze KWin decoration itself, which can be downloaded from . 22 | 23 | ## Installation 24 | 25 | The version number in the file [NEWS](NEWS) shows the main version of KWin that is required for the compilation. *Compilation should not be done against other versions of KWin!* 26 | 27 | In what follows, it is supposed that the name of the installation directory of KDE libraries is `lib` and the installation prefix is `/usr`. If they are different in your distro, please replace them! 28 | 29 | Open a terminal inside the source directory and do: 30 | ```sh 31 | mkdir build && cd build 32 | cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DKDE_INSTALL_LIBDIR=lib -DBUILD_TESTING=OFF -DKDE_INSTALL_USE_QT_SYS_PATHS=ON 33 | make 34 | sudo make install 35 | ``` 36 | After the installation, restart KWin by logging out and in. Then, BreezeEnhanced will appear in *System Settings → Application Style → Window Decorations*. 37 | 38 | ### Installation with package manager 39 | 40 | Users of Arch and its derivatives can install breeze-enhanced-git from AUR. 41 | 42 | Users of OpenSUSE Tumbleweed can do (thanks to trmdi at GitHub): 43 | ```sh 44 | sudo zypper ar obs://home:trmdi trmdi 45 | sudo zypper in -r trmdi BreezeEnhanced 46 | ``` 47 | 48 | Users of Ubuntu can do (thanks to krisives at GitHub): 49 | ```sh 50 | sudo add-apt-repository ppa:krisives/breezeenhanced 51 | sudo apt-get update 52 | sudo apt install breezeenhanced 53 | ``` 54 | 55 | ## Screenshots: 56 | 57 | ![Settings](screenshots/Settings.png?raw=true "Settings") 58 | 59 | ![Exception](screenshots/Exception.png?raw=true "Exception") 60 | 61 | ![Buttons](screenshots/Buttons.png?raw=true "Buttons") 62 | 63 | ![Animation](screenshots/Animation.gif?raw=true "Animation") 64 | -------------------------------------------------------------------------------- /libbreezecommon/breezeboxshadowrenderer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Vlad Zagorodniy 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | */ 18 | 19 | #pragma once 20 | 21 | // own 22 | #include "breezecommon_export.h" 23 | 24 | // Qt 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | namespace Breeze 31 | { 32 | class BREEZECOMMON_EXPORT BoxShadowRenderer 33 | { 34 | public: 35 | // Compiler generated constructors & destructor are fine. 36 | 37 | /** 38 | * Set the size of the box. 39 | * @param size The size of the box. 40 | **/ 41 | void setBoxSize(const QSizeF &size); 42 | 43 | /** 44 | * Set the radius of box' corners. 45 | * @param radius The border radius, in pixels. 46 | **/ 47 | void setBorderRadius(qreal radius); 48 | 49 | /** 50 | * Add a shadow. 51 | * @param offset The offset of the shadow. 52 | * @param radius The blur radius. 53 | * @param color The color of the shadow. 54 | **/ 55 | void addShadow(const QPointF &offset, double radius, const QColor &color); 56 | 57 | /** 58 | * Render the shadow. 59 | **/ 60 | QImage render() const; 61 | 62 | /** 63 | * Calculate the minimum size of the box. 64 | * 65 | * This helper computes the minimum size of the box so the shadow behind it has 66 | * full its strength. 67 | * 68 | * @param radius The blur radius of the shadow. 69 | **/ 70 | static QSize calculateMinimumBoxSize(int radius); 71 | 72 | /** 73 | * Calculate the minimum size of the shadow texture. 74 | * 75 | * This helper computes the minimum size of the resulting texture so the shadow 76 | * is not clipped. 77 | * 78 | * @param boxSize The size of the box. 79 | * @param radius The blur radius. 80 | * @param offset The offset of the shadow. 81 | **/ 82 | static QSizeF calculateMinimumShadowTextureSize(const QSizeF &boxSize, double radius, const QPointF &offset); 83 | 84 | private: 85 | QSizeF m_boxSize; 86 | qreal m_borderRadius = 0.0; 87 | 88 | struct Shadow { 89 | QPointF offset; 90 | double radius; 91 | QColor color; 92 | }; 93 | 94 | QVector m_shadows; 95 | }; 96 | 97 | } // namespace Breeze 98 | -------------------------------------------------------------------------------- /config/ui/breezeexceptionlistwidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | BreezeExceptionListWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 473 10 | 182 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | 21 | 0 22 | 0 23 | 24 | 25 | 26 | 27 | 0 28 | 29 | 30 | 0 31 | 32 | 33 | 0 34 | 35 | 36 | 0 37 | 38 | 39 | 40 | 41 | 42 | 0 43 | 0 44 | 45 | 46 | 47 | 48 | 100 49 | 100 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | Qt::Vertical 58 | 59 | 60 | 61 | 20 62 | 1 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | Move Up 71 | 72 | 73 | 74 | 75 | 76 | 77 | Move Down 78 | 79 | 80 | 81 | 82 | 83 | 84 | Add 85 | 86 | 87 | 88 | 89 | 90 | 91 | Remove 92 | 93 | 94 | 95 | 96 | 97 | 98 | Edit 99 | 100 | 101 | 102 | 103 | 104 | 105 | exceptionListView 106 | moveUpButton 107 | moveDownButton 108 | addButton 109 | removeButton 110 | editButton 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /config/breezeexceptiondialog.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // breezeexceptiondialog.h 3 | // ------------------- 4 | // 5 | // Copyright (c) 2009 Hugo Pereira Da Costa 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including without limitation the 10 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | // sell copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | // IN THE SOFTWARE. 24 | ////////////////////////////////////////////////////////////////////////////// 25 | 26 | #pragma once 27 | 28 | #include "breeze.h" 29 | #include "ui_breezeexceptiondialog.h" 30 | 31 | #include 32 | #include 33 | 34 | namespace Breeze 35 | { 36 | 37 | class DetectDialog; 38 | 39 | //* breeze exceptions list 40 | class ExceptionDialog: public QDialog 41 | { 42 | 43 | Q_OBJECT 44 | 45 | public: 46 | 47 | //* constructor 48 | explicit ExceptionDialog( QWidget* parent ); 49 | 50 | //* destructor 51 | virtual ~ExceptionDialog() 52 | {} 53 | 54 | //* set exception 55 | void setException( InternalSettingsPtr ); 56 | 57 | //* save exception 58 | void save(); 59 | 60 | //* true if changed 61 | virtual bool isChanged() const 62 | { return m_changed; } 63 | 64 | Q_SIGNALS: 65 | 66 | //* emitted when changed 67 | void changed( bool ); 68 | 69 | protected: 70 | 71 | //* set changed state 72 | virtual void setChanged( bool value ) 73 | { 74 | m_changed = value; 75 | Q_EMIT changed( value ); 76 | } 77 | 78 | protected Q_SLOTS: 79 | 80 | //* check whether configuration is changed and emit appropriate signal if yes 81 | virtual void updateChanged(); 82 | 83 | private Q_SLOTS: 84 | 85 | //* select window properties from grabbed pointers 86 | void selectWindowProperties(); 87 | 88 | //* read properties of selected window 89 | void readWindowProperties( bool ); 90 | 91 | private: 92 | 93 | //* map mask and checkbox 94 | using CheckBoxMap=QMap< ExceptionMask, QCheckBox*>; 95 | 96 | Ui::BreezeExceptionDialog m_ui; 97 | 98 | //* map mask and checkbox 99 | CheckBoxMap m_checkboxes; 100 | 101 | //* internal exception 102 | InternalSettingsPtr m_exception; 103 | 104 | //* detection dialog 105 | DetectDialog* m_detectDialog = nullptr; 106 | 107 | //* changed state 108 | bool m_changed = false; 109 | 110 | }; 111 | 112 | } 113 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16 FATAL_ERROR) 2 | 3 | project(breezeenhanced) 4 | set(PROJECT_VERSION "6.5.0") 5 | set(PROJECT_VERSION_MAJOR 6) 6 | 7 | include(WriteBasicConfigVersionFile) 8 | include(FeatureSummary) 9 | set(QT_MIN_VERSION "6.9.0") 10 | set(KF6_MIN_VERSION "6.18.0") 11 | 12 | find_package(ECM ${KF6_MIN_VERSION} REQUIRED NO_MODULE) 13 | 14 | set(CPACK_PACKAGE_NAME "BreezeEnhanced") 15 | set(CPACK_PACKAGING_INSTALL_PREFIX "/usr") 16 | set(CPACK_PACKAGE_FILE_NAME "BreezeEnhanced") 17 | set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") 18 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Enhanced version of the Breeze Window Decoration for KWIN that pairs well with kvantum themes.") 19 | include(CPack) 20 | 21 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules") 22 | 23 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_SOURCE_DIR}/cmake) 24 | 25 | include(ECMInstallIcons) 26 | include(KDEInstallDirs6) 27 | include(KDECMakeSettings) 28 | include(KDECompilerSettings NO_POLICY_SCOPE) 29 | include(GenerateExportHeader) 30 | # include(GtkUpdateIconCache) 31 | 32 | find_package(KDecoration3 REQUIRED) 33 | 34 | find_package(KF6KCMUtils ${KF6_MIN_VERSION}) 35 | set_package_properties(KF6KCMUtils PROPERTIES 36 | TYPE REQUIRED 37 | DESCRIPTION "Helps create configuration modules" 38 | PURPOSE "KCMUtils used for the configuration modules or the decoration and Qt Style" 39 | ) 40 | 41 | # old stuff 42 | add_definitions(-DTRANSLATION_DOMAIN="breeze_kwin_deco") 43 | 44 | 45 | find_package(KF6 ${KF6_MIN_VERSION} REQUIRED COMPONENTS GuiAddons WindowSystem I18n) 46 | find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Widgets DBus) 47 | 48 | ################# includes ################# 49 | add_subdirectory(libbreezecommon) 50 | 51 | ################# newt target ################# 52 | ### plugin classes 53 | set(breezeenhanced_SRCS 54 | breezebutton.cpp 55 | breezedecoration.cpp 56 | breezesettingsprovider.cpp) 57 | 58 | ### config classes 59 | set(breezeenhanced_config_SRCS 60 | breezeexceptionlist.cpp 61 | config/breezeconfigwidget.cpp 62 | config/breezedetectwidget.cpp 63 | config/breezeexceptiondialog.cpp 64 | config/breezeexceptionlistwidget.cpp 65 | config/breezeexceptionmodel.cpp 66 | config/breezeitemmodel.cpp 67 | ) 68 | ki18n_wrap_ui(breezeenhanced_config_SRCS 69 | config/ui/breezeconfigurationui.ui 70 | config/ui/breezeexceptiondialog.ui 71 | config/ui/breezeexceptionlistwidget.ui 72 | ) 73 | add_library(breezeenhanced_STATIC STATIC ${breezeenhanced_config_SRCS}) 74 | # Needed to link this static lib to shared libs 75 | set_property(TARGET breezeenhanced_STATIC PROPERTY POSITION_INDEPENDENT_CODE ON) 76 | kconfig_add_kcfg_files(breezeenhanced_STATIC breezesettings.kcfgc) 77 | target_link_libraries(breezeenhanced_STATIC 78 | PUBLIC 79 | Qt6::Core 80 | Qt6::Gui 81 | Qt6::Widgets 82 | Qt6::DBus 83 | KDecoration3::KDecoration 84 | PRIVATE 85 | KF6::I18n 86 | KF6::WindowSystem 87 | KF6::KCMUtils 88 | ) 89 | 90 | ### build library 91 | add_library(breezeenhanced MODULE 92 | ${breezeenhanced_SRCS} 93 | ${breezeenhanced_config_PART_FORMS_HEADERS}) 94 | 95 | target_link_libraries(breezeenhanced 96 | PRIVATE 97 | breezeenhancedcommon6 98 | breezeenhanced_STATIC 99 | KF6::GuiAddons 100 | KF6::I18n 101 | KF6::WindowSystem 102 | KF6::KCMUtils) 103 | 104 | 105 | install(TARGETS breezeenhanced DESTINATION ${KDE_INSTALL_PLUGINDIR}/${KDECORATION_PLUGIN_DIR}) 106 | 107 | add_subdirectory(config) 108 | -------------------------------------------------------------------------------- /config/breezeitemmodel.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // itemmodel.h 3 | // ------------------- 4 | // 5 | // Copyright (c) 2009-2010 Hugo Pereira Da Costa 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including without limitation the 10 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | // sell copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | // IN THE SOFTWARE. 24 | ////////////////////////////////////////////////////////////////////////////// 25 | 26 | #pragma once 27 | 28 | #include 29 | 30 | namespace Breeze 31 | { 32 | 33 | //* Job model. Stores job information for display in lists 34 | class ItemModel : public QAbstractItemModel 35 | { 36 | 37 | public: 38 | 39 | //* constructor 40 | explicit ItemModel(QObject *parent = nullptr); 41 | 42 | //* destructor 43 | virtual ~ItemModel() 44 | {} 45 | 46 | //* return all indexes in model starting from parent [recursive] 47 | QModelIndexList indexes( int column = 0, const QModelIndex& parent = QModelIndex() ) const; 48 | 49 | //*@name sorting 50 | //@{ 51 | 52 | //* sort 53 | virtual void sort() 54 | { sort( sortColumn(), sortOrder() ); } 55 | 56 | //* sort 57 | void sort( int column, Qt::SortOrder order = Qt::AscendingOrder ) override; 58 | 59 | //* current sorting column 60 | const int& sortColumn() const 61 | { return m_sortColumn; } 62 | 63 | //* current sort order 64 | const Qt::SortOrder& sortOrder() const 65 | { return m_sortOrder; } 66 | 67 | //@} 68 | 69 | protected: 70 | 71 | //* this sort columns without calling the layout changed callbacks 72 | void privateSort() 73 | { privateSort( m_sortColumn, m_sortOrder ); } 74 | 75 | //* private sort, with no signals emitted 76 | virtual void privateSort( int column, Qt::SortOrder order ) = 0; 77 | 78 | //* used to sort items in list 79 | class SortFTor 80 | { 81 | 82 | public: 83 | 84 | //* constructor 85 | explicit SortFTor( const int& type, Qt::SortOrder order = Qt::AscendingOrder ): 86 | _type( type ), 87 | _order( order ) 88 | {} 89 | 90 | protected: 91 | 92 | //* column 93 | int _type; 94 | 95 | //* order 96 | Qt::SortOrder _order; 97 | 98 | }; 99 | 100 | private: 101 | 102 | //* sorting column 103 | int m_sortColumn = 0; 104 | 105 | //* sorting order 106 | Qt::SortOrder m_sortOrder = Qt::AscendingOrder; 107 | 108 | }; 109 | 110 | } 111 | 112 | -------------------------------------------------------------------------------- /config/breezeexceptionlistwidget.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // breezeexceptionlistwidget.h 3 | // ------------------- 4 | // 5 | // Copyright (c) 2009 Hugo Pereira Da Costa 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including without limitation the 10 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | // sell copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | // IN THE SOFTWARE. 24 | ////////////////////////////////////////////////////////////////////////////// 25 | 26 | #pragma once 27 | 28 | #include "breezeexceptionmodel.h" 29 | #include "ui_breezeexceptionlistwidget.h" 30 | 31 | //* QDialog used to commit selected files 32 | namespace Breeze 33 | { 34 | 35 | class ExceptionListWidget: public QWidget 36 | { 37 | 38 | //* Qt meta object 39 | Q_OBJECT 40 | 41 | public: 42 | 43 | //* constructor 44 | explicit ExceptionListWidget( QWidget* = nullptr ); 45 | 46 | //* set exceptions 47 | void setExceptions( const InternalSettingsList& ); 48 | 49 | //* get exceptions 50 | InternalSettingsList exceptions(); 51 | 52 | //* true if changed 53 | virtual bool isChanged() const 54 | { return m_changed; } 55 | 56 | Q_SIGNALS: 57 | 58 | //* emitted when changed 59 | void changed( bool ); 60 | 61 | protected: 62 | 63 | //* model 64 | const ExceptionModel& model() const 65 | { return m_model; } 66 | 67 | //* model 68 | ExceptionModel& model() 69 | { return m_model; } 70 | 71 | protected Q_SLOTS: 72 | 73 | //* update button states 74 | virtual void updateButtons(); 75 | 76 | //* add 77 | virtual void add(); 78 | 79 | //* edit 80 | virtual void edit(); 81 | 82 | //* remove 83 | virtual void remove(); 84 | 85 | //* toggle 86 | virtual void toggle( const QModelIndex& ); 87 | 88 | //* move up 89 | virtual void up(); 90 | 91 | //* move down 92 | virtual void down(); 93 | 94 | protected: 95 | 96 | //* resize columns 97 | void resizeColumns() const; 98 | 99 | //* check exception 100 | bool checkException( InternalSettingsPtr ); 101 | 102 | //* set changed state 103 | virtual void setChanged( bool value ) 104 | { 105 | m_changed = value; 106 | Q_EMIT changed( value ); 107 | } 108 | 109 | private: 110 | 111 | //* model 112 | ExceptionModel m_model; 113 | 114 | //* ui 115 | Ui_BreezeExceptionListWidget m_ui; 116 | 117 | //* changed state 118 | bool m_changed = false; 119 | 120 | }; 121 | 122 | } 123 | 124 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | V6.5 2 | --------- 3 | * Bumped the version to 6.5. 4 | * Added an option for round bottom corners with no borders. 5 | 6 | V6.4 7 | --------- 8 | * Bumped the version to 6.4 and imported some changes from Breeze 6.4.0. 9 | * Used `KDecoration3::snapToPixelGrid` is a few places. 10 | 11 | V6.3 12 | --------- 13 | * Bumped the version to 6.3 and imported some changes from Breeze 6.3.0. 14 | * Fixed a problem in a ui file. 15 | * Removed the dialog option because it never worked on Wayland, and, since KDecoration3, it doesn't work on X11 either. 16 | 17 | V6.2 18 | --------- 19 | * Bumped the version to 6.2 and imported some changes from Breeze 6.2.0. 20 | * Silenced a compilation warning. 21 | * Code cleanup. 22 | 23 | V6.1 24 | --------- 25 | * Bumped the version to 6.1 and imported some changes from Breeze 6.1.5. 26 | 27 | V6.0 28 | --------- 29 | * Bumped the version to 6.0 and imported some changes from Breeze 6.0.2. 30 | 31 | V5.27 32 | --------- 33 | * Bumped the version to 5.27 and imported useful changes from breeze-5.27.2. 34 | * Removed the option about drawing border on maximized and tiled windows (it was both ugly and confusing). 35 | * Removed the 1-pix empty gap below shaded windows. 36 | * Smaller shadow for inactive windows (without any shadow animation). 37 | * Removed the activation state animation. It was redundant and wasn't consistent with Qt's activation state (which Kvantum supports). 38 | 39 | V5.26 40 | --------- 41 | * Bumped the version to 5.26 without any change. 42 | 43 | V5.25 44 | --------- 45 | * Enabled the new decoration blurring of KWin (without "blur glitches"). 46 | 47 | V5.24 48 | --------- 49 | * Bumped the version to 5.24 and silenced compilation warnings. 50 | 51 | V5.23 52 | --------- 53 | * Bumped the version to 5.23 and imported some changes from breeze-5.23.1. 54 | * Imported https://invent.kde.org/plasma/breeze/-/commit/f2b81df6522b611bdf8e2fde7947bde82c35147e 55 | 56 | V5.22 57 | --------- 58 | * Bumped the version to 5.22 and imported useful changes from breeze-5.22.1. 59 | 60 | V5.21 61 | --------- 62 | * Bumped the version to 5.21 without any change (breeze-5.21.0 added shadow animation but I didn't import it to save resources). 63 | 64 | V5.20 65 | --------- 66 | * Bumped the version to 5.20 without any change (breeze-5.20.0 removed button animation settings but I kept them). 67 | 68 | V5.19 69 | --------- 70 | * Imported useful changes from Breeze 5.19.1. 71 | * Changed QVariantAnimation emuns to QAbstractAnimation ones. 72 | 73 | V5.18 74 | --------- 75 | * Imported some of the changes from Breeze 5.18.0. 76 | 77 | V5.17 78 | --------- 79 | * Imported some of the changes from Breeze 5.17.1. 80 | * Milder hover/press backgrounds for non-macOS buttons. 81 | 82 | V5.16 83 | --------- 84 | * Imported some of the changes from Breeze 5.16.0. 85 | * Added an option for extra horizontal title margin. 86 | 87 | V5.15 88 | --------- 89 | * Imported the changes from Breeze 5.15.0. 90 | * Added the checkbox "Only for dialogs" to the exception dialog to support separate settings for dialogs. 91 | 92 | V5.14 93 | --------- 94 | * Upgraded for Breeze 5.14 with its new shadows. 95 | * Applied the upstream patch https://phabricator.kde.org/D16596. 96 | * Replaced font boldness checkbox with weight combobox. 97 | * Also include borders in the opacity override. 98 | 99 | V5.13 100 | --------- 101 | * First version, made out of Breeze 5.13 and BreezeBlurred with new options. 102 | * Set the font style name for KDE to render it correctly. I don't know why KDE needs that while LXQt doesn't. 103 | * Added an option for not using macOS-like buttons. 104 | * Added flatness to the exception list. 105 | * Made inactive macOS-like buttons gray. 106 | * Added a setting for button spacing. 107 | * Added opacity override to the exception dialog. 108 | -------------------------------------------------------------------------------- /breezebutton.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Martin Gräßlin 3 | * Copyright 2014 Hugo Pereira Da Costa 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License or (at your option) version 3 or any later version 9 | * accepted by the membership of KDE e.V. (or its successor approved 10 | * by the membership of KDE e.V.), which shall act as a proxy 11 | * defined in Section 14 of version 3 of the license. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "breezedecoration.h" 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | class QVariantAnimation; 31 | 32 | namespace Breeze 33 | { 34 | 35 | class Button : public KDecoration3::DecorationButton 36 | { 37 | Q_OBJECT 38 | 39 | public: 40 | 41 | //* constructor 42 | explicit Button(QObject *parent, const QVariantList &args); 43 | 44 | //* destructor 45 | virtual ~Button() = default; 46 | 47 | //* button creation 48 | static Button *create(KDecoration3::DecorationButtonType type, KDecoration3::Decoration *decoration, QObject *parent); 49 | 50 | //* render 51 | void paint(QPainter *painter, const QRectF &repaintRegion) override; 52 | 53 | //* padding 54 | void setPadding(const QMargins &value) 55 | { 56 | m_padding = value; 57 | } 58 | 59 | //* left padding, for rendering 60 | void setLeftPadding(qreal value) 61 | { 62 | m_padding.setLeft(value); 63 | } 64 | 65 | //* right padding, for rendering 66 | void setRightPadding(qreal value) 67 | { 68 | m_padding.setRight(value); 69 | } 70 | 71 | //*@name active state change animation 72 | //@{ 73 | void setOpacity(qreal value) 74 | { 75 | if (m_opacity == value) return; 76 | m_opacity = value; 77 | update(); 78 | } 79 | 80 | qreal opacity() const 81 | { 82 | return m_opacity; 83 | } 84 | 85 | //@} 86 | 87 | void setPreferredSize(const QSizeF &size) 88 | { 89 | m_preferredSize = size; 90 | } 91 | 92 | QSizeF preferredSize() const 93 | { 94 | return m_preferredSize; 95 | } 96 | 97 | private Q_SLOTS: 98 | 99 | //* apply configuration changes 100 | void reconfigure(); 101 | 102 | //* animation state 103 | void updateAnimationState(bool); 104 | 105 | private: 106 | 107 | //* private constructor 108 | explicit Button(KDecoration3::DecorationButtonType type, Decoration *decoration, QObject *parent = nullptr); 109 | 110 | //* draw button icon 111 | void drawIcon(QPainter *) const; 112 | 113 | //*@name colors 114 | //@{ 115 | QColor foregroundColor(const QColor& inactiveCol) const; 116 | QColor backgroundColor() const; 117 | //@} 118 | 119 | //* active state change animation 120 | QVariantAnimation *m_animation; 121 | 122 | //* padding (for rendering) 123 | QMargins m_padding; 124 | 125 | //* implicit size 126 | QSizeF m_preferredSize; 127 | 128 | //* active state change opacity 129 | qreal m_opacity = 0; 130 | }; 131 | 132 | } // namespace 133 | 134 | -------------------------------------------------------------------------------- /config/breezeexceptionmodel.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // breezeexceptionmodel.cpp 3 | // ------------------- 4 | // 5 | // Copyright (c) 2009 Hugo Pereira Da Costa 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including without limitation the 10 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | // sell copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | // IN THE SOFTWARE. 24 | ////////////////////////////////////////////////////////////////////////////// 25 | 26 | #include "breezeexceptionmodel.h" 27 | 28 | #include 29 | 30 | namespace Breeze 31 | { 32 | 33 | //_______________________________________________ 34 | const QString ExceptionModel::m_columnTitles[ ExceptionModel::nColumns ] = 35 | { 36 | QStringLiteral( "" ), 37 | i18n("Exception Type"), 38 | i18n("Regular Expression") 39 | }; 40 | 41 | //__________________________________________________________________ 42 | QVariant ExceptionModel::data( const QModelIndex& index, int role ) const 43 | { 44 | 45 | // check index, role and column 46 | if( !index.isValid() ) return QVariant(); 47 | 48 | // retrieve associated file info 49 | const InternalSettingsPtr& configuration( get(index) ); 50 | 51 | // return text associated to file and column 52 | if( role == Qt::DisplayRole ) 53 | { 54 | 55 | switch( index.column() ) 56 | { 57 | case ColumnType: 58 | { 59 | switch( configuration->exceptionType() ) 60 | { 61 | 62 | case InternalSettings::ExceptionWindowTitle: 63 | return i18n( "Window Title" ); 64 | 65 | default: 66 | case InternalSettings::ExceptionWindowClassName: 67 | return i18n( "Window Class Name" ); 68 | } 69 | 70 | } 71 | 72 | case ColumnRegExp: return configuration->exceptionPattern(); 73 | default: return QVariant(); 74 | break; 75 | } 76 | 77 | } else if( role == Qt::CheckStateRole && index.column() == ColumnEnabled ) { 78 | 79 | return configuration->enabled() ? Qt::Checked : Qt::Unchecked; 80 | 81 | } else if( role == Qt::ToolTipRole && index.column() == ColumnEnabled ) { 82 | 83 | return i18n("Enable/disable this exception"); 84 | 85 | } 86 | 87 | 88 | return QVariant(); 89 | } 90 | 91 | //__________________________________________________________________ 92 | QVariant ExceptionModel::headerData(int section, Qt::Orientation orientation, int role) const 93 | { 94 | 95 | if( 96 | orientation == Qt::Horizontal && 97 | role == Qt::DisplayRole && 98 | section >= 0 && 99 | section < nColumns ) 100 | { return m_columnTitles[section]; } 101 | 102 | // return empty 103 | return QVariant(); 104 | 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /breezesettingsprovider.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Hugo Pereira Da Costa 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "breezesettingsprovider.h" 22 | 23 | #include "breezeexceptionlist.h" 24 | 25 | //#include 26 | 27 | #include 28 | #include 29 | 30 | namespace Breeze 31 | { 32 | 33 | SettingsProvider *SettingsProvider::s_self = nullptr; 34 | 35 | //__________________________________________________________________ 36 | SettingsProvider::SettingsProvider(): 37 | m_config( KSharedConfig::openConfig( QStringLiteral("breezerc") ) ) 38 | { reconfigure(); } 39 | 40 | //__________________________________________________________________ 41 | SettingsProvider::~SettingsProvider() 42 | { s_self = nullptr; } 43 | 44 | //__________________________________________________________________ 45 | SettingsProvider *SettingsProvider::self() 46 | { 47 | // TODO: this is not thread safe! 48 | if (!s_self) 49 | { s_self = new SettingsProvider(); } 50 | 51 | return s_self; 52 | } 53 | 54 | //__________________________________________________________________ 55 | void SettingsProvider::reconfigure() 56 | { 57 | if( !m_defaultSettings ) 58 | { 59 | m_defaultSettings = InternalSettingsPtr(new InternalSettings()); 60 | m_defaultSettings->setCurrentGroup( QStringLiteral("Windeco") ); 61 | } 62 | 63 | m_defaultSettings->load(); 64 | 65 | ExceptionList exceptions; 66 | exceptions.readConfig( m_config ); 67 | m_exceptions = exceptions.get(); 68 | 69 | } 70 | 71 | //__________________________________________________________________ 72 | InternalSettingsPtr SettingsProvider::internalSettings(Decoration *decoration) const 73 | { 74 | 75 | QString windowTitle; 76 | QString windowClass; 77 | 78 | // get the decorated window 79 | const auto w = decoration->window(); 80 | 81 | for (auto internalSettings : std::as_const(m_exceptions)) 82 | { 83 | // discard disabled exceptions 84 | if (!internalSettings->enabled()) continue; 85 | 86 | // discard exceptions with empty exception pattern 87 | if (internalSettings->exceptionPattern().isEmpty()) continue; 88 | 89 | /*if (internalSettings->isDialog()) 90 | { 91 | KWindowInfo info(w->windowId(), NET::WMWindowType); 92 | if (info.valid() 93 | && info.windowType(NET::NormalMask | NET::DialogMask) != NET::Dialog) { 94 | continue; 95 | } 96 | }*/ 97 | 98 | /* 99 | decide which value is to be compared 100 | to the regular expression, based on exception type 101 | */ 102 | QString value; 103 | switch (internalSettings->exceptionType()) 104 | { 105 | case InternalSettings::ExceptionWindowTitle: 106 | { 107 | value = windowTitle.isEmpty() ? (windowTitle = w->caption()):windowTitle; 108 | break; 109 | } 110 | 111 | default: 112 | case InternalSettings::ExceptionWindowClassName: { 113 | value = windowClass.isEmpty() ? (windowClass = w->windowClass()) : windowClass; 114 | break; 115 | } 116 | 117 | } 118 | 119 | // check matching 120 | QRegularExpression rx( internalSettings->exceptionPattern() ); 121 | if (rx.match(value).hasMatch()) 122 | { 123 | return internalSettings; 124 | } 125 | } 126 | 127 | return m_defaultSettings; 128 | 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /breezesettingsdata.kcfg: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 255 13 | 25 14 | 255 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ShadowLarge 27 | 28 | 29 | 30 | 0, 0, 0 31 | 32 | 33 | 34 | 35 | false 36 | 37 | 38 | 39 | true 40 | 41 | 42 | 43 | 44 | 45 | 46 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | BorderNone 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | AlignCenterFullWidth 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | ButtonDefault 86 | 87 | 88 | 89 | 6 90 | 91 | 92 | 93 | 0 94 | 95 | 96 | 97 | 98 | false 99 | 100 | 101 | 102 | true 103 | 104 | 105 | 106 | 100 107 | 108 | 109 | 110 | 111 | true 112 | 113 | 114 | 115 | 20 116 | 117 | 118 | 119 | 120 | 121 | 122 | true 123 | 124 | 125 | 126 | 150 127 | 128 | 129 | 130 | 131 | false 132 | 133 | 134 | 135 | 136 | false 137 | 138 | 139 | 140 | -1 141 | 142 | 143 | 144 | 145 | false 146 | 147 | 148 | 149 | 150 | false 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | ExceptionWindowClassName 160 | 161 | 162 | 163 | 164 | 165 | true 166 | 167 | 168 | 169 | 0 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /breezeexceptionlist.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // breezeexceptionlist.cpp 3 | // window decoration exceptions 4 | // ------------------- 5 | // 6 | // Copyright (c) 2009 Hugo Pereira Da Costa 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to 10 | // deal in the Software without restriction, including without limitation the 11 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 12 | // sell copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 24 | // IN THE SOFTWARE. 25 | ////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include "breezeexceptionlist.h" 28 | 29 | 30 | namespace Breeze 31 | { 32 | 33 | //______________________________________________________________ 34 | void ExceptionList::readConfig(KSharedConfig::Ptr config) 35 | { 36 | _exceptions.clear(); 37 | 38 | QString groupName; 39 | for (int index = 0; config->hasGroup(groupName = exceptionGroupName(index)); ++index) 40 | { 41 | 42 | // create exception 43 | InternalSettings exception; 44 | 45 | // reset group 46 | readConfig(&exception, config.data(), groupName); 47 | 48 | // create new configuration 49 | InternalSettingsPtr configuration(new InternalSettings()); 50 | configuration.data()->load(); 51 | 52 | // apply changes from exception 53 | configuration->setEnabled(exception.enabled()); 54 | configuration->setExceptionType(exception.exceptionType()); 55 | configuration->setExceptionPattern(exception.exceptionPattern()); 56 | configuration->setMask(exception.mask()); 57 | 58 | // propagate all features found in mask to the output configuration 59 | if (exception.mask() & BorderSize) 60 | configuration->setBorderSize(exception.borderSize()); 61 | configuration->setHideTitleBar(exception.hideTitleBar()); 62 | configuration->setOpaqueTitleBar(exception.opaqueTitleBar()); 63 | configuration->setOpacityOverride(exception.opacityOverride()); 64 | configuration->setFlatTitleBar(exception.flatTitleBar()); 65 | configuration->setIsDialog(exception.isDialog()); 66 | 67 | // append to exceptions 68 | _exceptions.append(configuration); 69 | 70 | } 71 | } 72 | 73 | //______________________________________________________________ 74 | void ExceptionList::writeConfig(KSharedConfig::Ptr config) 75 | { 76 | // remove all existing exceptions 77 | QString groupName; 78 | for (int index = 0; config->hasGroup(groupName = exceptionGroupName(index)); ++index) 79 | { 80 | config->deleteGroup(groupName); 81 | } 82 | 83 | // rewrite current exceptions 84 | int index = 0; 85 | for (const InternalSettingsPtr &exception : std::as_const(_exceptions)) 86 | { 87 | 88 | writeConfig(exception.data(), config.data(), exceptionGroupName(index )); 89 | ++index; 90 | 91 | } 92 | } 93 | 94 | //_______________________________________________________________________ 95 | QString ExceptionList::exceptionGroupName(int index) 96 | { 97 | return QStringLiteral("Windeco Exception %1").arg(index); 98 | } 99 | 100 | //______________________________________________________________ 101 | void ExceptionList::writeConfig(KCoreConfigSkeleton* skeleton, KConfig* config, const QString& groupName) 102 | { 103 | // list of items to be written 104 | const QStringList keys = {QStringLiteral("Enabled"), 105 | QStringLiteral("ExceptionPattern"), 106 | QStringLiteral("ExceptionType"), 107 | QStringLiteral("HideTitleBar"), 108 | QStringLiteral("IsDialog"), 109 | QStringLiteral("OpaqueTitleBar"), 110 | QStringLiteral("OpacityOverride"), 111 | QStringLiteral("FlatTitleBar"), 112 | QStringLiteral("Mask"), 113 | QStringLiteral("BorderSize")}; 114 | 115 | // write all items 116 | for (auto key : keys) 117 | { 118 | KConfigSkeletonItem* item(skeleton->findItem(key)); 119 | if( !item ) continue; 120 | 121 | if(!groupName.isEmpty()) item->setGroup( groupName); 122 | KConfigGroup configGroup(config, item->group()); 123 | configGroup.writeEntry(item->key(), item->property()); 124 | 125 | } 126 | } 127 | 128 | //______________________________________________________________ 129 | void ExceptionList::readConfig(KCoreConfigSkeleton* skeleton, KConfig* config, const QString& groupName) 130 | { 131 | const auto items = skeleton->items(); 132 | for (KConfigSkeletonItem *item : items) 133 | { 134 | if(!groupName.isEmpty() ) 135 | item->setGroup(groupName); 136 | item->readConfig( config ); 137 | } 138 | 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /breezedecoration.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Martin Gräßlin 3 | * Copyright 2014 Hugo Pereira Da Costa 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License or (at your option) version 3 or any later version 9 | * accepted by the membership of KDE e.V. (or its successor approved 10 | * by the membership of KDE e.V.), which shall act as a proxy 11 | * defined in Section 14 of version 3 of the license. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "breeze.h" 25 | #include "breezesettings.h" 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | namespace KDecoration3 36 | { 37 | class DecorationButton; 38 | class DecorationButtonGroup; 39 | } 40 | 41 | namespace Breeze 42 | { 43 | class Decoration : public KDecoration3::Decoration 44 | { 45 | Q_OBJECT 46 | 47 | public: 48 | 49 | //* constructor 50 | explicit Decoration(QObject *parent = nullptr, const QVariantList &args = QVariantList()); 51 | 52 | //* destructor 53 | ~Decoration() override; 54 | 55 | //* paint 56 | void paint(QPainter *painter, const QRectF &repaintRegion) override; 57 | 58 | //* internal settings 59 | InternalSettingsPtr internalSettings() const 60 | { return m_internalSettings; } 61 | 62 | //* caption height 63 | qreal captionHeight() const; 64 | 65 | //* button size 66 | int buttonSize() const; 67 | 68 | //*@name colors 69 | //@{ 70 | QColor titleBarColor() const; 71 | QColor fontColor() const; 72 | //@} 73 | 74 | //*@name maximization modes 75 | //@{ 76 | inline bool isMaximized() const; 77 | inline bool isMaximizedHorizontally() const; 78 | inline bool isMaximizedVertically() const; 79 | 80 | inline bool isLeftEdge() const; 81 | inline bool isRightEdge() const; 82 | inline bool isTopEdge() const; 83 | inline bool isBottomEdge() const; 84 | 85 | inline bool hideTitleBar() const; 86 | //@} 87 | 88 | public Q_SLOTS: 89 | bool init() override; 90 | 91 | private Q_SLOTS: 92 | void reconfigure(); 93 | void recalculateBorders(); 94 | void resetBlurRegion(); 95 | void updateButtonsGeometry(); 96 | void updateButtonsGeometryDelayed(); 97 | void updateTitleBar(); 98 | void updateActiveState(); 99 | void updateScale(); 100 | 101 | private: 102 | 103 | //* return the rect in which caption will be drawn 104 | QPair captionRect() const; 105 | 106 | void createButtons(); 107 | void paintTitleBar(QPainter *painter, const QRectF &repaintRegion); 108 | void updateShadow(); 109 | 110 | void setScaledCornerRadius(); 111 | 112 | //*@name border size 113 | //@{ 114 | qreal borderSize(bool bottom, qreal scale) const; 115 | inline bool hasBorders() const; 116 | inline bool hasNoBorders() const; 117 | inline bool hasNoSideBorders() const; 118 | QMarginsF bordersFor(qreal scale) const; 119 | //@} 120 | 121 | //*@name color customization 122 | //@{ 123 | inline bool opaqueTitleBar() const; 124 | inline bool flatTitleBar() const; 125 | inline int titleBarAlpha() const; 126 | //@} 127 | 128 | InternalSettingsPtr m_internalSettings; 129 | KDecoration3::DecorationButtonGroup *m_leftButtons = nullptr; 130 | KDecoration3::DecorationButtonGroup *m_rightButtons = nullptr; 131 | 132 | //*frame corner radius, scaled according to DPI 133 | qreal m_scaledCornerRadius = 3; 134 | }; 135 | 136 | bool Decoration::hasBorders() const 137 | { 138 | if (m_internalSettings && m_internalSettings->mask() & BorderSize) 139 | return m_internalSettings->borderSize() > InternalSettings::BorderNoSides; 140 | else 141 | return settings()->borderSize() > KDecoration3::BorderSize::NoSides; 142 | } 143 | 144 | bool Decoration::hasNoBorders() const 145 | { 146 | if (m_internalSettings && m_internalSettings->mask() & BorderSize) 147 | return m_internalSettings->borderSize() == InternalSettings::BorderNone; 148 | else 149 | return settings()->borderSize() == KDecoration3::BorderSize::None; 150 | } 151 | 152 | bool Decoration::hasNoSideBorders() const 153 | { 154 | if (m_internalSettings && m_internalSettings->mask() & BorderSize) 155 | return m_internalSettings->borderSize() == InternalSettings::BorderNoSides; 156 | else 157 | return settings()->borderSize() == KDecoration3::BorderSize::NoSides; 158 | } 159 | 160 | bool Decoration::isMaximized() const 161 | { 162 | return window()->isMaximized(); 163 | } 164 | 165 | bool Decoration::isMaximizedHorizontally() const 166 | { 167 | return window()->isMaximizedHorizontally(); 168 | } 169 | 170 | bool Decoration::isMaximizedVertically() const 171 | { 172 | return window()->isMaximizedVertically(); 173 | } 174 | 175 | bool Decoration::isLeftEdge() const 176 | { 177 | const auto w = window(); 178 | return (w->isMaximizedHorizontally() || w->adjacentScreenEdges().testFlag(Qt::LeftEdge)); 179 | } 180 | 181 | bool Decoration::isRightEdge() const 182 | { 183 | const auto w = window(); 184 | return (w->isMaximizedHorizontally() || w->adjacentScreenEdges().testFlag(Qt::RightEdge)); 185 | } 186 | 187 | bool Decoration::isTopEdge() const 188 | { 189 | const auto w = window(); 190 | return (w->isMaximizedVertically() || w->adjacentScreenEdges().testFlag(Qt::TopEdge)); 191 | } 192 | 193 | bool Decoration::isBottomEdge() const 194 | { 195 | const auto w = window(); 196 | return (w->isMaximizedVertically() || w->adjacentScreenEdges().testFlag(Qt::BottomEdge)); 197 | } 198 | 199 | bool Decoration::hideTitleBar() const 200 | { return m_internalSettings->hideTitleBar() && !window()->isShaded(); } 201 | 202 | bool Decoration::opaqueTitleBar() const 203 | { return m_internalSettings->opaqueTitleBar(); } 204 | 205 | bool Decoration::flatTitleBar() const 206 | { return m_internalSettings->flatTitleBar(); } 207 | 208 | int Decoration::titleBarAlpha() const 209 | { 210 | if (m_internalSettings->opaqueTitleBar()) 211 | return 255; 212 | int a = m_internalSettings->opacityOverride() > -1 ? m_internalSettings->opacityOverride() 213 | : m_internalSettings->backgroundOpacity(); 214 | a = qBound(0, a, 100); 215 | return qRound(static_cast(a) * static_cast(2.55)); 216 | } 217 | 218 | } 219 | 220 | -------------------------------------------------------------------------------- /config/breezeexceptiondialog.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // breezeexceptiondialog.cpp 3 | // ------------------- 4 | // 5 | // Copyright (c) 2009 Hugo Pereira Da Costa 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including without limitation the 10 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | // sell copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | // IN THE SOFTWARE. 24 | ////////////////////////////////////////////////////////////////////////////// 25 | 26 | #include "breezeexceptiondialog.h" 27 | #include "breezedetectwidget.h" 28 | 29 | namespace Breeze 30 | { 31 | 32 | //___________________________________________ 33 | ExceptionDialog::ExceptionDialog( QWidget* parent ): 34 | QDialog( parent ) 35 | { 36 | 37 | m_ui.setupUi( this ); 38 | 39 | // can't work on Wayland and, since KDecoration3, doesn't work on X11 either 40 | m_ui.isDialog->setVisible(false); 41 | 42 | connect( m_ui.buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, this, &QWidget::close); 43 | 44 | // store checkboxes from ui into list 45 | m_checkboxes.insert( BorderSize, m_ui.borderSizeCheckBox ); 46 | 47 | // detect window properties 48 | connect(m_ui.detectDialogButton, &QAbstractButton::clicked, this, &ExceptionDialog::selectWindowProperties); 49 | 50 | // connections 51 | connect( m_ui.exceptionType, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) ); 52 | connect( m_ui.exceptionEditor, &QLineEdit::textChanged, this, &ExceptionDialog::updateChanged ); 53 | connect( m_ui.borderSizeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) ); 54 | 55 | for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter ) 56 | { connect( iter.value(), &QAbstractButton::clicked, this, &ExceptionDialog::updateChanged ); } 57 | 58 | connect( m_ui.hideTitleBar, &QAbstractButton::clicked, this, &ExceptionDialog::updateChanged ); 59 | connect( m_ui.opaqueTitleBar, SIGNAL(clicked()), SLOT(updateChanged()) ); 60 | m_ui.opacityOverrideLabelSpinBox->setSpecialValueText(tr("None")); 61 | connect( m_ui.opacityOverrideLabelSpinBox, QOverload::of(&QSpinBox::valueChanged), [this](int /*i*/){updateChanged();} ); 62 | connect( m_ui.flatTitleBar, SIGNAL(clicked()), SLOT(updateChanged()) ); 63 | //connect( m_ui.isDialog, SIGNAL(clicked()), SLOT(updateChanged()) ); 64 | } 65 | 66 | //___________________________________________ 67 | void ExceptionDialog::setException( InternalSettingsPtr exception ) 68 | { 69 | 70 | // store exception internally 71 | m_exception = exception; 72 | 73 | // type 74 | m_ui.exceptionType->setCurrentIndex(m_exception->exceptionType() ); 75 | m_ui.exceptionEditor->setText( m_exception->exceptionPattern() ); 76 | m_ui.borderSizeComboBox->setCurrentIndex( m_exception->borderSize() ); 77 | m_ui.hideTitleBar->setChecked( m_exception->hideTitleBar() ); 78 | m_ui.opaqueTitleBar->setChecked( m_exception->opaqueTitleBar() ); 79 | m_ui.opacityOverrideLabelSpinBox->setValue( m_exception->opacityOverride() ); 80 | m_ui.flatTitleBar->setChecked( m_exception->flatTitleBar() ); 81 | //m_ui.isDialog->setChecked( m_exception->isDialog() ); 82 | 83 | // mask 84 | for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter ) 85 | { iter.value()->setChecked( m_exception->mask() & iter.key() ); } 86 | 87 | setChanged( false ); 88 | 89 | } 90 | 91 | //___________________________________________ 92 | void ExceptionDialog::save() 93 | { 94 | m_exception->setExceptionType( m_ui.exceptionType->currentIndex() ); 95 | m_exception->setExceptionPattern( m_ui.exceptionEditor->text() ); 96 | m_exception->setBorderSize( m_ui.borderSizeComboBox->currentIndex() ); 97 | m_exception->setHideTitleBar( m_ui.hideTitleBar->isChecked() ); 98 | m_exception->setOpaqueTitleBar( m_ui.opaqueTitleBar->isChecked() ); 99 | m_exception->setOpacityOverride( m_ui.opacityOverrideLabelSpinBox->value() ); 100 | m_exception->setFlatTitleBar( m_ui.flatTitleBar->isChecked() ); 101 | //m_exception->setIsDialog( m_ui.isDialog->isChecked() ); 102 | 103 | // mask 104 | unsigned int mask = None; 105 | for (CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter) { 106 | if (iter.value()->isChecked()) 107 | mask |= iter.key(); 108 | } 109 | 110 | m_exception->setMask( mask ); 111 | 112 | setChanged( false ); 113 | 114 | } 115 | 116 | //___________________________________________ 117 | void ExceptionDialog::updateChanged() 118 | { 119 | bool modified( false ); 120 | if (m_exception->exceptionType() != m_ui.exceptionType->currentIndex()) 121 | modified = true; 122 | else if (m_exception->exceptionPattern() != m_ui.exceptionEditor->text()) 123 | modified = true; 124 | else if (m_exception->borderSize() != m_ui.borderSizeComboBox->currentIndex()) 125 | modified = true; 126 | else if (m_exception->hideTitleBar() != m_ui.hideTitleBar->isChecked()) 127 | modified = true; 128 | else if (m_exception->opaqueTitleBar() != m_ui.opaqueTitleBar->isChecked()) 129 | modified = true; 130 | else if (m_exception->opacityOverride() != m_ui.opacityOverrideLabelSpinBox->value()) 131 | modified = true; 132 | else if (m_exception->flatTitleBar() != m_ui.flatTitleBar->isChecked()) 133 | modified = true; 134 | //else if (m_exception->isDialog() != m_ui.isDialog->isChecked()) 135 | // modified = true; 136 | else 137 | { 138 | // check mask 139 | for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter ) 140 | { 141 | if( iter.value()->isChecked() != (bool)( m_exception->mask() & iter.key() ) ) 142 | { 143 | modified = true; 144 | break; 145 | } 146 | } 147 | } 148 | 149 | setChanged( modified ); 150 | 151 | } 152 | 153 | //___________________________________________ 154 | void ExceptionDialog::selectWindowProperties() 155 | { 156 | // create widget 157 | if(!m_detectDialog) 158 | { 159 | m_detectDialog = new DetectDialog(this); 160 | connect(m_detectDialog, &DetectDialog::detectionDone, this, &ExceptionDialog::readWindowProperties); 161 | } 162 | 163 | m_detectDialog->detect(); 164 | } 165 | 166 | //___________________________________________ 167 | void ExceptionDialog::readWindowProperties(bool valid) 168 | { 169 | Q_CHECK_PTR(m_detectDialog); 170 | if (valid) { 171 | // window info 172 | const QVariantMap properties = m_detectDialog->properties(); 173 | 174 | switch (m_ui.exceptionType->currentIndex()) { 175 | default: 176 | case InternalSettings::ExceptionWindowClassName: 177 | m_ui.exceptionEditor->setText(properties.value(QStringLiteral("resourceClass")).toString()); 178 | break; 179 | 180 | case InternalSettings::ExceptionWindowTitle: 181 | m_ui.exceptionEditor->setText(properties.value(QStringLiteral("caption")).toString()); 182 | break; 183 | } 184 | } 185 | 186 | delete m_detectDialog; 187 | m_detectDialog = nullptr; 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /config/ui/breezeexceptiondialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | BreezeExceptionDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 362 10 | 321 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | Window Identification 21 | 22 | 23 | 24 | 25 | 26 | &Matching window property: 27 | 28 | 29 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 30 | 31 | 32 | exceptionType 33 | 34 | 35 | 36 | 37 | 38 | 39 | Regular expression &to match: 40 | 41 | 42 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 43 | 44 | 45 | exceptionEditor 46 | 47 | 48 | 49 | 50 | 51 | 52 | Detect Window Properties… 53 | 54 | 55 | 56 | 57 | 58 | 59 | true 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | Window Class Name 68 | 69 | 70 | 71 | 72 | Window Title 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | Decoration Options 84 | 85 | 86 | 87 | 88 | 89 | Border size: 90 | 91 | 92 | 93 | 94 | 95 | 96 | false 97 | 98 | 99 | 100 | No Border 101 | 102 | 103 | 104 | 105 | No Side Borders 106 | 107 | 108 | 109 | 110 | Tiny 111 | 112 | 113 | 114 | 115 | Normal 116 | 117 | 118 | 119 | 120 | Large 121 | 122 | 123 | 124 | 125 | Very Large 126 | 127 | 128 | 129 | 130 | Huge 131 | 132 | 133 | 134 | 135 | Very Huge 136 | 137 | 138 | 139 | 140 | Oversized 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | Only for dialogs 149 | 150 | 151 | 152 | 153 | 154 | 155 | Qt::Vertical 156 | 157 | 158 | 159 | 20 160 | 40 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | Hide window title bar 169 | 170 | 171 | 172 | 173 | 174 | 175 | Opaque title bar 176 | 177 | 178 | 179 | 180 | 181 | 182 | Flat title bar 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | Qt::Horizontal 192 | 193 | 194 | QSizePolicy::Fixed 195 | 196 | 197 | 198 | 16 199 | 5 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | Override opacity: 208 | 209 | 210 | 211 | 212 | 213 | 214 | % 215 | 216 | 217 | -1 218 | 219 | 220 | 100 221 | 222 | 223 | -1 224 | 225 | 226 | 227 | 228 | 229 | 230 | Qt::Horizontal 231 | 232 | 233 | 234 | 40 235 | 20 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | Qt::Horizontal 249 | 250 | 251 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | buttonBox 261 | accepted() 262 | BreezeExceptionDialog 263 | accept() 264 | 265 | 266 | 252 267 | 342 268 | 269 | 270 | 157 271 | 274 272 | 273 | 274 | 275 | 276 | buttonBox 277 | rejected() 278 | BreezeExceptionDialog 279 | reject() 280 | 281 | 282 | 320 283 | 342 284 | 285 | 286 | 286 287 | 274 288 | 289 | 290 | 291 | 292 | borderSizeCheckBox 293 | toggled(bool) 294 | borderSizeComboBox 295 | setEnabled(bool) 296 | 297 | 298 | 125 299 | 162 300 | 301 | 302 | 316 303 | 163 304 | 305 | 306 | 307 | 308 | opaqueTitleBar 309 | toggled(bool) 310 | opacityOverrideLabel 311 | setDisabled(bool) 312 | 313 | 314 | 104 315 | 202 316 | 317 | 318 | 82 319 | 229 320 | 321 | 322 | 323 | 324 | opaqueTitleBar 325 | toggled(bool) 326 | opacityOverrideLabelSpinBox 327 | setDisabled(bool) 328 | 329 | 330 | 104 331 | 202 332 | 333 | 334 | 166 335 | 229 336 | 337 | 338 | 339 | 340 | 341 | -------------------------------------------------------------------------------- /libbreezecommon/breezeboxshadowrenderer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Vlad Zagorodniy 3 | * 4 | * The box blur implementation is based on AlphaBoxBlur from Firefox. 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | // own 22 | #include "breezeboxshadowrenderer.h" 23 | 24 | // Qt 25 | #include 26 | #include 27 | 28 | namespace Breeze 29 | { 30 | static inline int calculateBlurRadius(qreal stdDev) 31 | { 32 | // See https://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement 33 | const qreal gaussianScaleFactor = (3.0 * qSqrt(2.0 * M_PI) / 4.0) * 1.5; 34 | return qMax(2, qFloor(stdDev * gaussianScaleFactor + 0.5)); 35 | } 36 | 37 | static inline qreal calculateBlurStdDev(int radius) 38 | { 39 | // See https://www.w3.org/TR/css-backgrounds-3/#shadow-blur 40 | return radius * 0.5; 41 | } 42 | 43 | static inline QSize calculateBlurExtent(int radius) 44 | { 45 | const int blurRadius = calculateBlurRadius(calculateBlurStdDev(radius)); 46 | return QSize(blurRadius, blurRadius); 47 | } 48 | 49 | struct BoxLobes { 50 | int left; ///< how many pixels sample to the left 51 | int right; ///< how many pixels sample to the right 52 | }; 53 | 54 | /** 55 | * Compute box filter parameters. 56 | * 57 | * @param radius The blur radius. 58 | * @returns Parameters for three box filters. 59 | **/ 60 | static QVector computeLobes(int radius) 61 | { 62 | const int blurRadius = calculateBlurRadius(calculateBlurStdDev(radius)); 63 | const int z = blurRadius / 3; 64 | 65 | int major; 66 | int minor; 67 | int final; 68 | 69 | switch (blurRadius % 3) { 70 | case 0: 71 | major = z; 72 | minor = z; 73 | final = z; 74 | break; 75 | 76 | case 1: 77 | major = z + 1; 78 | minor = z; 79 | final = z; 80 | break; 81 | 82 | case 2: 83 | major = z + 1; 84 | minor = z; 85 | final = z + 1; 86 | break; 87 | 88 | default: 89 | Q_UNREACHABLE(); 90 | break; 91 | } 92 | 93 | Q_ASSERT(major + minor + final == blurRadius); 94 | 95 | return {{major, minor}, {minor, major}, {final, final}}; 96 | } 97 | 98 | /** 99 | * Process a row with a box filter. 100 | * 101 | * @param src The start of the row. 102 | * @param dst The destination. 103 | * @param width The width of the row, in pixels. 104 | * @param horizontalStride The number of bytes from one alpha value to the 105 | * next alpha value. 106 | * @param verticalStride The number of bytes from one row to the next row. 107 | * @param lobes Params of the box filter. 108 | * @param transposeInput Whether the input is transposed. 109 | * @param transposeOutput Whether the output should be transposed. 110 | **/ 111 | static inline void boxBlurRowAlpha(const uint8_t *src, 112 | uint8_t *dst, 113 | int width, 114 | int horizontalStride, 115 | int verticalStride, 116 | const BoxLobes &lobes, 117 | bool transposeInput, 118 | bool transposeOutput) 119 | { 120 | const int inputStep = transposeInput ? verticalStride : horizontalStride; 121 | const int outputStep = transposeOutput ? verticalStride : horizontalStride; 122 | 123 | const int boxSize = lobes.left + 1 + lobes.right; 124 | const int reciprocal = (1 << 24) / boxSize; 125 | 126 | uint32_t alphaSum = (boxSize + 1) / 2; 127 | 128 | const uint8_t *left = src; 129 | const uint8_t *right = src; 130 | uint8_t *out = dst; 131 | 132 | const uint8_t firstValue = src[0]; 133 | const uint8_t lastValue = src[(width - 1) * inputStep]; 134 | 135 | alphaSum += firstValue * lobes.left; 136 | 137 | const uint8_t *initEnd = src + (boxSize - lobes.left) * inputStep; 138 | while (right < initEnd) { 139 | alphaSum += *right; 140 | right += inputStep; 141 | } 142 | 143 | const uint8_t *leftEnd = src + boxSize * inputStep; 144 | while (right < leftEnd) { 145 | *out = (alphaSum * reciprocal) >> 24; 146 | alphaSum += *right - firstValue; 147 | right += inputStep; 148 | out += outputStep; 149 | } 150 | 151 | const uint8_t *centerEnd = src + width * inputStep; 152 | while (right < centerEnd) { 153 | *out = (alphaSum * reciprocal) >> 24; 154 | alphaSum += *right - *left; 155 | left += inputStep; 156 | right += inputStep; 157 | out += outputStep; 158 | } 159 | 160 | const uint8_t *rightEnd = dst + width * outputStep; 161 | while (out < rightEnd) { 162 | *out = (alphaSum * reciprocal) >> 24; 163 | alphaSum += lastValue - *left; 164 | left += inputStep; 165 | out += outputStep; 166 | } 167 | } 168 | 169 | /** 170 | * Blur the alpha channel of a given image. 171 | * 172 | * @param image The input image. 173 | * @param radius The blur radius. 174 | * @param rect Specifies what part of the image to blur. If nothing is provided, then 175 | * the whole alpha channel of the input image will be blurred. 176 | **/ 177 | static inline void boxBlurAlpha(QImage &image, int radius, const QRect &rect = {}) 178 | { 179 | if (radius < 2) { 180 | return; 181 | } 182 | 183 | const QVector lobes = computeLobes(radius); 184 | 185 | const QRect blurRect = rect.isNull() ? image.rect() : rect; 186 | 187 | const int alphaOffset = QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3; 188 | const int width = blurRect.width(); 189 | const int height = blurRect.height(); 190 | const int rowStride = image.bytesPerLine(); 191 | const int pixelStride = image.depth() >> 3; 192 | 193 | const int bufferStride = qMax(width, height) * pixelStride; 194 | QScopedPointer> buf(new uint8_t[2 * bufferStride]); 195 | uint8_t *buf1 = buf.data(); 196 | uint8_t *buf2 = buf1 + bufferStride; 197 | 198 | // Blur the image in horizontal direction. 199 | for (int i = 0; i < height; ++i) { 200 | uint8_t *row = image.scanLine(blurRect.y() + i) + blurRect.x() * pixelStride + alphaOffset; 201 | boxBlurRowAlpha(row, buf1, width, pixelStride, rowStride, lobes[0], false, false); 202 | boxBlurRowAlpha(buf1, buf2, width, pixelStride, rowStride, lobes[1], false, false); 203 | boxBlurRowAlpha(buf2, row, width, pixelStride, rowStride, lobes[2], false, false); 204 | } 205 | 206 | // Blur the image in vertical direction. 207 | for (int i = 0; i < width; ++i) { 208 | uint8_t *column = image.scanLine(blurRect.y()) + (blurRect.x() + i) * pixelStride + alphaOffset; 209 | boxBlurRowAlpha(column, buf1, height, pixelStride, rowStride, lobes[0], true, false); 210 | boxBlurRowAlpha(buf1, buf2, height, pixelStride, rowStride, lobes[1], false, false); 211 | boxBlurRowAlpha(buf2, column, height, pixelStride, rowStride, lobes[2], false, true); 212 | } 213 | } 214 | 215 | static inline void mirrorTopLeftQuadrant(QImage &image) 216 | { 217 | const int width = image.width(); 218 | const int height = image.height(); 219 | 220 | const int centerX = qCeil(width * 0.5); 221 | const int centerY = qCeil(height * 0.5); 222 | 223 | const int alphaOffset = QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3; 224 | const int stride = image.depth() >> 3; 225 | 226 | for (int y = 0; y < centerY; ++y) { 227 | uint8_t *in = image.scanLine(y) + alphaOffset; 228 | uint8_t *out = in + (width - 1) * stride; 229 | 230 | for (int x = 0; x < centerX; ++x, in += stride, out -= stride) { 231 | *out = *in; 232 | } 233 | } 234 | 235 | for (int y = 0; y < centerY; ++y) { 236 | const uint8_t *in = image.scanLine(y) + alphaOffset; 237 | uint8_t *out = image.scanLine(width - y - 1) + alphaOffset; 238 | 239 | for (int x = 0; x < width; ++x, in += stride, out += stride) { 240 | *out = *in; 241 | } 242 | } 243 | } 244 | 245 | static void renderShadow(QPainter *painter, const QRectF &rect, qreal borderRadius, const QPointF &offset, double radius, const QColor &color) 246 | { 247 | const qreal dpr = painter->device()->devicePixelRatioF(); 248 | const QSize inflation = calculateBlurExtent(radius); 249 | const QSize pixelSize = ((rect.size() + 2 * inflation) * dpr).toSize(); 250 | const QSizeF size = QSizeF(pixelSize) / dpr; 251 | 252 | QImage shadow(pixelSize, QImage::Format_ARGB32_Premultiplied); 253 | shadow.setDevicePixelRatio(dpr); 254 | shadow.fill(Qt::transparent); 255 | 256 | QRectF boxRect(QPoint(0, 0), rect.size()); 257 | boxRect.moveCenter(QRectF(QPoint(0, 0), size).center()); 258 | 259 | const qreal xRadius = 2.0 * borderRadius / boxRect.width(); 260 | const qreal yRadius = 2.0 * borderRadius / boxRect.height(); 261 | 262 | QPainter shadowPainter; 263 | shadowPainter.begin(&shadow); 264 | shadowPainter.setRenderHint(QPainter::Antialiasing); 265 | shadowPainter.setPen(Qt::NoPen); 266 | shadowPainter.setBrush(Qt::black); 267 | shadowPainter.drawRoundedRect(boxRect, xRadius, yRadius); 268 | shadowPainter.end(); 269 | 270 | // Because the shadow texture is symmetrical, that's enough to blur 271 | // only the top-left quadrant and then mirror it. 272 | const QRect blurRect(0, 0, std::ceil(shadow.width() * 0.5), std::ceil(shadow.height() * 0.5)); 273 | const int scaledRadius = std::round(radius * dpr); 274 | boxBlurAlpha(shadow, scaledRadius, blurRect); 275 | mirrorTopLeftQuadrant(shadow); 276 | 277 | // Give the shadow a tint of the desired color. 278 | shadowPainter.begin(&shadow); 279 | shadowPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); 280 | shadowPainter.fillRect(shadow.rect(), color); 281 | shadowPainter.end(); 282 | 283 | // Actually, present the shadow. 284 | QRectF shadowRect = shadow.rect(); 285 | shadowRect.setSize(shadowRect.size() / dpr); 286 | shadowRect.moveCenter(rect.center() + offset); 287 | painter->drawImage(shadowRect, shadow); 288 | } 289 | 290 | void BoxShadowRenderer::setBoxSize(const QSizeF &size) 291 | { 292 | m_boxSize = size; 293 | } 294 | 295 | void BoxShadowRenderer::setBorderRadius(qreal radius) 296 | { 297 | m_borderRadius = radius; 298 | } 299 | 300 | void BoxShadowRenderer::addShadow(const QPointF &offset, double radius, const QColor &color) 301 | { 302 | Shadow shadow = {}; 303 | shadow.offset = offset; 304 | shadow.radius = radius; 305 | shadow.color = color; 306 | m_shadows.append(shadow); 307 | } 308 | 309 | QImage BoxShadowRenderer::render() const 310 | { 311 | if (m_shadows.isEmpty()) { 312 | return {}; 313 | } 314 | 315 | QSizeF canvasSize; 316 | for (const Shadow &shadow : std::as_const(m_shadows)) { 317 | canvasSize = canvasSize.expandedTo(calculateMinimumShadowTextureSize(m_boxSize, shadow.radius, shadow.offset)); 318 | } 319 | 320 | QImage canvas(canvasSize.toSize(), QImage::Format_ARGB32_Premultiplied); 321 | canvas.fill(Qt::transparent); 322 | 323 | QRectF boxRect(QPoint(0, 0), m_boxSize); 324 | boxRect.moveCenter(QRect(QPoint(0, 0), canvas.size()).center()); 325 | 326 | QPainter painter(&canvas); 327 | for (const Shadow &shadow : std::as_const(m_shadows)) { 328 | renderShadow(&painter, boxRect, m_borderRadius, shadow.offset, shadow.radius, shadow.color); 329 | } 330 | painter.end(); 331 | 332 | return canvas; 333 | } 334 | 335 | QSize BoxShadowRenderer::calculateMinimumBoxSize(int radius) 336 | { 337 | const QSize blurExtent = calculateBlurExtent(radius); 338 | return 2 * blurExtent + QSize(1, 1); 339 | } 340 | 341 | QSizeF BoxShadowRenderer::calculateMinimumShadowTextureSize(const QSizeF &boxSize, double radius, const QPointF &offset) 342 | { 343 | return boxSize + 2 * calculateBlurExtent(radius) + QSizeF(std::abs(offset.x()), std::abs(offset.y())); 344 | } 345 | 346 | } // namespace Breeze 347 | -------------------------------------------------------------------------------- /config/breezelistmodel.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // listmodel.h 3 | // ------------------- 4 | // 5 | // Copyright (c) 2009 Hugo Pereira Da Costa 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including without limitation the 10 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | // sell copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | // IN THE SOFTWARE. 24 | ////////////////////////////////////////////////////////////////////////////// 25 | 26 | #pragma once 27 | 28 | #include "breezeitemmodel.h" 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | namespace Breeze 36 | { 37 | //! Job model. Stores job information for display in lists 38 | template class ListModel : public ItemModel 39 | { 40 | 41 | public: 42 | 43 | //! value type 44 | typedef T ValueType; 45 | 46 | //! reference 47 | typedef T& Reference; 48 | 49 | //! pointer 50 | typedef T* Pointer; 51 | 52 | //! value list and iterators 53 | typedef QList List; 54 | typedef QListIterator ListIterator; 55 | typedef QMutableListIterator MutableListIterator; 56 | 57 | //! list of vector 58 | // typedef QSet Set; 59 | 60 | //! constructor 61 | ListModel(QObject *parent = nullptr): 62 | ItemModel( parent ) 63 | {} 64 | 65 | //! destructor 66 | virtual ~ListModel() 67 | {} 68 | 69 | //!@name methods reimplemented from base class 70 | //@{ 71 | 72 | //! flags 73 | Qt::ItemFlags flags(const QModelIndex &index) const override 74 | { 75 | if (!index.isValid()) return Qt::NoItemFlags; 76 | return Qt::ItemIsEnabled | Qt::ItemIsSelectable; 77 | } 78 | 79 | //! unique index for given row, column and parent index 80 | QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override 81 | { 82 | 83 | // check if index is valid 84 | if( !hasIndex( row, column, parent ) ) return QModelIndex(); 85 | 86 | // return invalid index if parent is valid 87 | if( parent.isValid() ) return QModelIndex(); 88 | 89 | // check against _values 90 | return ( row < (int) _values.size() ) ? createIndex( row, column ):QModelIndex(); 91 | 92 | } 93 | 94 | //! index of parent 95 | QModelIndex parent(const QModelIndex &) const override 96 | { return QModelIndex(); } 97 | 98 | //! number of rows below given index 99 | int rowCount(const QModelIndex &parent = QModelIndex()) const override 100 | { return parent.isValid() ? 0:_values.size(); } 101 | 102 | //@} 103 | 104 | //!@name selection 105 | //@{ 106 | 107 | //! clear internal list selected items 108 | virtual void clearSelectedIndexes() 109 | { _selection.clear(); } 110 | 111 | //! store index internal selection state 112 | virtual void setIndexSelected( const QModelIndex& index, bool value ) 113 | { 114 | if( value ) _selection.push_back( get(index) ); 115 | else _selection.erase( std::remove( _selection.begin(), _selection.end(), get(index) ), _selection.end() ); 116 | } 117 | 118 | //! get list of internal selected items 119 | virtual QModelIndexList selectedIndexes() const 120 | { 121 | 122 | QModelIndexList out; 123 | for( typename List::const_iterator iter = _selection.begin(); iter != _selection.end(); iter++ ) 124 | { 125 | QModelIndex index( ListModel::index( *iter ) ); 126 | if( index.isValid() ) out.push_back( index ); 127 | } 128 | return out; 129 | 130 | } 131 | 132 | //@} 133 | 134 | //!@name interface 135 | //@{ 136 | 137 | //! add value 138 | virtual void add( const ValueType& value ) 139 | { 140 | 141 | Q_EMIT layoutAboutToBeChanged(); 142 | _add( value ); 143 | privateSort(); 144 | Q_EMIT layoutChanged(); 145 | 146 | } 147 | 148 | //! add values 149 | virtual void add( const List& values ) 150 | { 151 | 152 | // check if not empty 153 | // this avoids sending useless signals 154 | if( values.empty() ) return; 155 | 156 | Q_EMIT layoutAboutToBeChanged(); 157 | 158 | for( typename List::const_iterator iter = values.begin(); iter != values.end(); iter++ ) 159 | { _add( *iter ); } 160 | 161 | privateSort(); 162 | Q_EMIT layoutChanged(); 163 | 164 | } 165 | 166 | 167 | //! insert values 168 | virtual void insert( const QModelIndex& index, const ValueType& value ) 169 | { 170 | Q_EMIT layoutAboutToBeChanged(); 171 | _insert( index, value ); 172 | Q_EMIT layoutChanged(); 173 | } 174 | 175 | //! insert values 176 | virtual void insert( const QModelIndex& index, const List& values ) 177 | { 178 | Q_EMIT layoutAboutToBeChanged(); 179 | 180 | // need to loop in reverse order so that the "values" ordering is preserved 181 | ListIterator iter( values ); 182 | iter.toBack(); 183 | while( iter.hasPrevious() ) 184 | { _insert( index, iter.previous() ); } 185 | 186 | Q_EMIT layoutChanged(); 187 | 188 | } 189 | 190 | //! insert values 191 | virtual void replace( const QModelIndex& index, const ValueType& value ) 192 | { 193 | if( !index.isValid() ) add( value ); 194 | else { 195 | Q_EMIT layoutAboutToBeChanged(); 196 | setIndexSelected( index, false ); 197 | _values[index.row()] = value; 198 | setIndexSelected( index, true ); 199 | Q_EMIT layoutChanged(); 200 | } 201 | } 202 | 203 | //! remove 204 | virtual void remove( const ValueType& value ) 205 | { 206 | 207 | Q_EMIT layoutAboutToBeChanged(); 208 | _remove( value ); 209 | Q_EMIT layoutChanged(); 210 | 211 | } 212 | 213 | //! remove 214 | virtual void remove( const List& values ) 215 | { 216 | 217 | // check if not empty 218 | // this avoids sending useless signals 219 | if( values.empty() ) return; 220 | 221 | Q_EMIT layoutAboutToBeChanged(); 222 | for( typename List::const_iterator iter = values.begin(); iter != values.end(); iter++ ) 223 | { _remove( *iter ); } 224 | Q_EMIT layoutChanged(); 225 | 226 | } 227 | 228 | //! clear 229 | virtual void clear() 230 | { set( List() ); } 231 | 232 | //! update values from list 233 | /*! 234 | values that are not found in current are removed 235 | new values are set to the end. 236 | This is slower than the "set" method, but the selection is not cleared in the process 237 | */ 238 | virtual void update( List values ) 239 | { 240 | 241 | Q_EMIT layoutAboutToBeChanged(); 242 | 243 | // store values to be removed 244 | List removed_values; 245 | 246 | // update values that are common to both lists 247 | for( typename List::iterator iter = _values.begin(); iter != _values.end(); iter++ ) 248 | { 249 | 250 | // see if iterator is in list 251 | typename List::iterator found_iter( std::find( values.begin(), values.end(), *iter ) ); 252 | if( found_iter == values.end() ) removed_values.push_back( *iter ); 253 | else { 254 | *iter = *found_iter; 255 | values.erase( found_iter ); 256 | } 257 | 258 | } 259 | 260 | // remove values that have not been found in new list 261 | for( typename List::const_iterator iter = removed_values.constBegin(); iter != removed_values.constEnd(); iter++ ) 262 | { _remove( *iter ); } 263 | 264 | // add remaining values 265 | for( typename List::const_iterator iter = values.constBegin(); iter != values.constEnd(); iter++ ) 266 | { _add( *iter ); } 267 | 268 | privateSort(); 269 | Q_EMIT layoutChanged(); 270 | 271 | } 272 | 273 | //! set all values 274 | virtual void set( const List& values ) 275 | { 276 | 277 | Q_EMIT layoutAboutToBeChanged(); 278 | _values = values; 279 | _selection.clear(); 280 | privateSort(); 281 | Q_EMIT layoutChanged(); 282 | } 283 | 284 | //! return all values 285 | const List& get() const 286 | { return _values; } 287 | 288 | //! return value for given index 289 | virtual ValueType get( const QModelIndex& index ) const 290 | { return (index.isValid() && index.row() < int(_values.size()) ) ? _values[index.row()]:ValueType(); } 291 | 292 | //! return value for given index 293 | virtual ValueType& get( const QModelIndex& index ) 294 | { 295 | Q_ASSERT( index.isValid() && index.row() < int( _values.size() ) ); 296 | return _values[index.row()]; 297 | } 298 | 299 | //! return all values 300 | List get( const QModelIndexList& indexes ) const 301 | { 302 | List out; 303 | for( QModelIndexList::const_iterator iter = indexes.begin(); iter != indexes.end(); iter++ ) 304 | { if( iter->isValid() && iter->row() < int(_values.size()) ) out.push_back( get( *iter ) ); } 305 | return out; 306 | } 307 | 308 | //! return index associated to a given value 309 | virtual QModelIndex index( const ValueType& value, int column = 0 ) const 310 | { 311 | for( int row = 0; row < _values.size(); ++row ) 312 | { if( value == _values[row] ) return index( row, column ); } 313 | return QModelIndex(); 314 | } 315 | 316 | //@} 317 | 318 | //! return true if model contains given index 319 | virtual bool contains( const QModelIndex& index ) const 320 | { return index.isValid() && index.row() < _values.size(); } 321 | 322 | protected: 323 | 324 | //! return all values 325 | List& _get() 326 | { return _values; } 327 | 328 | //! add, without update 329 | virtual void _add( const ValueType& value ) 330 | { 331 | typename List::iterator iter = std::find( _values.begin(), _values.end(), value ); 332 | if( iter == _values.end() ) _values.push_back( value ); 333 | else *iter = value; 334 | } 335 | 336 | //! add, without update 337 | virtual void _insert( const QModelIndex& index, const ValueType& value ) 338 | { 339 | if( !index.isValid() ) add( value ); 340 | int row = 0; 341 | typename List::iterator iter( _values.begin() ); 342 | for( ;iter != _values.end() && row != index.row(); iter++, row++ ) 343 | {} 344 | 345 | _values.insert( iter, value ); 346 | } 347 | 348 | //! remove, without update 349 | virtual void _remove( const ValueType& value ) 350 | { 351 | _values.erase( std::remove( _values.begin(), _values.end(), value ), _values.end() ); 352 | _selection.erase( std::remove( _selection.begin(), _selection.end(), value ), _selection.end() ); 353 | } 354 | 355 | private: 356 | 357 | //! values 358 | List _values; 359 | 360 | //! selection 361 | List _selection; 362 | 363 | }; 364 | } 365 | 366 | -------------------------------------------------------------------------------- /config/breezeexceptionlistwidget.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // breezeexceptionlistwidget.cpp 3 | // ------------------- 4 | // 5 | // Copyright (c) 2009 Hugo Pereira Da Costa 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including without limitation the 10 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | // sell copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | // IN THE SOFTWARE. 24 | ////////////////////////////////////////////////////////////////////////////// 25 | 26 | #include "breezeexceptionlistwidget.h" 27 | #include "breezeexceptiondialog.h" 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | //__________________________________________________________ 37 | namespace Breeze 38 | { 39 | 40 | //__________________________________________________________ 41 | ExceptionListWidget::ExceptionListWidget( QWidget* parent ): 42 | QWidget( parent ) 43 | { 44 | 45 | // ui 46 | m_ui.setupUi( this ); 47 | 48 | // list 49 | m_ui.exceptionListView->setAllColumnsShowFocus( true ); 50 | m_ui.exceptionListView->setRootIsDecorated( false ); 51 | m_ui.exceptionListView->setSortingEnabled( false ); 52 | m_ui.exceptionListView->setModel( &model() ); 53 | m_ui.exceptionListView->sortByColumn( ExceptionModel::ColumnType, Qt::AscendingOrder ); 54 | m_ui.exceptionListView->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Ignored ) ); 55 | 56 | m_ui.moveUpButton->setIcon( QIcon::fromTheme( QStringLiteral( "arrow-up" ) ) ); 57 | m_ui.moveDownButton->setIcon( QIcon::fromTheme( QStringLiteral( "arrow-down" ) ) ); 58 | m_ui.addButton->setIcon( QIcon::fromTheme( QStringLiteral( "list-add" ) ) ); 59 | m_ui.removeButton->setIcon( QIcon::fromTheme( QStringLiteral( "list-remove" ) ) ); 60 | m_ui.editButton->setIcon( QIcon::fromTheme( QStringLiteral( "edit-rename" ) ) ); 61 | 62 | connect( m_ui.addButton, &QAbstractButton::clicked, this, &ExceptionListWidget::add ); 63 | connect( m_ui.editButton, &QAbstractButton::clicked, this, &ExceptionListWidget::edit ); 64 | connect( m_ui.removeButton, &QAbstractButton::clicked, this, &ExceptionListWidget::remove ); 65 | connect( m_ui.moveUpButton, &QAbstractButton::clicked, this, &ExceptionListWidget::up ); 66 | connect( m_ui.moveDownButton, &QAbstractButton::clicked, this, &ExceptionListWidget::down ); 67 | 68 | connect( m_ui.exceptionListView, &QAbstractItemView::activated, this, &ExceptionListWidget::edit ); 69 | connect( m_ui.exceptionListView, &QAbstractItemView::clicked, this, &ExceptionListWidget::toggle ); 70 | connect( m_ui.exceptionListView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ExceptionListWidget::updateButtons ); 71 | 72 | updateButtons(); 73 | resizeColumns(); 74 | 75 | 76 | } 77 | 78 | //__________________________________________________________ 79 | void ExceptionListWidget::setExceptions( const InternalSettingsList& exceptions ) 80 | { 81 | model().set( exceptions ); 82 | resizeColumns(); 83 | setChanged( false ); 84 | } 85 | 86 | //__________________________________________________________ 87 | InternalSettingsList ExceptionListWidget::exceptions() 88 | { 89 | return model().get(); 90 | setChanged( false ); 91 | } 92 | 93 | //__________________________________________________________ 94 | void ExceptionListWidget::updateButtons() 95 | { 96 | 97 | bool hasSelection( !m_ui.exceptionListView->selectionModel()->selectedRows().empty() ); 98 | m_ui.removeButton->setEnabled( hasSelection ); 99 | m_ui.editButton->setEnabled( hasSelection ); 100 | 101 | m_ui.moveUpButton->setEnabled( hasSelection && !m_ui.exceptionListView->selectionModel()->isRowSelected( 0, QModelIndex() ) ); 102 | m_ui.moveDownButton->setEnabled( hasSelection && !m_ui.exceptionListView->selectionModel()->isRowSelected( model().rowCount()-1, QModelIndex() ) ); 103 | 104 | } 105 | 106 | 107 | //_______________________________________________________ 108 | void ExceptionListWidget::add() 109 | { 110 | 111 | 112 | QPointer dialog = new ExceptionDialog( this ); 113 | dialog->setWindowTitle( i18n( "New Exception - Breeze Settings" ) ); 114 | InternalSettingsPtr exception( new InternalSettings() ); 115 | 116 | exception->load(); 117 | 118 | dialog->setException( exception ); 119 | 120 | // run dialog and check existence 121 | if (!dialog->exec()) 122 | { 123 | delete dialog; 124 | return; 125 | } 126 | 127 | dialog->save(); 128 | delete dialog; 129 | 130 | // check exceptions 131 | if (!checkException(exception)) 132 | return; 133 | 134 | // create new item 135 | model().add( exception ); 136 | setChanged( true ); 137 | 138 | // make sure item is selected 139 | QModelIndex index( model().index( exception ) ); 140 | if( index != m_ui.exceptionListView->selectionModel()->currentIndex() ) 141 | { 142 | m_ui.exceptionListView->selectionModel()->select( index, QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Rows ); 143 | m_ui.exceptionListView->selectionModel()->setCurrentIndex( index, QItemSelectionModel::Current|QItemSelectionModel::Rows ); 144 | } 145 | 146 | resizeColumns(); 147 | 148 | } 149 | 150 | //_______________________________________________________ 151 | void ExceptionListWidget::edit() 152 | { 153 | 154 | // retrieve selection 155 | QModelIndex current( m_ui.exceptionListView->selectionModel()->currentIndex() ); 156 | if(!model().contains(current)) 157 | return; 158 | 159 | InternalSettingsPtr exception(model().get(current)); 160 | 161 | // create dialog 162 | QPointer dialog(new ExceptionDialog(this)); 163 | dialog->setWindowTitle( i18n("Edit Exception - Breeze Settings")); 164 | dialog->setException(exception); 165 | 166 | // map dialog 167 | if (!dialog->exec()) 168 | { 169 | delete dialog; 170 | return; 171 | } 172 | 173 | // check modifications 174 | if(!dialog->isChanged()) 175 | return; 176 | 177 | // retrieve exception 178 | dialog->save(); 179 | delete dialog; 180 | 181 | // check new exception validity 182 | checkException(exception); 183 | resizeColumns(); 184 | 185 | setChanged(true); 186 | 187 | } 188 | 189 | //_______________________________________________________ 190 | void ExceptionListWidget::remove() 191 | { 192 | 193 | // confirmation dialog 194 | { 195 | QMessageBox messageBox(QMessageBox::Question, i18n("Question - Breeze Settings" ), i18n("Remove selected exception?"), QMessageBox::Yes | QMessageBox::Cancel); 196 | messageBox.button(QMessageBox::Yes)->setText(i18n("Remove")); 197 | messageBox.setDefaultButton(QMessageBox::Cancel); 198 | if (messageBox.exec() == QMessageBox::Cancel) 199 | return; 200 | } 201 | 202 | // remove 203 | model().remove(model().get(m_ui.exceptionListView->selectionModel()->selectedRows())); 204 | resizeColumns(); 205 | updateButtons(); 206 | 207 | setChanged(true); 208 | 209 | } 210 | 211 | //_______________________________________________________ 212 | void ExceptionListWidget::toggle( const QModelIndex& index ) 213 | { 214 | 215 | if (!model().contains(index)) 216 | return; 217 | if (index.column() != ExceptionModel::ColumnEnabled) 218 | return; 219 | 220 | // get matching exception 221 | InternalSettingsPtr exception(model().get(index)); 222 | exception->setEnabled(!exception->enabled()); 223 | setChanged(true); 224 | 225 | } 226 | 227 | //_______________________________________________________ 228 | void ExceptionListWidget::up() 229 | { 230 | 231 | InternalSettingsList selection(model().get(m_ui.exceptionListView->selectionModel()->selectedRows())); 232 | if(selection.empty()) 233 | return; 234 | 235 | // retrieve selected indexes in list and store in model 236 | QModelIndexList selectedIndices( m_ui.exceptionListView->selectionModel()->selectedRows() ); 237 | InternalSettingsList selectedExceptions( model().get( selectedIndices ) ); 238 | 239 | InternalSettingsList currentException( model().get() ); 240 | InternalSettingsList newExceptions; 241 | 242 | for( InternalSettingsList::const_iterator iter = currentException.constBegin(); iter != currentException.constEnd(); ++iter ) 243 | { 244 | 245 | // check if new list is not empty, current index is selected and last index is not. 246 | // if yes, move. 247 | if( 248 | !( newExceptions.empty() || 249 | selectedIndices.indexOf( model().index( *iter ) ) == -1 || 250 | selectedIndices.indexOf( model().index( newExceptions.back() ) ) != -1 251 | ) ) 252 | { 253 | InternalSettingsPtr last( newExceptions.back() ); 254 | newExceptions.removeLast(); 255 | newExceptions.append( *iter ); 256 | newExceptions.append( last ); 257 | } else newExceptions.append( *iter ); 258 | 259 | } 260 | 261 | model().set(newExceptions); 262 | 263 | // restore selection 264 | m_ui.exceptionListView->selectionModel()->select( model().index( selectedExceptions.front() ), QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Rows ); 265 | for( InternalSettingsList::const_iterator iter = selectedExceptions.constBegin(); iter != selectedExceptions.constEnd(); ++iter ) 266 | { m_ui.exceptionListView->selectionModel()->select( model().index( *iter ), QItemSelectionModel::Select|QItemSelectionModel::Rows ); } 267 | 268 | setChanged(true); 269 | 270 | } 271 | 272 | //_______________________________________________________ 273 | void ExceptionListWidget::down() 274 | { 275 | 276 | InternalSettingsList selection( model().get( m_ui.exceptionListView->selectionModel()->selectedRows() ) ); 277 | if( selection.empty() ) 278 | { return; } 279 | 280 | // retrieve selected indexes in list and store in model 281 | QModelIndexList selectedIndices( m_ui.exceptionListView->selectionModel()->selectedIndexes() ); 282 | InternalSettingsList selectedExceptions( model().get( selectedIndices ) ); 283 | 284 | InternalSettingsList currentExceptions( model().get() ); 285 | InternalSettingsList newExceptions; 286 | 287 | InternalSettingsListIterator iter( currentExceptions ); 288 | iter.toBack(); 289 | while( iter.hasPrevious() ) 290 | { 291 | 292 | InternalSettingsPtr current( iter.previous() ); 293 | 294 | // check if new list is not empty, current index is selected and last index is not. 295 | // if yes, move. 296 | if( 297 | !( newExceptions.empty() || 298 | selectedIndices.indexOf( model().index( current ) ) == -1 || 299 | selectedIndices.indexOf( model().index( newExceptions.front() ) ) != -1 300 | ) ) 301 | { 302 | 303 | InternalSettingsPtr first( newExceptions.front() ); 304 | newExceptions.removeFirst(); 305 | newExceptions.prepend( current ); 306 | newExceptions.prepend( first ); 307 | 308 | } else newExceptions.prepend( current ); 309 | } 310 | 311 | model().set( newExceptions ); 312 | 313 | // restore selection 314 | m_ui.exceptionListView->selectionModel()->select( model().index( selectedExceptions.front() ), QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Rows ); 315 | for( InternalSettingsList::const_iterator iter = selectedExceptions.constBegin(); iter != selectedExceptions.constEnd(); ++iter ) 316 | { m_ui.exceptionListView->selectionModel()->select( model().index( *iter ), QItemSelectionModel::Select|QItemSelectionModel::Rows ); } 317 | 318 | setChanged( true ); 319 | 320 | } 321 | 322 | //_______________________________________________________ 323 | void ExceptionListWidget::resizeColumns() const 324 | { 325 | m_ui.exceptionListView->resizeColumnToContents( ExceptionModel::ColumnEnabled ); 326 | m_ui.exceptionListView->resizeColumnToContents( ExceptionModel::ColumnType ); 327 | m_ui.exceptionListView->resizeColumnToContents( ExceptionModel::ColumnRegExp ); 328 | } 329 | 330 | //_______________________________________________________ 331 | bool ExceptionListWidget::checkException( InternalSettingsPtr exception ) 332 | { 333 | 334 | while( exception->exceptionPattern().isEmpty() || !QRegularExpression( exception->exceptionPattern() ).isValid() ) 335 | { 336 | 337 | QMessageBox::warning( this, i18n( "Warning - Breeze Settings" ), i18n("Regular Expression syntax is incorrect") ); 338 | QPointer dialog( new ExceptionDialog( this ) ); 339 | dialog->setException( exception ); 340 | if( dialog->exec() == QDialog::Rejected ) 341 | { 342 | delete dialog; 343 | return false; 344 | } 345 | 346 | dialog->save(); 347 | delete dialog; 348 | } 349 | 350 | return true; 351 | } 352 | 353 | } 354 | -------------------------------------------------------------------------------- /config/breezeconfigwidget.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // breezeconfigurationui.cpp 3 | // ------------------- 4 | // 5 | // Copyright (c) 2009 Hugo Pereira Da Costa 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including without limitation the 10 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | // sell copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | // IN THE SOFTWARE. 24 | ////////////////////////////////////////////////////////////////////////////// 25 | 26 | #include "breezeconfigwidget.h" 27 | #include "breezeexceptionlist.h" 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | namespace Breeze 36 | { 37 | 38 | //_________________________________________________________ 39 | ConfigWidget::ConfigWidget(QObject *parent, const KPluginMetaData &data, const QVariantList & /*args*/): 40 | KCModule(parent, data), 41 | m_configuration( KSharedConfig::openConfig( QStringLiteral( "breezerc" ) ) ), 42 | m_changed( false ) 43 | { 44 | 45 | // configuration 46 | m_ui.setupUi(widget()); 47 | 48 | // track ui changes 49 | connect(m_ui.titleAlignment, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged())); 50 | connect(m_ui.buttonSize, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged())); 51 | connect(m_ui.titleMarginSpinBox, QOverload::of(&QSpinBox::valueChanged), [this](int /*i*/) {updateChanged();}); 52 | connect(m_ui.btnSpacingSpinBox, QOverload::of(&QSpinBox::valueChanged), [this](int /*i*/) {updateChanged();}); 53 | connect(m_ui.drawBackgroundGradient, &QAbstractButton::clicked, this, &ConfigWidget::updateChanged); 54 | connect(m_ui.roundedCorners, &QAbstractButton::clicked, this, &ConfigWidget::updateChanged); 55 | connect(m_ui.macOSButtons, SIGNAL(clicked()), SLOT(updateChanged()) ); 56 | connect(m_ui.opacitySpinBox, QOverload::of(&QSpinBox::valueChanged), [this](int /*i*/) {updateChanged();}); 57 | connect(m_ui.gradientSpinBox, QOverload::of(&QSpinBox::valueChanged), [this](int /*i*/) {updateChanged();}); 58 | 59 | connect(m_ui.fontComboBox, &QFontComboBox::currentFontChanged, [this] {updateChanged();}); 60 | connect(m_ui.fontSizeSpinBox, QOverload::of(&QSpinBox::valueChanged), [this](int /*i*/) {updateChanged();}); 61 | connect(m_ui.weightComboBox, QOverload::of(&QComboBox::currentIndexChanged), [this] {updateChanged();}); 62 | #if (QT_VERSION >= QT_VERSION_CHECK(6,7,0)) 63 | connect(m_ui.italicCheckBox, &QCheckBox::checkStateChanged, [this] {updateChanged();}); 64 | #else 65 | connect(m_ui.italicCheckBox, &QCheckBox::stateChanged, [this] {updateChanged();}); 66 | #endif 67 | 68 | // track animations changes 69 | connect(m_ui.animationsEnabled, &QAbstractButton::clicked, this, &ConfigWidget::updateChanged); 70 | connect(m_ui.animationsDuration, SIGNAL(valueChanged(int)), SLOT(updateChanged())); 71 | 72 | // track shadows changes 73 | connect(m_ui.shadowSize, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged())); 74 | connect(m_ui.shadowStrength, SIGNAL(valueChanged(int)), SLOT(updateChanged())); 75 | connect(m_ui.shadowColor, &KColorButton::changed, this, &ConfigWidget::updateChanged); 76 | 77 | // track exception changes 78 | connect(m_ui.exceptions, &ExceptionListWidget::changed, this, &ConfigWidget::updateChanged); 79 | 80 | } 81 | 82 | //_________________________________________________________ 83 | void ConfigWidget::load() 84 | { 85 | 86 | // create internal settings and load from rc files 87 | m_internalSettings = InternalSettingsPtr(new InternalSettings()); 88 | m_internalSettings->load(); 89 | 90 | // assign to ui 91 | m_ui.titleAlignment->setCurrentIndex(m_internalSettings->titleAlignment()); 92 | m_ui.buttonSize->setCurrentIndex(m_internalSettings->buttonSize()); 93 | m_ui.titleMarginSpinBox->setValue(m_internalSettings->extraTitleMargin()); 94 | m_ui.btnSpacingSpinBox->setValue(m_internalSettings->buttonSpacing()); 95 | m_ui.drawBackgroundGradient->setChecked(m_internalSettings->drawBackgroundGradient()); 96 | m_ui.roundedCorners->setChecked(m_internalSettings->roundedCorners()); 97 | m_ui.animationsEnabled->setChecked(m_internalSettings->animationsEnabled()); 98 | m_ui.animationsDuration->setValue(m_internalSettings->animationsDuration()); 99 | m_ui.macOSButtons->setChecked(m_internalSettings->macOSButtons()); 100 | m_ui.opacitySpinBox->setValue(m_internalSettings->backgroundOpacity()); 101 | m_ui.gradientSpinBox->setValue(m_internalSettings->backgroundGradientIntensity()); 102 | 103 | QString fontStr = m_internalSettings->titleBarFont(); 104 | if (fontStr.isEmpty()) 105 | fontStr = QLatin1String("Sans,11,-1,5,400,0,0,0,0,0,0,0,0,0,0,1"); 106 | QFont f; f.fromString(fontStr); 107 | m_ui.fontComboBox->setCurrentFont(f); 108 | m_ui.fontSizeSpinBox->setValue(f.pointSize()); 109 | int w = f.weight(); 110 | switch (w) { 111 | case QFont::Medium: 112 | m_ui.weightComboBox->setCurrentIndex(1); 113 | break; 114 | case QFont::DemiBold: 115 | m_ui.weightComboBox->setCurrentIndex(2); 116 | break; 117 | case QFont::Bold: 118 | m_ui.weightComboBox->setCurrentIndex(3); 119 | break; 120 | case QFont::ExtraBold: 121 | m_ui.weightComboBox->setCurrentIndex(4); 122 | break; 123 | case QFont::Black: 124 | m_ui.weightComboBox->setCurrentIndex(5); 125 | break; 126 | default: 127 | m_ui.weightComboBox->setCurrentIndex(0); 128 | break; 129 | } 130 | m_ui.italicCheckBox->setChecked(f.italic()); 131 | 132 | // load shadows 133 | if(m_internalSettings->shadowSize() <= InternalSettings::ShadowVeryLarge) 134 | m_ui.shadowSize->setCurrentIndex(m_internalSettings->shadowSize()); 135 | else 136 | m_ui.shadowSize->setCurrentIndex(InternalSettings::ShadowLarge); 137 | 138 | m_ui.shadowStrength->setValue(qRound(qreal(m_internalSettings->shadowStrength()*100)/255)); 139 | m_ui.shadowColor->setColor(m_internalSettings->shadowColor()); 140 | 141 | // load exceptions 142 | ExceptionList exceptions; 143 | exceptions.readConfig(m_configuration); 144 | m_ui.exceptions->setExceptions(exceptions.get()); 145 | setNeedsSave(false); 146 | 147 | } 148 | 149 | //_________________________________________________________ 150 | void ConfigWidget::save() 151 | { 152 | 153 | // create internal settings and load from rc files 154 | m_internalSettings = InternalSettingsPtr(new InternalSettings()); 155 | m_internalSettings->load(); 156 | 157 | // apply modifications from ui 158 | m_internalSettings->setTitleAlignment(m_ui.titleAlignment->currentIndex()); 159 | m_internalSettings->setButtonSize(m_ui.buttonSize->currentIndex()); 160 | m_internalSettings->setExtraTitleMargin(m_ui.titleMarginSpinBox->value()); 161 | m_internalSettings->setButtonSpacing(m_ui.btnSpacingSpinBox->value()); 162 | m_internalSettings->setDrawBackgroundGradient(m_ui.drawBackgroundGradient->isChecked()); 163 | m_internalSettings->setRoundedCorners(m_ui.roundedCorners->isChecked()); 164 | m_internalSettings->setAnimationsEnabled(m_ui.animationsEnabled->isChecked()); 165 | m_internalSettings->setAnimationsDuration(m_ui.animationsDuration->value()); 166 | m_internalSettings->setMacOSButtons(m_ui.macOSButtons->isChecked()); 167 | m_internalSettings->setBackgroundOpacity(m_ui.opacitySpinBox->value()); 168 | m_internalSettings->setBackgroundGradientIntensity(m_ui.gradientSpinBox->value()); 169 | 170 | QFont f = m_ui.fontComboBox->currentFont(); 171 | f.setPointSize(m_ui.fontSizeSpinBox->value()); 172 | int indx = m_ui.weightComboBox->currentIndex(); 173 | switch (indx) { 174 | case 1: 175 | f.setWeight(QFont::Medium); 176 | break; 177 | case 2: 178 | f.setWeight(QFont::DemiBold); 179 | break; 180 | case 3: 181 | f.setWeight(QFont::Bold); 182 | break; 183 | case 4: 184 | f.setWeight(QFont::ExtraBold); 185 | break; 186 | case 5: 187 | f.setWeight(QFont::Black); 188 | break; 189 | default: 190 | f.setBold(false); 191 | break; 192 | } 193 | f.setItalic(m_ui.italicCheckBox->isChecked()); 194 | m_internalSettings->setTitleBarFont(f.toString()); 195 | 196 | m_internalSettings->setShadowSize(m_ui.shadowSize->currentIndex()); 197 | m_internalSettings->setShadowStrength(qRound( qreal(m_ui.shadowStrength->value()*255)/100)); 198 | m_internalSettings->setShadowColor(m_ui.shadowColor->color()); 199 | 200 | // save configuration 201 | m_internalSettings->save(); 202 | 203 | // get list of exceptions and write 204 | InternalSettingsList exceptions(m_ui.exceptions->exceptions()); 205 | ExceptionList(exceptions).writeConfig(m_configuration); 206 | 207 | // sync configuration 208 | m_configuration->sync(); 209 | setNeedsSave(false); 210 | 211 | // needed to tell kwin to reload when running from external kcmshell 212 | { 213 | QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"), 214 | QStringLiteral("org.kde.KWin"), 215 | QStringLiteral("reloadConfig")); 216 | QDBusConnection::sessionBus().send(message); 217 | } 218 | 219 | // needed for breeze style to reload shadows 220 | { 221 | QDBusMessage message(QDBusMessage::createSignal(QStringLiteral("/BreezeDecoration"), 222 | QStringLiteral("org.kde.Breeze.Style"), 223 | QStringLiteral("reparseConfiguration"))); 224 | QDBusConnection::sessionBus().send(message); 225 | } 226 | 227 | } 228 | 229 | //_________________________________________________________ 230 | void ConfigWidget::defaults() 231 | { 232 | 233 | // create internal settings and load from rc files 234 | m_internalSettings = InternalSettingsPtr(new InternalSettings()); 235 | m_internalSettings->setDefaults(); 236 | 237 | // assign to ui 238 | m_ui.titleAlignment->setCurrentIndex(m_internalSettings->titleAlignment()); 239 | m_ui.buttonSize->setCurrentIndex(m_internalSettings->buttonSize()); 240 | m_ui.titleMarginSpinBox->setValue(m_internalSettings->extraTitleMargin()); 241 | m_ui.btnSpacingSpinBox->setValue(m_internalSettings->buttonSpacing()); 242 | m_ui.drawBackgroundGradient->setChecked(m_internalSettings->drawBackgroundGradient()); 243 | m_ui.roundedCorners->setChecked(m_internalSettings->roundedCorners()); 244 | m_ui.animationsEnabled->setChecked(m_internalSettings->animationsEnabled()); 245 | m_ui.animationsDuration->setValue(m_internalSettings->animationsDuration()); 246 | m_ui.macOSButtons->setChecked(m_internalSettings->macOSButtons()); 247 | m_ui.opacitySpinBox->setValue(m_internalSettings->backgroundOpacity()); 248 | m_ui.gradientSpinBox->setValue(m_internalSettings->backgroundGradientIntensity()); 249 | 250 | QFont f; f.fromString(QStringLiteral("Sans,11,-1,5,400,0,0,0,0,0,0,0,0,0,0,1")); 251 | m_ui.fontComboBox->setCurrentFont(f); 252 | m_ui.fontSizeSpinBox->setValue(f.pointSize()); 253 | int w = f.weight(); 254 | switch (w) { 255 | case QFont::Medium: 256 | m_ui.weightComboBox->setCurrentIndex(1); 257 | break; 258 | case QFont::DemiBold: 259 | m_ui.weightComboBox->setCurrentIndex(2); 260 | break; 261 | case QFont::Bold: 262 | m_ui.weightComboBox->setCurrentIndex(3); 263 | break; 264 | case QFont::ExtraBold: 265 | m_ui.weightComboBox->setCurrentIndex(4); 266 | break; 267 | case QFont::Black: 268 | m_ui.weightComboBox->setCurrentIndex(5); 269 | break; 270 | default: 271 | m_ui.weightComboBox->setCurrentIndex(0); 272 | break; 273 | } 274 | m_ui.italicCheckBox->setChecked(f.italic()); 275 | 276 | m_ui.shadowSize->setCurrentIndex(m_internalSettings->shadowSize()); 277 | m_ui.shadowStrength->setValue(qRound(qreal(m_internalSettings->shadowStrength()*100)/255)); 278 | m_ui.shadowColor->setColor(m_internalSettings->shadowColor()); 279 | 280 | } 281 | 282 | //_______________________________________________ 283 | void ConfigWidget::updateChanged() 284 | { 285 | 286 | // check configuration 287 | if(!m_internalSettings) 288 | return; 289 | 290 | // track modifications 291 | bool modified(false); 292 | QFont f; f.fromString(m_internalSettings->titleBarFont()); 293 | 294 | if (m_ui.macOSButtons->isChecked() != m_internalSettings->macOSButtons()) 295 | modified = true; 296 | if (m_ui.titleAlignment->currentIndex() != m_internalSettings->titleAlignment()) 297 | modified = true; 298 | else if (m_ui.buttonSize->currentIndex() != m_internalSettings->buttonSize()) 299 | modified = true; 300 | else if (m_ui.titleMarginSpinBox->value() != m_internalSettings->extraTitleMargin()) 301 | modified = true; 302 | else if (m_ui.btnSpacingSpinBox->value() != m_internalSettings->buttonSpacing()) 303 | modified = true; 304 | else if (m_ui.drawBackgroundGradient->isChecked() != m_internalSettings->drawBackgroundGradient()) 305 | modified = true; 306 | else if (m_ui.roundedCorners->isChecked() != m_internalSettings->roundedCorners()) 307 | modified = true; 308 | else if (m_ui.opacitySpinBox->value() != m_internalSettings->backgroundOpacity()) 309 | modified = true; 310 | else if (m_ui.gradientSpinBox->value() != m_internalSettings->backgroundGradientIntensity()) 311 | modified = true; 312 | 313 | // font (also see below) 314 | else if (m_ui.fontComboBox->currentFont().toString() != f.family()) 315 | modified = true; 316 | else if (m_ui.fontSizeSpinBox->value() != f.pointSize()) 317 | modified = true; 318 | else if (m_ui.italicCheckBox->isChecked() != f.italic()) 319 | modified = true; 320 | 321 | // animations 322 | else if (m_ui.animationsEnabled->isChecked() != m_internalSettings->animationsEnabled()) 323 | modified = true; 324 | else if (m_ui.animationsDuration->value() != m_internalSettings->animationsDuration()) 325 | modified = true; 326 | 327 | // shadows 328 | else if (m_ui.shadowSize->currentIndex() != m_internalSettings->shadowSize()) 329 | modified = true; 330 | else if (qRound(qreal(m_ui.shadowStrength->value()*255)/100) != m_internalSettings->shadowStrength()) 331 | modified = true; 332 | else if (m_ui.shadowColor->color() != m_internalSettings->shadowColor()) 333 | modified = true; 334 | 335 | // exceptions 336 | else if (m_ui.exceptions->isChanged()) 337 | modified = true; 338 | else { 339 | int indx = m_ui.weightComboBox->currentIndex(); 340 | switch (indx) { 341 | case 1: 342 | if (f.weight() != QFont::Medium) modified = true; 343 | break; 344 | case 2: 345 | if (f.weight() != QFont::DemiBold) modified = true; 346 | break; 347 | case 3: 348 | if (f.weight() != QFont::Bold) modified = true; 349 | break; 350 | case 4: 351 | if (f.weight() != QFont::ExtraBold) modified = true; 352 | break; 353 | case 5: 354 | if (f.weight() != QFont::Black) modified = true; 355 | break; 356 | default: 357 | if (f.bold()) modified = true; 358 | break; 359 | } 360 | } 361 | 362 | setNeedsSave(modified); 363 | 364 | } 365 | 366 | } 367 | -------------------------------------------------------------------------------- /config/ui/breezeconfigurationui.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | BreezeConfigurationUI 4 | 5 | 6 | 7 | 0 8 | 0 9 | 428 10 | 418 11 | 12 | 13 | 14 | 15 | 0 16 | 17 | 18 | 19 | 20 | 0 21 | 22 | 23 | 24 | General 25 | 26 | 27 | 28 | 29 | 30 | Tit&le alignment: 31 | 32 | 33 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 34 | 35 | 36 | titleAlignment 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Left 45 | 46 | 47 | 48 | 49 | Center 50 | 51 | 52 | 53 | 54 | Center (Full Width) 55 | 56 | 57 | 58 | 59 | Right 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | Qt::Horizontal 68 | 69 | 70 | 71 | 40 72 | 20 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | B&utton size: 81 | 82 | 83 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 84 | 85 | 86 | buttonSize 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | Tiny 95 | 96 | 97 | 98 | 99 | Small 100 | 101 | 102 | 103 | 104 | Medium 105 | 106 | 107 | 108 | 109 | Large 110 | 111 | 112 | 113 | 114 | Very Large 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | Extra horizontal title margin: 125 | 126 | 127 | 128 | 129 | 130 | 131 | px 132 | 133 | 134 | 135 | 136 | 137 | 138 | Qt::Horizontal 139 | 140 | 141 | 142 | 40 143 | 20 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | Button spacing: 156 | 157 | 158 | 159 | 160 | 161 | 162 | px 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | Qt::Horizontal 173 | 174 | 175 | 176 | 40 177 | 20 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | Draw titlebar background gradient 188 | 189 | 190 | 191 | 192 | 193 | 194 | false 195 | 196 | 197 | Gradient intensity: 198 | 199 | 200 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 201 | 202 | 203 | 204 | 205 | 206 | 207 | false 208 | 209 | 210 | % 211 | 212 | 213 | 100 214 | 215 | 216 | 217 | 218 | 219 | 220 | macOS-like buttons 221 | 222 | 223 | 224 | 225 | 226 | 227 | Round bottom corners of windows with no borders 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | Opacity: 237 | 238 | 239 | 240 | 241 | 242 | 243 | % 244 | 245 | 246 | 100 247 | 248 | 249 | 250 | 251 | 252 | 253 | Qt::Horizontal 254 | 255 | 256 | 257 | 5 258 | 5 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | Font: 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 5 276 | 277 | 278 | 50 279 | 280 | 281 | 282 | 283 | 284 | 285 | Size: 286 | 287 | 288 | 289 | 290 | 291 | 292 | Qt::Horizontal 293 | 294 | 295 | 296 | 5 297 | 5 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | Weight: 306 | 307 | 308 | 309 | 310 | 311 | 312 | 0 313 | 314 | 315 | 316 | Normal 317 | 318 | 319 | 320 | 321 | Medium 322 | 323 | 324 | 325 | 326 | DemiBold 327 | 328 | 329 | 330 | 331 | Bold 332 | 333 | 334 | 335 | 336 | ExtraBold 337 | 338 | 339 | 340 | 341 | Black 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | Italic 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | Qt::Horizontal 360 | 361 | 362 | 363 | 5 364 | 5 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | Qt::Vertical 375 | 376 | 377 | 378 | 20 379 | 40 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | Animations 389 | 390 | 391 | 392 | 393 | 394 | Enable animations 395 | 396 | 397 | 398 | 399 | 400 | 401 | false 402 | 403 | 404 | Anima&tions duration: 405 | 406 | 407 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 408 | 409 | 410 | animationsDuration 411 | 412 | 413 | 414 | 415 | 416 | 417 | false 418 | 419 | 420 | ms 421 | 422 | 423 | 500 424 | 425 | 426 | 427 | 428 | 429 | 430 | Qt::Horizontal 431 | 432 | 433 | 434 | 40 435 | 20 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | Qt::Vertical 444 | 445 | 446 | 447 | 20 448 | 40 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | Shadows 458 | 459 | 460 | 461 | 462 | 463 | Si&ze: 464 | 465 | 466 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 467 | 468 | 469 | shadowSize 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | None 478 | 479 | 480 | 481 | 482 | Small 483 | 484 | 485 | 486 | 487 | Medium 488 | 489 | 490 | 491 | 492 | Large 493 | 494 | 495 | 496 | 497 | Very Large 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | S&trength: 506 | 507 | 508 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 509 | 510 | 511 | shadowStrength 512 | 513 | 514 | 515 | 516 | 517 | 518 | % 519 | 520 | 521 | 10 522 | 523 | 524 | 100 525 | 526 | 527 | 528 | 529 | 530 | 531 | Qt::Horizontal 532 | 533 | 534 | 535 | 40 536 | 20 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | Color: 545 | 546 | 547 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | Qt::Vertical 558 | 559 | 560 | 561 | 20 562 | 40 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | Window-Specific Overrides 572 | 573 | 574 | 575 | 576 | 577 | 578 | 0 579 | 0 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | KColorButton 593 | QPushButton 594 |
kcolorbutton.h
595 |
596 | 597 | Breeze::ExceptionListWidget 598 | QWidget 599 |
config/breezeexceptionlistwidget.h
600 | 1 601 |
602 |
603 | 604 | 605 | 606 | animationsEnabled 607 | toggled(bool) 608 | animationsDurationLabel 609 | setEnabled(bool) 610 | 611 | 612 | 34 613 | 194 614 | 615 | 616 | 84 617 | 221 618 | 619 | 620 | 621 | 622 | animationsEnabled 623 | toggled(bool) 624 | animationsDuration 625 | setEnabled(bool) 626 | 627 | 628 | 108 629 | 194 630 | 631 | 632 | 141 633 | 229 634 | 635 | 636 | 637 | 638 | drawBackgroundGradient 639 | toggled(bool) 640 | gradientSpinBox 641 | setEnabled(bool) 642 | 643 | 644 | 222 645 | 160 646 | 647 | 648 | 166 649 | 188 650 | 651 | 652 | 653 | 654 | drawBackgroundGradient 655 | toggled(bool) 656 | label_7 657 | setEnabled(bool) 658 | 659 | 660 | 222 661 | 160 662 | 663 | 664 | 64 665 | 57 666 | 667 | 668 | 669 | 670 |
671 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------