├── .clang-format ├── .gitignore ├── CHANGELOG.md ├── CMakeLists.txt ├── COPYING ├── COPYING.LIB ├── INSTALLATION.md ├── LICENSE ├── LICENSES ├── GPL-2.0-only.txt ├── GPL-2.0-or-later.txt ├── GPL-3.0-only.txt └── LicenseRef-KDE-Accepted-GPL.txt ├── README.md ├── install.sh ├── libappletdecoration ├── CMakeLists.txt ├── appletdecorationplugin.cpp ├── appletdecorationplugin.h ├── auroraetheme.cpp ├── auroraetheme.h ├── buttonsmodel.cpp ├── buttonsmodel.h ├── commontools.cpp ├── commontools.h ├── config-decoration.h.cmake ├── decorationpalette.cpp ├── decorationpalette.h ├── decorationsmodel.cpp ├── decorationsmodel.h ├── environment.cpp ├── environment.h ├── kwinconfig.cpp ├── kwinconfig.h ├── padding.cpp ├── padding.h ├── previewbridge.cpp ├── previewbridge.h ├── previewbutton.cpp ├── previewbutton.h ├── previewclient.cpp ├── previewclient.h ├── previewsettings.cpp ├── previewsettings.h ├── previewshareddecoration.cpp ├── previewshareddecoration.h ├── qml │ └── AuroraeButton.qml ├── qmldir ├── schemecolors.cpp ├── schemecolors.h ├── schemesmodel.cpp ├── schemesmodel.h ├── themeextended.cpp ├── themeextended.h ├── types.cpp └── types.h ├── package ├── contents │ ├── code │ │ └── tools.js │ ├── config │ │ ├── config.qml │ │ └── main.xml │ └── ui │ │ ├── PlasmaTasksModel.qml │ │ ├── config │ │ ├── ColorsComboBox.qml │ │ ├── ConfigBehavior.qml │ │ ├── ConfigGeneral.qml │ │ ├── DecorationsComboBox.qml │ │ ├── LockItem.qml │ │ └── OrderableListView.qml │ │ └── main.qml ├── metadata.desktop └── metadata.json └── uninstall.sh /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Microsoft 3 | AccessModifierOffset: -2 4 | AlignAfterOpenBracket: Align 5 | AllowAllArgumentsOnNextLine: false 6 | AllowAllConstructorInitializersOnNextLine: false 7 | AllowAllParametersOfDeclarationOnNextLine: false 8 | AlignConsecutiveMacros: true 9 | AllowShortBlocksOnASingleLine: Never 10 | AllowShortCaseLabelsOnASingleLine: true 11 | AllowShortFunctionsOnASingleLine: None 12 | AllowShortIfStatementsOnASingleLine: Never 13 | AllowShortLambdasOnASingleLine: All 14 | AllowShortLoopsOnASingleLine: false 15 | AlwaysBreakAfterDefinitionReturnType: None 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakBeforeMultilineStrings: false 18 | AlwaysBreakTemplateDeclarations: Yes 19 | BinPackArguments: true 20 | BinPackParameters: true 21 | BreakBeforeBraces: Allman 22 | BreakBeforeTernaryOperators: false 23 | BreakInheritanceList: BeforeComma 24 | BreakStringLiterals: false 25 | ColumnLimit: 170 26 | CompactNamespaces: false 27 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 28 | Cpp11BracedListStyle: false 29 | ExperimentalAutoDetectBinPacking: false 30 | FixNamespaceComments: true 31 | IncludeBlocks: Regroup 32 | IndentCaseLabels: true 33 | IndentPPDirectives: None 34 | IndentWidth: 4 35 | MaxEmptyLinesToKeep: 1 36 | NamespaceIndentation: All 37 | ReflowComments: true 38 | SortIncludes: true 39 | SortUsingDeclarations: true 40 | SpaceAfterCStyleCast: true 41 | SpaceAfterTemplateKeyword: false 42 | SpaceBeforeParens: ControlStatements 43 | SpaceBeforeRangeBasedForLoopColon: true 44 | SpacesInParentheses: false 45 | Standard: c++17 46 | StatementMacros: [Q_UNUSED LOG DEBUG] 47 | # ForEachMacros: [list_foreach] 48 | TabWidth: 4 49 | UseTab: Never 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .* 3 | !.arcconfig 4 | !.gitignore 5 | # Ignore hidden files 6 | .directory 7 | 8 | # Ignore patches 9 | *.patch~ 10 | 11 | # build directory 12 | build/ 13 | 14 | # backup files 15 | *.autosave 16 | *.desktop~ 17 | *.gitignore~ 18 | *.js~ 19 | *.kate-swp 20 | *.qml~ 21 | *.sh~ 22 | *.xml~ 23 | .*.cpp~ 24 | .*.h~ 25 | .*.js~ 26 | .*.pot~ 27 | .*.po~ 28 | .*.qml~ 29 | .*.txt~ 30 | .*.xml~ 31 | .*~ 32 | *.*.user 33 | *.*.orig 34 | 35 | # locale files 36 | *.mo 37 | 38 | # KDevelop Project files 39 | *.kdev4 40 | .kdev4/ 41 | 42 | build-kdev/ 43 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### CHANGELOG 2 | 3 | #### Version 0.11.0 4 | 5 | * support Plasma 5.24 way of discovering themes from theme engines 6 | * hide when preserveemptyspace is selected 7 | 8 | #### Version 0.10.1 9 | 10 | * fix glitches with slide-in/out animations 11 | * improve cpu and hard disk usage 12 | * remove all workarounds related to faulty buttons painting 13 | * respect and trust bug fixes in decorations provided with Plasma 5.23.2 14 | 15 | #### Version 0.10.0 16 | 17 | * support Plasma 5.23 18 | * depend only on Plasma and KDecorations2 >= 5.23 19 | * drop option for plasma panels to disable decoration on maximized windows 20 | 21 | #### Version 0.9.0 22 | 23 | * support Plasma 5.18 and 5.21 24 | * support aurorae monochrome icons with Latte auto-color functionality 25 | * support aurorae restore button 26 | * fix, do not hide buttons for AlwaysVisible 27 | * fix, do not hide button in Latte edit mode 28 | * fix, improve default based on Plasma values 29 | * fix, preserve empty space for hidden states when needed 30 | * remove no needed workarounds 31 | 32 | #### Version 0.8.1 33 | 34 | * fix compatibility with Plasma 5.18 (Rodrigo Pedra Brum) 35 | * never hide buttons for AlwaysVisible visibility state 36 | 37 | #### Version 0.8.0 38 | 39 | * fix which plasma theme colors are used for buttons when Colors:Plasma Theme is chosen 40 | * do not show buttons that the current window has disabled them, for example a window is NOT Closable; Close button becomes hidden in such case 41 | * hide buttons when the last active maximized window is minimized and there are no other shown windows 42 | * improve configuration window texts 43 | * create a new decoration only when it is really needed 44 | * reduce filesystem trackers for scheme colors files 45 | * use shared decoration between all buttons 46 | * set an object name for the shared decoration in order to be easily identified by KDecoration3 decorations 47 | 48 | #### Version 0.7.0 49 | 50 | * introduce a new Button Size percentage option and drop thickness margin in order to set the buttons size 51 | * introduce Hidden State in order for the user to choose how buttons should behave when they should not be shown. Currently two states are supported: Slide out and Preserve Empty Space 52 | * introduce a new Color Scheme based on current Plasma Theme used and make it also default 53 | * live preview for changes in the settings window 54 | * do not crash when the selected decoration does not exist in the systemm, for example it was uninstalled 55 | * update buttons for scheme changes 56 | 57 | #### Version 0.6.0 58 | 59 | * new visibility mode: At least one window is shown 60 | * option to draw buttons in inactive state (for both c++ and aurorae decorations) 61 | * fix the current buttons decoration discovery, the user can now change between different decorations and the buttons style is updated runtime 62 | * hide when the last maximized window is closed and the visibility mode is ActiveMaximized 63 | * fix multi-screens behavior for Latte panels 64 | * fix typo that broke builds at some systems 65 | 66 | #### Version 0.5.0 67 | 68 | * provide a relevant background for window buttons in configuration window to fix contrast issues 69 | * support new Latte v0.9 Communicator API 70 | * support new Latte v0.9 Windows Tracking interface when in Latte dock/panel 71 | 72 | #### Version 0.4 73 | 74 | * add new KeepAbove button support (community contribution) 75 | * merge different versions into a single one. One version for all Plasma versions >= 5.12 76 | * close ComboBoxes after clicking 77 | 78 | #### Version 0.3 79 | 80 | * support new Latte coloring and Communicator mechanism 81 | * fix spacing issues with Aurorae themes 82 | 83 | #### Version 0.2 84 | 85 | * Choose Colors to apply a color palette to your window buttons 86 | * Three different Visibility modes, Always Visible/Active Window/Active and Maximized 87 | * Multi-Screen aware, handle active windows only from current screen or from any screen 88 | * Option to activate/deactivate borderless maximized windows and a third System Decide when 89 | the checkbox is partially checked in order to play nice with Latte v0.8 90 | * respect Fitt's Law and include padding and margins when hovering buttons 91 | * fix, update buttons visual settings when the user changes the current decoration settings 92 | * fix, respect all focus out/hover out events 93 | * provide a Plasma 5.12 compatible version 94 | 95 | #### Version 0.1 96 | 97 | * Current mode, in order to automatically update button appearance according to plasma current window decoration 98 | * Choose the decoration theme you would like to use for the buttons 99 | * Support Minimize/Maximize/Close/OnAllDesktops buttons 100 | * Support icon-based Aurorae themes such as **.svg** and **.svgz** 101 | * Identify system's available decorations automatically 102 | * Option to show buttons only when there is an active-maximized window in the current screen 103 | * Slide out/in animation for showing/hiding buttons 104 | * Reorder buttons according to user preference 105 | * Various appearance settings in order to adjust margins. This way you can also change the button size 106 | * Automatically discover Aurorae theme settings in order to make buttons look identical to window buttons 107 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2018 Michail Vourlakos 2 | # SPDX-License-Identifier: GPL-2.0-or-later 3 | cmake_minimum_required(VERSION 3.20 FATAL_ERROR) 4 | project(applet_windowbuttons) 5 | 6 | set(CMAKE_CXX_STANDARD 14) 7 | set(VERSION 0.12.0) 8 | set(AUTHOR "Michail Vourlakos") 9 | set(EMAIL "mvourlakos@gmail.com") 10 | 11 | set(QT_MIN_VERSION "6.6.0") 12 | set(KF6_MIN_VERSION "5.246.0") 13 | set(KDecoration3_MIN_VERSION "6.2.90") 14 | 15 | find_package(ECM ${KF6_MIN_VERSION} REQUIRED NO_MODULE) 16 | set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) 17 | 18 | find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED NO_MODULE COMPONENTS DBus Gui Qml Quick) 19 | find_package(KF6 ${KF6_MIN_VERSION} REQUIRED COMPONENTS CoreAddons Config Declarative Package Svg) 20 | find_package(Plasma "5.90" REQUIRED) 21 | find_package(KDecoration3 ${KDecoration3_MIN_VERSION} REQUIRED) 22 | 23 | include(ECMFindQmlModule) 24 | include(CheckIncludeFiles) 25 | include(KDECMakeSettings) 26 | include(KDEInstallDirs) 27 | 28 | set(KDecoration3_VERSION_MAJOR ${KDecoration3_VERSION_MAJOR}) 29 | set(KDecoration3_VERSION_MINOR ${KDecoration3_VERSION_MINOR}) 30 | 31 | message(STATUS "KDecoration3 VERSION MAJOR : ${KDecoration3_VERSION_MAJOR}") 32 | message(STATUS "KDecoration3 VERSION MINOR : ${KDecoration3_VERSION_MINOR}") 33 | 34 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libappletdecoration/config-decoration.h.cmake 35 | ${CMAKE_CURRENT_BINARY_DIR}/libappletdecoration/config-decoration.h) 36 | 37 | add_subdirectory(libappletdecoration) 38 | plasma_install_package(package org.kde.windowbuttons) 39 | -------------------------------------------------------------------------------- /INSTALLATION.md: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | ## Building from Source 5 | The provided `install.sh` script will build everything and install it for you. Before running the installation script you have to install the dependencies needed for compiling. 6 | 7 | ### Build Dependencies 8 | 9 | - Ubuntu: 10 | ``` 11 | sudo apt install g++ extra-cmake-modules qt6-base-dev qt6-declarative-dev libkf6declarative-dev libkf6plasma-dev kf6-ksvg-dev libkdecorations2-dev gettext 12 | ``` 13 | - Fedora: 14 | ``` 15 | sudo dnf install extra-cmake-modules qt5-qtdeclarative-devel kf5-plasma-devel kf5-kdeclarative-devel kf5-kconfigwidgets-devel kf5-ki18n-devel kdecoration-devel 16 | ``` 17 | - Arch: 18 | ``` 19 | sudo pacman -Syu 20 | sudo pacman -S gcc extra-cmake-modules plasma-framework gettext kdecoration 21 | ``` 22 | 23 | ### Building and Installing 24 | Once you have installed the dependencies listed above you can execute the build and install script: 25 | 26 | ``` 27 | sh install.sh 28 | ``` 29 | 30 | ## Prebuilt Binaries 31 | 32 | - Ubuntu: You can install via a PPA on Ubuntu 18.04 (Bionic) or later including KDE Neon. 33 | ``` 34 | sudo add-apt-repository ppa:krisives/applet-window-buttons 35 | sudo apt install applet-window-buttons 36 | ``` 37 | 38 | - openSUSE: install the package from the official repo 39 | ``` 40 | sudo zypper in applet-window-buttons 41 | ``` 42 | -------------------------------------------------------------------------------- /LICENSES/LicenseRef-KDE-Accepted-GPL.txt: -------------------------------------------------------------------------------- 1 | This library is free software; you can redistribute it and/or 2 | modify it under the terms of the GNU General Public License as 3 | published by the Free Software Foundation; either version 3 of 4 | the license or (at your option) at any later version that is 5 | accepted by the membership of KDE e.V. (or its successor 6 | approved by the membership of KDE e.V.), which shall act as a 7 | proxy as defined in Section 14 of version 3 of the license. 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Window Buttons Applet 2 | 3 | This is a Plasma 5 applet that shows window buttons in your panels. This plasmoid is coming from [Latte land](https://phabricator.kde.org/source/latte-dock/repository/master/) but it can also support Plasma panels. 4 | 5 |

6 |
7 | slide in/out animation 8 |

9 | 10 |

11 |
12 | Breeze decoration 13 |

14 | 15 |

16 |
17 | BreezeEnhanced decoration 18 |

19 | 20 |

21 |
22 | Settings window 23 |

24 | 25 | # Requires 26 | 27 | - Qt >= 5.9 28 | - KF5 >= 5.38 29 | - Plasma >= 5.23.2 30 | - KDecoration2 >= 5.23 31 | 32 | **Qt elements**: Gui Qml Quick 33 | 34 | **KF5 elements**: CoreAddons Declarative Plasma PlasmaQuick extra-cmake-modules 35 | 36 | 37 | # Install 38 | 39 | You can execute `sh install.sh` in the root directory as long as you have installed the previous mentioned development packages. For more details please read [INSTALLATION.md](/INSTALLATION.md) 40 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2018 Michail Vourlakos 2 | # SPDX-License-Identifier: GPL-2.0-or-later 3 | */ 4 | if ! [ -a build ] ; then 5 | mkdir build 6 | fi 7 | cd build 8 | cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -Wnodev .. 9 | make -j$(nproc) 10 | sudo make install 11 | -------------------------------------------------------------------------------- /libappletdecoration/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2018 Michail Vourlakos 2 | # SPDX-License-Identifier: GPL-2.0-or-later 3 | cmake_minimum_required(VERSION 3.10 FATAL_ERROR) 4 | 5 | set(QT_MIN_VERSION "6.6.0") 6 | set(KF6_MIN_VERSION "6.0.0") 7 | 8 | find_package(ECM 0.0.11 REQUIRED NO_MODULE) 9 | set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) 10 | 11 | set(kwin_xml /usr/${KDE_INSTALL_DBUSINTERFACEDIR}/org.kde.KWin.xml) 12 | message(STATUS "KWIN_XML Path : ${kwin_xml}") 13 | set(KWinConfig_SRCS) 14 | qt_add_dbus_interface(KWinConfig_SRCS ${kwin_xml} kwin_interface ) 15 | 16 | set(appletdecoration_SRCS 17 | appletdecorationplugin.cpp 18 | auroraetheme.cpp 19 | buttonsmodel.cpp 20 | commontools.cpp 21 | decorationsmodel.cpp 22 | decorationpalette.cpp 23 | environment.cpp 24 | padding.cpp 25 | previewbutton.cpp 26 | previewbridge.cpp 27 | previewclient.cpp 28 | previewsettings.cpp 29 | previewshareddecoration.cpp 30 | schemecolors.cpp 31 | schemesmodel.cpp 32 | themeextended.cpp 33 | types.cpp 34 | kwinconfig.cpp 35 | ${KWinConfig_SRCS} 36 | ) 37 | 38 | add_library(appletdecorationplugin SHARED ${appletdecoration_SRCS}) 39 | 40 | find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED Quick DBus Widgets) 41 | find_package(KF6 ${KF6_MIN_VERSION} REQUIRED COMPONENTS CoreAddons I18n Service ConfigWidgets KCMUtils) 42 | find_package(KDecoration3 REQUIRED) 43 | 44 | target_link_libraries(appletdecorationplugin 45 | Qt6::Core 46 | Qt6::DBus 47 | Qt6::Widgets 48 | Qt6::Quick 49 | KF6::CoreAddons 50 | KF6::ConfigWidgets 51 | KF6::I18n 52 | Plasma::Plasma 53 | KF6::Service 54 | KF6::Svg 55 | KF6::KCMUtils 56 | KDecoration3::KDecoration 57 | KDecoration3::KDecoration3Private 58 | ) 59 | 60 | # install plugin 61 | install(TARGETS appletdecorationplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/appletdecoration) 62 | 63 | install(DIRECTORY qml/ DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/appletdecoration) 64 | 65 | install(FILES qmldir DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/appletdecoration) 66 | -------------------------------------------------------------------------------- /libappletdecoration/appletdecorationplugin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #include "appletdecorationplugin.h" 10 | 11 | #include "auroraetheme.h" 12 | #include "decorationsmodel.h" 13 | #include "environment.h" 14 | #include "kwinconfig.h" 15 | #include "padding.h" 16 | #include "previewbridge.h" 17 | #include "previewbutton.h" 18 | #include "previewclient.h" 19 | #include "previewsettings.h" 20 | #include "previewshareddecoration.h" 21 | #include "schemesmodel.h" 22 | #include "themeextended.h" 23 | #include "types.h" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | void AppletDecorationPlugin::registerTypes(const char *uri) 30 | { 31 | Q_ASSERT(uri == QLatin1String("org.kde.appletdecoration")); 32 | qmlRegisterUncreatableType(uri, 0, 1, "Types", "Applet decoration types"); 33 | 34 | qmlRegisterType(uri, 0, 1, "AuroraeTheme"); 35 | qmlRegisterType(uri, 0, 1, "Bridge"); 36 | qmlRegisterType(uri, 0, 1, "Settings"); 37 | qmlRegisterType(uri, 0, 1, "Button"); 38 | qmlRegisterType(uri, 0, 1, "DecorationsModel"); 39 | qmlRegisterType(uri, 0, 1, "ColorsModel"); 40 | qmlRegisterType(uri, 0, 1, "SharedDecoration"); 41 | qmlRegisterType(uri, 0, 1, "PlasmaThemeExtended"); 42 | qmlRegisterType(uri, 0, 1, "KWinConfig"); 43 | 44 | qmlRegisterAnonymousType("", 1); 45 | qmlRegisterAnonymousType("", 1); 46 | qmlRegisterAnonymousType("", 1); 47 | qmlRegisterAnonymousType("", 1); 48 | 49 | qmlRegisterSingletonType(uri, 0, 1, "Environment", &Environment::instance); 50 | } 51 | -------------------------------------------------------------------------------- /libappletdecoration/appletdecorationplugin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #ifndef APPLETDECORATIONPLUGIN_H 10 | #define APPLETDECORATIONPLUGIN_H 11 | 12 | #include 13 | 14 | class AppletDecorationPlugin : public QQmlExtensionPlugin 15 | { 16 | Q_OBJECT 17 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") 18 | 19 | public: 20 | void registerTypes(const char *uri) override; 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /libappletdecoration/auroraetheme.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #include "auroraetheme.h" 10 | 11 | #include "commontools.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | static const QString s_auroraeSvgTheme = QStringLiteral("__aurorae__svg__"); 23 | static const QString s_auroraerc = QStringLiteral("auroraerc"); 24 | static int i_buttonSizeStep = 4; 25 | 26 | AuroraeTheme::AuroraeTheme(QObject *parent) : QObject(parent) 27 | { 28 | const auto auroraerc = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + s_auroraerc; 29 | 30 | KDirWatch::self()->addFile(auroraerc); 31 | 32 | connect(KDirWatch::self(), &KDirWatch::dirty, this, &AuroraeTheme::auroraeRCChanged); 33 | connect(KDirWatch::self(), &KDirWatch::created, this, &AuroraeTheme::auroraeRCChanged); 34 | 35 | connect(this, &AuroraeTheme::themeChanged, this, &AuroraeTheme::loadSettings); 36 | } 37 | 38 | AuroraeTheme::~AuroraeTheme() 39 | { 40 | } 41 | 42 | int AuroraeTheme::buttonWidth() const 43 | { 44 | int f = (int) m_buttonSize; 45 | return m_buttonWidth + ((f - 1) * i_buttonSizeStep); 46 | } 47 | 48 | int AuroraeTheme::buttonHeight() const 49 | { 50 | int f = (int) m_buttonSize; 51 | 52 | return m_buttonHeight + ((f - 1) * i_buttonSizeStep); 53 | } 54 | 55 | int AuroraeTheme::buttonSpacing() const 56 | { 57 | return m_buttonSpacing; 58 | } 59 | 60 | int AuroraeTheme::duration() const 61 | { 62 | return m_duration; 63 | } 64 | 65 | float AuroraeTheme::buttonRatio() const 66 | { 67 | return ((float) m_buttonWidth / (float) m_buttonHeight); 68 | } 69 | 70 | QString AuroraeTheme::theme() const 71 | { 72 | return m_theme; 73 | } 74 | 75 | void AuroraeTheme::setTheme(QString theme) 76 | { 77 | if (m_theme == theme || theme.isEmpty()) 78 | { 79 | return; 80 | } 81 | 82 | m_theme = theme; 83 | updateAurorae(theme); 84 | 85 | emit themeChanged(); 86 | } 87 | 88 | QString AuroraeTheme::themeName() const 89 | { 90 | return m_themeName; 91 | } 92 | 93 | QString AuroraeTheme::themePath() const 94 | { 95 | return m_themePath; 96 | } 97 | 98 | QString AuroraeTheme::themeType() const 99 | { 100 | return m_themeType; 101 | } 102 | 103 | QColor AuroraeTheme::titleBackgroundColor() const 104 | { 105 | return m_titleBackgroundColor; 106 | } 107 | 108 | bool AuroraeTheme::hasMonochromeIcons() const 109 | { 110 | return m_hasMonochromeIcons; 111 | } 112 | 113 | bool AuroraeTheme::hasRestoreButton() const 114 | { 115 | return m_hasRestoreButton; 116 | } 117 | 118 | QString AuroraeTheme::monochromePrefix() const 119 | { 120 | return m_monochromePrefix; 121 | } 122 | 123 | void AuroraeTheme::auroraeRCChanged(const QString &filename) 124 | { 125 | if (!filename.endsWith(s_auroraerc)) 126 | return; 127 | 128 | loadSettings(); 129 | } 130 | 131 | void AuroraeTheme::updateAurorae(const QString &themeName) 132 | { 133 | const QString separator("__"); 134 | const QString name = themeName.section(separator, -1, -1); 135 | QString path = standardPath("aurorae/themes/" + name); 136 | 137 | if (QFileInfo(path + "/close.svg").exists()) 138 | m_themeType = "svg"; 139 | else if (QFileInfo(path + "/close.svgz").exists()) 140 | m_themeType = "svgz"; 141 | else if (QFileInfo(path + "/close.png").exists()) 142 | m_themeType = "png"; 143 | else 144 | m_themeType = "svg"; 145 | 146 | m_hasRestoreButton = QFileInfo(path + "/restore." + m_themeType).exists(); 147 | 148 | m_themeName = name; 149 | m_themePath = path; 150 | } 151 | 152 | void AuroraeTheme::loadSettings() 153 | { 154 | const QString rc(m_themePath + "/" + m_themeName + "rc"); 155 | 156 | if (!QFileInfo(rc).exists()) 157 | { 158 | return; 159 | } 160 | 161 | const auto auroraerc = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + s_auroraerc; 162 | 163 | if (QFileInfo(auroraerc).exists()) 164 | { 165 | KSharedConfigPtr auroraePtr = KSharedConfig::openConfig(auroraerc); 166 | 167 | const KConfigGroup themeGroup = KConfigGroup(auroraePtr, m_themeName); 168 | m_buttonSize = static_cast(themeGroup.readEntry("ButtonSize", (int) Types::NormalButton)); 169 | } 170 | else 171 | { 172 | m_buttonSize = Types::NormalButton; 173 | } 174 | 175 | KSharedConfigPtr rcPtr = KSharedConfig::openConfig(rc); 176 | 177 | const KConfigGroup generalGroup = KConfigGroup(rcPtr, u"General"_qs); 178 | const KConfigGroup layoutGroup = KConfigGroup(rcPtr, u"Layout"_qs); 179 | 180 | m_duration = generalGroup.readEntry("Animation", 0); 181 | m_buttonWidth = layoutGroup.readEntry("ButtonWidth", 24); 182 | m_buttonHeight = layoutGroup.readEntry("ButtonHeight", 24); 183 | m_buttonSpacing = layoutGroup.readEntry("ButtonSpacing", 2); 184 | 185 | QString monoprefix = generalGroup.readEntry("MonochromeIconsPrefix", ""); 186 | 187 | if (!monoprefix.isEmpty()) 188 | { 189 | m_hasMonochromeIcons = true; 190 | m_monochromePrefix = (monoprefix == "*" ? "" : monoprefix); 191 | } 192 | else 193 | { 194 | m_hasMonochromeIcons = false; 195 | m_monochromePrefix = ""; 196 | } 197 | 198 | parseThemeImages(); 199 | 200 | emit settingsChanged(); 201 | } 202 | 203 | void AuroraeTheme::parseThemeImages() 204 | { 205 | QString origBackgroundFilePath = m_themePath + "/decoration." + m_themeType; 206 | 207 | if (!QFileInfo(origBackgroundFilePath).exists()) 208 | { 209 | qDebug() << "Aurorare decoration file was not found for theme: " << m_themeName; 210 | return; 211 | } 212 | 213 | KSvg::Svg *svg = new KSvg::Svg(this); 214 | svg->setImagePath(origBackgroundFilePath); 215 | svg->resize(50, 50); 216 | QImage img = svg->image(QSize(50, 50), "decoration-top"); 217 | 218 | int maxOpacity = -1; 219 | 220 | for (int y = 49; y >= 0; --y) 221 | { 222 | for (int x = 0; x < 50; ++x) 223 | { 224 | QRgb pix = img.pixel(x, y); 225 | int opacity = qAlpha(pix); 226 | 227 | //! the equality returns better results for more aurorae themes 228 | if (maxOpacity <= opacity) 229 | { 230 | maxOpacity = opacity; 231 | m_titleBackgroundColor = QColor(qRed(pix), qGreen(pix), qBlue(pix)); 232 | } 233 | } 234 | } 235 | 236 | svg->deleteLater(); 237 | } 238 | -------------------------------------------------------------------------------- /libappletdecoration/auroraetheme.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #ifndef AURORAETHEME_H 10 | #define AURORAETHEME_H 11 | 12 | #include "types.h" 13 | 14 | #include 15 | #include 16 | 17 | class AuroraeTheme : public QObject 18 | { 19 | Q_OBJECT 20 | Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged) 21 | Q_PROPERTY(QString themeName READ themeName NOTIFY themeChanged) 22 | Q_PROPERTY(QString themePath READ themePath NOTIFY themeChanged) 23 | Q_PROPERTY(QString themeType READ themeType NOTIFY themeChanged) 24 | 25 | Q_PROPERTY(int buttonHeight READ buttonHeight NOTIFY settingsChanged) 26 | Q_PROPERTY(int buttonWidth READ buttonWidth NOTIFY settingsChanged) 27 | Q_PROPERTY(int buttonSpacing READ buttonSpacing NOTIFY settingsChanged) 28 | Q_PROPERTY(int duration READ duration NOTIFY settingsChanged) 29 | 30 | Q_PROPERTY(float buttonRatio READ buttonRatio NOTIFY settingsChanged) 31 | 32 | Q_PROPERTY(QColor titleBackgroundColor READ titleBackgroundColor NOTIFY settingsChanged) 33 | 34 | Q_PROPERTY(bool hasRestoreButton READ hasRestoreButton NOTIFY settingsChanged) 35 | 36 | Q_PROPERTY(bool hasMonochromeIcons READ hasMonochromeIcons NOTIFY settingsChanged) 37 | Q_PROPERTY(QString monochromePrefix READ monochromePrefix NOTIFY settingsChanged) 38 | 39 | public: 40 | explicit AuroraeTheme(QObject *parent = nullptr); 41 | ~AuroraeTheme() override; 42 | ; 43 | 44 | QString theme() const; 45 | void setTheme(QString theme); 46 | 47 | QString themeName() const; 48 | QString themePath() const; 49 | QString themeType() const; 50 | 51 | int buttonHeight() const; 52 | int buttonWidth() const; 53 | int buttonSpacing() const; 54 | int duration() const; 55 | 56 | float buttonRatio() const; 57 | 58 | QColor titleBackgroundColor() const; 59 | 60 | bool hasRestoreButton() const; 61 | 62 | bool hasMonochromeIcons() const; 63 | QString monochromePrefix() const; 64 | 65 | signals: 66 | void settingsChanged(); 67 | void themeChanged(); 68 | 69 | private slots: 70 | void parseThemeImages(); 71 | void auroraeRCChanged(const QString &filename); 72 | 73 | private: 74 | void loadSettings(); 75 | void updateAurorae(const QString &themeName); 76 | 77 | private: 78 | bool m_hasMonochromeIcons{ false }; 79 | bool m_hasRestoreButton{ false }; 80 | 81 | int m_buttonHeight{ 24 }; 82 | int m_buttonWidth{ 24 }; 83 | int m_buttonSpacing{ 2 }; 84 | int m_duration{ 0 }; 85 | 86 | Types::ButtonSize m_buttonSize{ Types::NormalButton }; // Normal size 87 | 88 | QString m_theme; 89 | QString m_themeName; 90 | QString m_themePath; 91 | QString m_themeType; 92 | 93 | QString m_monochromePrefix; 94 | 95 | QColor m_titleBackgroundColor; 96 | }; 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /libappletdecoration/buttonsmodel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2014 Martin Gräßlin 3 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 4 | * 5 | * This file is part of the libappletdecoration library 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 8 | */ 9 | 10 | #include "buttonsmodel.h" 11 | 12 | #include 13 | #include 14 | 15 | ButtonsModel::ButtonsModel(const QVector &buttons, QObject *parent) : QAbstractListModel(parent), m_buttons(buttons) 16 | { 17 | } 18 | 19 | ButtonsModel::ButtonsModel(QObject *parent) 20 | : ButtonsModel(QVector({ 21 | KDecoration3::DecorationButtonType::Menu, 22 | KDecoration3::DecorationButtonType::ApplicationMenu, 23 | KDecoration3::DecorationButtonType::OnAllDesktops, 24 | KDecoration3::DecorationButtonType::Minimize, 25 | KDecoration3::DecorationButtonType::Maximize, 26 | KDecoration3::DecorationButtonType::Close, 27 | KDecoration3::DecorationButtonType::ContextHelp, 28 | KDecoration3::DecorationButtonType::Shade, 29 | KDecoration3::DecorationButtonType::KeepBelow, 30 | KDecoration3::DecorationButtonType::KeepAbove, 31 | }), 32 | parent) 33 | { 34 | } 35 | 36 | ButtonsModel::~ButtonsModel() = default; 37 | 38 | int ButtonsModel::rowCount(const QModelIndex &parent) const 39 | { 40 | if (parent.isValid()) 41 | { 42 | return 0; 43 | } 44 | 45 | return m_buttons.count(); 46 | } 47 | 48 | static QString buttonToName(KDecoration3::DecorationButtonType type) 49 | { 50 | switch (type) 51 | { 52 | case KDecoration3::DecorationButtonType::Menu: return i18n("Menu"); 53 | case KDecoration3::DecorationButtonType::ApplicationMenu: return i18n("Application menu"); 54 | case KDecoration3::DecorationButtonType::OnAllDesktops: return i18n("On all desktops"); 55 | case KDecoration3::DecorationButtonType::Minimize: return i18n("Minimize"); 56 | case KDecoration3::DecorationButtonType::Maximize: return i18n("Maximize"); 57 | case KDecoration3::DecorationButtonType::Close: return i18n("Close"); 58 | case KDecoration3::DecorationButtonType::ContextHelp: return i18n("Context help"); 59 | case KDecoration3::DecorationButtonType::Shade: return i18n("Shade"); 60 | case KDecoration3::DecorationButtonType::KeepBelow: return i18n("Keep below"); 61 | case KDecoration3::DecorationButtonType::KeepAbove: return i18n("Keep above"); 62 | default: return QString(); 63 | } 64 | } 65 | 66 | QVariant ButtonsModel::data(const QModelIndex &index, int role) const 67 | { 68 | if (!index.isValid() || index.row() < 0 || index.row() >= m_buttons.count() || index.column() != 0) 69 | return QVariant(); 70 | 71 | const auto &button = m_buttons.at(index.row()); 72 | 73 | switch (role) 74 | { 75 | case Qt::DisplayRole: return buttonToName(button); 76 | case Qt::UserRole: return QVariant::fromValue(int(button)); 77 | } 78 | 79 | return QVariant(); 80 | } 81 | 82 | QHash ButtonsModel::roleNames() const 83 | { 84 | QHash roles; 85 | roles.insert(Qt::DisplayRole, QByteArrayLiteral("display")); 86 | roles.insert(Qt::UserRole, QByteArrayLiteral("button")); 87 | return roles; 88 | } 89 | 90 | void ButtonsModel::remove(int row) 91 | { 92 | if (row < 0 || row >= m_buttons.count()) 93 | return; 94 | 95 | beginRemoveRows(QModelIndex(), row, row); 96 | m_buttons.removeAt(row); 97 | endRemoveRows(); 98 | } 99 | 100 | void ButtonsModel::down(int index) 101 | { 102 | if (m_buttons.count() < 2 || index == m_buttons.count() - 1) 103 | return; 104 | 105 | beginMoveRows(QModelIndex(), index, index, QModelIndex(), index + 2); 106 | m_buttons.insert(index + 1, m_buttons.takeAt(index)); 107 | endMoveRows(); 108 | } 109 | 110 | void ButtonsModel::up(int index) 111 | { 112 | if (m_buttons.count() < 2 || index == 0) 113 | return; 114 | 115 | beginMoveRows(QModelIndex(), index, index, QModelIndex(), index - 1); 116 | m_buttons.insert(index - 1, m_buttons.takeAt(index)); 117 | endMoveRows(); 118 | } 119 | 120 | void ButtonsModel::add(KDecoration3::DecorationButtonType type) 121 | { 122 | beginInsertRows(QModelIndex(), m_buttons.count(), m_buttons.count()); 123 | m_buttons.append(type); 124 | endInsertRows(); 125 | } 126 | 127 | void ButtonsModel::add(int index, int type) 128 | { 129 | beginInsertRows(QModelIndex(), index + 1, index + 1); 130 | m_buttons.insert(index + 1, KDecoration3::DecorationButtonType(type)); 131 | endInsertRows(); 132 | } 133 | 134 | void ButtonsModel::move(int sourceIndex, int targetIndex) 135 | { 136 | if (sourceIndex == qMax(0, targetIndex)) 137 | { 138 | return; 139 | } 140 | 141 | /* When moving an item down, the destination index needs to be incremented 142 | by one, as explained in the documentation: 143 | http://doc.qt.nokia.com/qabstractitemmodel.html#beginMoveRows */ 144 | if (targetIndex > sourceIndex) 145 | { 146 | // Row will be moved down 147 | beginMoveRows(QModelIndex(), sourceIndex, sourceIndex, QModelIndex(), targetIndex + 1); 148 | } 149 | else 150 | { 151 | beginMoveRows(QModelIndex(), sourceIndex, sourceIndex, QModelIndex(), qMax(0, targetIndex)); 152 | } 153 | 154 | m_buttons.move(sourceIndex, qMax(0, targetIndex)); 155 | endMoveRows(); 156 | } 157 | -------------------------------------------------------------------------------- /libappletdecoration/buttonsmodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2014 Martin Gräßlin 3 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 4 | * 5 | * This file is part of the libappletdecoration library 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 8 | */ 9 | 10 | #ifndef KDECOARTIONS_PREVIEW_BUTTONS_MODEL_H 11 | #define KDECOARTIONS_PREVIEW_BUTTONS_MODEL_H 12 | 13 | #include 14 | #include 15 | 16 | class PreviewBridge; 17 | 18 | class ButtonsModel : public QAbstractListModel 19 | { 20 | Q_OBJECT 21 | public: 22 | explicit ButtonsModel(const QVector &buttons, QObject *parent = 0); 23 | explicit ButtonsModel(QObject *parent = nullptr); 24 | virtual ~ButtonsModel(); 25 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 26 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 27 | QHash roleNames() const override; 28 | 29 | QVector buttons() const 30 | { 31 | return m_buttons; 32 | } 33 | 34 | Q_INVOKABLE void remove(int index); 35 | Q_INVOKABLE void up(int index); 36 | Q_INVOKABLE void down(int index); 37 | Q_INVOKABLE void move(int sourceIndex, int targetIndex); 38 | 39 | void add(KDecoration3::DecorationButtonType type); 40 | Q_INVOKABLE void add(int index, int type); 41 | 42 | private: 43 | QVector m_buttons; 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /libappletdecoration/commontools.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | * 8 | */ 9 | 10 | #include "commontools.h" 11 | 12 | #include 13 | #include 14 | 15 | QString standardPath(QString subPath, bool localfirst) 16 | { 17 | QStringList paths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); 18 | 19 | if (localfirst) 20 | { 21 | for (const auto &pt : paths) 22 | { 23 | QString ptF = pt + "/" + subPath; 24 | if (QFileInfo(ptF).exists()) 25 | { 26 | return ptF; 27 | } 28 | } 29 | } 30 | else 31 | { 32 | for (int i = paths.count() - 1; i >= 0; i--) 33 | { 34 | QString ptF = paths[i] + "/" + subPath; 35 | if (QFileInfo(ptF).exists()) 36 | { 37 | return ptF; 38 | } 39 | } 40 | } 41 | 42 | //! in any case that above fails 43 | if (QFileInfo("/usr/share/" + subPath).exists()) 44 | { 45 | return "/usr/share/" + subPath; 46 | } 47 | 48 | return ""; 49 | } 50 | 51 | QStringList standardPaths(bool localfirst) 52 | { 53 | QStringList paths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); 54 | 55 | if (localfirst) 56 | { 57 | return paths; 58 | } 59 | else 60 | { 61 | QStringList reversed; 62 | 63 | for (int i = paths.count() - 1; i >= 0; i--) 64 | { 65 | reversed << paths[i]; 66 | } 67 | 68 | return reversed; 69 | } 70 | } 71 | 72 | QStringList standardPathsFor(QString subPath, bool localfirst) 73 | { 74 | QStringList paths = standardPaths(localfirst); 75 | 76 | QString separator = subPath.startsWith("/") ? "" : "/"; 77 | 78 | for (int i = 0; i < paths.count(); ++i) 79 | { 80 | paths[i] = paths[i] + separator + subPath; 81 | } 82 | 83 | return paths; 84 | } 85 | -------------------------------------------------------------------------------- /libappletdecoration/commontools.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2019 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | * 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | //! returns the standard path found that contains the subPath 14 | //! local paths have higher priority by default 15 | QString standardPath(QString subPath, bool localFirst = true); 16 | 17 | QStringList standardPaths(bool localfirst = true); 18 | QStringList standardPathsFor(QString subPath, bool localfirst = true); 19 | -------------------------------------------------------------------------------- /libappletdecoration/config-decoration.h.cmake: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_DECORATION_H 2 | #define CONFIG_DECORATION_H 3 | 4 | #cmakedefine KDecoration3_VERSION_MAJOR @KDecoration3_VERSION_MAJOR@ 5 | #cmakedefine KDecoration3_VERSION_MINOR @KDecoration3_VERSION_MINOR@ 6 | 7 | #endif // CONFIG_DECORATION_H 8 | -------------------------------------------------------------------------------- /libappletdecoration/decorationpalette.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************** 2 | KWin - the KDE window manager 3 | This file is part of the KDE project. 4 | 5 | SPDX-FileCopyrightText: 2014 Martin Gräßlin 6 | SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa 7 | SPDX-FileCopyrightText: 2015 Mika Allan Rauhala 8 | 9 | SPDX-License-Identifier: GPL-2.0-or-later 10 | *********************************************************************/ 11 | 12 | #include "decorationpalette.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | DecorationPalette::DecorationPalette(const QString &colorScheme) 23 | : m_colorScheme(QFileInfo(colorScheme).isAbsolute() ? colorScheme : QStandardPaths::locate(QStandardPaths::GenericConfigLocation, colorScheme)) 24 | { 25 | if (m_colorScheme.isEmpty() && colorScheme == QStringLiteral("kdeglobals")) 26 | { 27 | // kdeglobals doesn't exist so create it. This is needed to monitor it using QFileSystemWatcher. 28 | auto config = KSharedConfig::openConfig(colorScheme, KConfig::SimpleConfig); 29 | KConfigGroup wmConfig(config, QStringLiteral("WM")); 30 | wmConfig.writeEntry("FakeEntryToKeepThisGroup", true); 31 | config->sync(); 32 | 33 | m_colorScheme = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, colorScheme); 34 | } 35 | 36 | m_watcher.addPath(m_colorScheme); 37 | connect(&m_watcher, &QFileSystemWatcher::fileChanged, [this]() { m_watcher.addPath(m_colorScheme), update(), emit changed(); }); 38 | update(); 39 | } 40 | 41 | bool DecorationPalette::isValid() const 42 | { 43 | return m_activeTitleBarColor.isValid(); 44 | } 45 | 46 | QColor DecorationPalette::color(KDecoration3::ColorGroup group, KDecoration3::ColorRole role) const 47 | { 48 | using KDecoration3::ColorGroup; 49 | using KDecoration3::ColorRole; 50 | 51 | switch (role) 52 | { 53 | case ColorRole::Frame: 54 | { 55 | switch (group) 56 | { 57 | case ColorGroup::Active: return m_activeFrameColor; 58 | case ColorGroup::Inactive: return m_inactiveFrameColor; 59 | default: break; 60 | } 61 | break; 62 | } 63 | case ColorRole::TitleBar: 64 | { 65 | switch (group) 66 | { 67 | case ColorGroup::Active: return m_activeTitleBarColor; 68 | case ColorGroup::Inactive: return m_inactiveTitleBarColor; 69 | default: break; 70 | } 71 | break; 72 | } 73 | 74 | case ColorRole::Foreground: 75 | { 76 | switch (group) 77 | { 78 | case ColorGroup::Active: return m_activeForegroundColor; 79 | case ColorGroup::Inactive: return m_inactiveForegroundColor; 80 | case ColorGroup::Warning: return m_warningForegroundColor; 81 | default: break; 82 | } 83 | } 84 | default: break; 85 | } 86 | 87 | return QColor(); 88 | } 89 | 90 | QPalette DecorationPalette::palette() const 91 | { 92 | return m_palette; 93 | } 94 | 95 | void DecorationPalette::update() 96 | { 97 | auto config = KSharedConfig::openConfig(m_colorScheme, KConfig::SimpleConfig); 98 | KConfigGroup wmConfig(config, QStringLiteral("WM")); 99 | 100 | if (!wmConfig.exists() && !m_colorScheme.endsWith(QStringLiteral("/kdeglobals"))) 101 | { 102 | qDebug() << "Invalid color scheme" << m_colorScheme << "lacks WM group"; 103 | return; 104 | } 105 | 106 | m_palette = KColorScheme::createApplicationPalette(config); 107 | 108 | m_activeFrameColor = wmConfig.readEntry("frame", m_palette.color(QPalette::Active, QPalette::Base)); // !! TODO: Base? 109 | m_inactiveFrameColor = wmConfig.readEntry("inactiveFrame", m_activeFrameColor); 110 | m_activeTitleBarColor = wmConfig.readEntry("activeBackground", m_palette.color(QPalette::Active, QPalette::Highlight)); 111 | m_inactiveTitleBarColor = wmConfig.readEntry("inactiveBackground", m_inactiveFrameColor); 112 | m_activeForegroundColor = wmConfig.readEntry("activeForeground", m_palette.color(QPalette::Active, QPalette::HighlightedText)); 113 | m_inactiveForegroundColor = wmConfig.readEntry("inactiveForeground", m_activeForegroundColor.darker()); 114 | 115 | KConfigGroup windowColorsConfig(config, QStringLiteral("Colors:Window")); 116 | m_warningForegroundColor = windowColorsConfig.readEntry("ForegroundNegative", QColor(237, 21, 2)); 117 | } 118 | -------------------------------------------------------------------------------- /libappletdecoration/decorationpalette.h: -------------------------------------------------------------------------------- 1 | /******************************************************************** 2 | KWin - the KDE window manager 3 | This file is part of the KDE project. 4 | 5 | SPDX-FileCopyrightText: 2014 Martin Gräßlin 6 | SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa 7 | SPDX-FileCopyrightText: 2015 Mika Allan Rauhala 8 | 9 | SPDX-License-Identifier: GPL-2.0-or-later 10 | *********************************************************************/ 11 | 12 | #ifndef KWIN_DECORATION_PALETTE_H 13 | #define KWIN_DECORATION_PALETTE_H 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | class DecorationPalette : public QObject 20 | { 21 | Q_OBJECT 22 | public: 23 | DecorationPalette(const QString &colorScheme); 24 | 25 | bool isValid() const; 26 | 27 | QColor color(KDecoration3::ColorGroup group, KDecoration3::ColorRole role) const; 28 | QPalette palette() const; 29 | 30 | Q_SIGNALS: 31 | void changed(); 32 | 33 | private: 34 | void update(); 35 | 36 | QString m_colorScheme; 37 | QFileSystemWatcher m_watcher; 38 | 39 | QPalette m_palette; 40 | 41 | QColor m_activeTitleBarColor; 42 | QColor m_inactiveTitleBarColor; 43 | 44 | QColor m_activeFrameColor; 45 | QColor m_inactiveFrameColor; 46 | 47 | QColor m_activeForegroundColor; 48 | QColor m_inactiveForegroundColor; 49 | QColor m_warningForegroundColor; 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /libappletdecoration/decorationsmodel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2014 Martin Gräßlin 3 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 4 | * 5 | * This file is part of the libappletdecoration library 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 8 | */ 9 | 10 | #include "decorationsmodel.h" 11 | 12 | #include "previewbridge.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | Q_LOGGING_CATEGORY(decorations_model, "DecorationsModel"); 27 | 28 | static const QString s_defaultPlugin = QStringLiteral("org.kde.breeze"); 29 | static const QString s_defaultTheme; 30 | static const QString s_auroraePlugin = QStringLiteral("org.kde.kwin.aurorae"); 31 | static const QString s_auroraeSvgTheme = QStringLiteral("__aurorae__svg__"); 32 | 33 | static const QString s_kwinrc = QStringLiteral("kwinrc"); 34 | static const QString s_pluginName = QStringLiteral("org.kde.kdecoration3"); 35 | 36 | DecorationsModel::DecorationsModel(QObject *parent) : QAbstractListModel(parent) 37 | { 38 | init(); 39 | loadCurrents(); 40 | 41 | const auto kwinRc = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + s_kwinrc; 42 | 43 | KDirWatch::self()->addFile(kwinRc); 44 | 45 | connect(KDirWatch::self(), &KDirWatch::dirty, this, &DecorationsModel::kwinChanged); 46 | connect(KDirWatch::self(), &KDirWatch::created, this, &DecorationsModel::kwinChanged); 47 | } 48 | 49 | DecorationsModel::~DecorationsModel() = default; 50 | 51 | int DecorationsModel::count() const 52 | { 53 | return m_plugins.size(); 54 | } 55 | 56 | QString DecorationsModel::currentPlugin() const 57 | { 58 | return m_currentPlugin; 59 | } 60 | 61 | void DecorationsModel::setCurrentPlugin(QString plugin) 62 | { 63 | if (m_currentPlugin == plugin) 64 | { 65 | return; 66 | } 67 | 68 | m_currentPlugin = plugin; 69 | emit currentPluginChanged(); 70 | } 71 | 72 | QString DecorationsModel::currentTheme() const 73 | { 74 | return m_currentTheme; 75 | } 76 | 77 | void DecorationsModel::setCurrentTheme(QString theme) 78 | { 79 | if (m_currentTheme == theme) 80 | { 81 | return; 82 | } 83 | 84 | m_currentTheme = theme; 85 | emit currentThemeChanged(); 86 | } 87 | 88 | int DecorationsModel::rowCount(const QModelIndex &parent) const 89 | { 90 | if (parent.isValid()) 91 | { 92 | return 0; 93 | } 94 | 95 | return m_plugins.size(); 96 | } 97 | 98 | QVariant DecorationsModel::data(const QModelIndex &index, int role) const 99 | { 100 | if (!index.isValid() || index.column() != 0 || index.row() < 0 || index.row() >= int(m_plugins.size())) 101 | { 102 | return QVariant(); 103 | } 104 | 105 | const Data &d = m_plugins.at(index.row()); 106 | 107 | switch (role) 108 | { 109 | case Qt::DisplayRole: return d.visibleName; 110 | case Qt::UserRole + 4: return d.pluginName; 111 | case Qt::UserRole + 5: return d.themeName; 112 | case Qt::UserRole + 6: return d.isAuroraeTheme; 113 | case Qt::UserRole + 7: return d.configuration; 114 | } 115 | 116 | return QVariant(); 117 | } 118 | 119 | QHash DecorationsModel::roleNames() const 120 | { 121 | QHash roles({ { Qt::DisplayRole, QByteArrayLiteral("display") }, 122 | { Qt::UserRole + 4, QByteArrayLiteral("plugin") }, 123 | { Qt::UserRole + 5, QByteArrayLiteral("theme") }, 124 | { Qt::UserRole + 6, QByteArrayLiteral("isAuroraeTheme") }, 125 | { Qt::UserRole + 7, QByteArrayLiteral("configureable") } }); 126 | return roles; 127 | } 128 | 129 | static bool isThemeEngine(const QVariantMap &decoSettingsMap) 130 | { 131 | return decoSettingsMap["themes"].toBool(); 132 | } 133 | 134 | static bool isConfigureable(const QVariantMap &decoSettingsMap) 135 | { 136 | return decoSettingsMap["kcmodule"].toBool(); 137 | } 138 | 139 | static QString themeListKeyword(const QVariantMap &decoSettingsMap) 140 | { 141 | return decoSettingsMap["themeListKeyword"].toString(); 142 | } 143 | 144 | static QString findKNewStuff(const QVariantMap &decoSettingsMap) 145 | { 146 | return decoSettingsMap["KNewStuff"].toString(); 147 | } 148 | 149 | void DecorationsModel::init() 150 | { 151 | beginResetModel(); 152 | m_plugins.clear(); 153 | 154 | const auto plugins = KPluginMetaData::findPlugins(s_pluginName); 155 | for (const auto &info : plugins) 156 | { 157 | const auto decoSettingsMap = info.rawData().value("org.kde.kdecoration3").toObject().toVariantMap(); 158 | 159 | const QString &kns = findKNewStuff(decoSettingsMap); 160 | if (!kns.isEmpty() && !m_knsProvides.contains(kns)) 161 | m_knsProvides.insert(kns, info.name().isEmpty() ? info.pluginId() : info.name()); 162 | 163 | if (isThemeEngine(decoSettingsMap)) 164 | { 165 | const QString keyword = themeListKeyword(decoSettingsMap); 166 | if (keyword.isNull()) 167 | { 168 | // We cannot list the themes 169 | qWarning() << "No theme list keyword for" << info.pluginId(); 170 | continue; 171 | } 172 | 173 | const auto themeProvider = KPluginFactory::instantiatePlugin(info).plugin; 174 | for (const auto &t : themeProvider->themes()) 175 | { 176 | Data data; 177 | data.pluginName = t.pluginId(); 178 | data.themeName = t.themeName(); 179 | data.visibleName = t.visibleName(); 180 | 181 | if (data.pluginName == s_auroraePlugin && data.themeName.startsWith(s_auroraeSvgTheme)) 182 | data.isAuroraeTheme = true; 183 | 184 | qCInfo(decorations_model) << "Adding theme" << data.visibleName << "from" << data.pluginName; 185 | m_plugins.emplace_back(std::move(data)); 186 | } 187 | } 188 | else 189 | { 190 | 191 | const Data data{ 192 | .pluginName = info.pluginId(), 193 | .themeName = QString(), 194 | .visibleName = info.name().isEmpty() ? info.pluginId() : info.name(), 195 | .isAuroraeTheme = false, 196 | .configuration = isConfigureable(decoSettingsMap), 197 | }; 198 | 199 | qCInfo(decorations_model) << "Adding theme" << data.visibleName << "from" << data.pluginName; 200 | m_plugins.emplace_back(std::move(data)); 201 | } 202 | } 203 | endResetModel(); 204 | } 205 | 206 | void DecorationsModel::loadCurrents() 207 | { 208 | const KConfigGroup config = KSharedConfig::openConfig(s_kwinrc)->group(s_pluginName); 209 | const QString plugin = config.readEntry("library", s_defaultPlugin); 210 | const QString theme = config.readEntry("theme", s_defaultTheme); 211 | 212 | bool exists{ false }; 213 | bool isAur{ isAurorae(plugin, theme) }; 214 | 215 | if ((!isAur && pluginExists(plugin)) || (isAur && decorationExists(plugin, theme))) 216 | { 217 | exists = true; 218 | } 219 | 220 | setCurrentPlugin(exists ? plugin : s_defaultPlugin); 221 | setCurrentTheme(exists ? theme : s_defaultTheme); 222 | } 223 | 224 | void DecorationsModel::kwinChanged(const QString &filename) 225 | { 226 | if (!filename.endsWith(s_kwinrc)) 227 | { 228 | return; 229 | } 230 | 231 | loadCurrents(); 232 | } 233 | 234 | bool DecorationsModel::isAurorae(const QString &plugin, const QString &theme) 235 | { 236 | auto it = std::find_if(m_plugins.cbegin(), m_plugins.cend(), [plugin, theme](const Data &d) { return d.pluginName == plugin && d.themeName == theme; }); 237 | 238 | if (it == m_plugins.cend()) 239 | { 240 | return false; 241 | } 242 | 243 | return (*it).isAuroraeTheme; 244 | } 245 | 246 | bool DecorationsModel::decorationExists(const QString &plugin, const QString &theme) 247 | { 248 | auto it = std::find_if(m_plugins.cbegin(), m_plugins.cend(), [plugin, theme](const Data &d) { return d.pluginName == plugin && d.themeName == theme; }); 249 | 250 | if (it == m_plugins.cend()) 251 | { 252 | return false; 253 | } 254 | 255 | return true; 256 | } 257 | 258 | bool DecorationsModel::pluginExists(const QString &plugin) 259 | { 260 | auto it = std::find_if(m_plugins.cbegin(), m_plugins.cend(), [plugin](const Data &d) { return d.pluginName == plugin; }); 261 | 262 | if (it == m_plugins.cend()) 263 | { 264 | return false; 265 | } 266 | 267 | return true; 268 | } 269 | 270 | QModelIndex DecorationsModel::findDecoration(const QString &pluginName, const QString &themeName) const 271 | { 272 | auto it = 273 | std::find_if(m_plugins.cbegin(), m_plugins.cend(), [pluginName, themeName](const Data &d) { return d.pluginName == pluginName && d.themeName == themeName; }); 274 | 275 | if (it == m_plugins.cend()) 276 | { 277 | return QModelIndex(); 278 | } 279 | 280 | const auto distance = std::distance(m_plugins.cbegin(), it); 281 | return createIndex(distance, 0); 282 | } 283 | -------------------------------------------------------------------------------- /libappletdecoration/decorationsmodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2014 Martin Gräßlin 3 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 4 | * 5 | * This file is part of the libappletdecoration library 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 8 | */ 9 | 10 | #ifndef DECORATIONSMODEL_H 11 | #define DECORATIONSMODEL_H 12 | 13 | #include 14 | 15 | class DecorationsModel : public QAbstractListModel 16 | { 17 | Q_OBJECT 18 | Q_PROPERTY(int count READ count NOTIFY countChanged) 19 | Q_PROPERTY(QString currentPlugin READ currentPlugin NOTIFY currentPluginChanged) 20 | Q_PROPERTY(QString currentTheme READ currentTheme NOTIFY currentThemeChanged) 21 | 22 | public: 23 | explicit DecorationsModel(QObject *parent = nullptr); 24 | virtual ~DecorationsModel(); 25 | 26 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 27 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 28 | QHash roleNames() const override; 29 | 30 | QModelIndex findDecoration(const QString &pluginName, const QString &themeName = QString()) const; 31 | 32 | QMap knsProviders() const 33 | { 34 | return m_knsProvides; 35 | } 36 | 37 | int count() const; 38 | 39 | QString currentPlugin() const; 40 | QString currentTheme() const; 41 | 42 | public Q_SLOTS: 43 | Q_INVOKABLE bool decorationExists(const QString &plugin, const QString &theme); 44 | Q_INVOKABLE bool isAurorae(const QString &plugin, const QString &theme); 45 | 46 | signals: 47 | void countChanged(); 48 | void currentThemeChanged(); 49 | void currentPluginChanged(); 50 | 51 | private slots: 52 | void init(); 53 | void loadCurrents(); 54 | void kwinChanged(const QString &filename); 55 | void setCurrentPlugin(QString plugin); 56 | void setCurrentTheme(QString theme); 57 | 58 | private: 59 | bool pluginExists(const QString &plugin); 60 | 61 | private: 62 | struct Data 63 | { 64 | QString pluginName; 65 | QString themeName; 66 | QString visibleName; 67 | bool isAuroraeTheme = false; 68 | bool configuration = false; 69 | }; 70 | 71 | QString m_currentPlugin; 72 | QString m_currentTheme; 73 | 74 | std::vector m_plugins; 75 | QMap m_knsProvides; 76 | }; 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /libappletdecoration/environment.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2019 Michail Vourlakos 3 | * 4 | * This file is part of Window Buttons Applet 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #include "environment.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | Environment::Environment(QObject *parent) : QObject(parent) 16 | { 17 | } 18 | 19 | Environment::~Environment() 20 | { 21 | qDebug() << staticMetaObject.className() << "destructed"; 22 | } 23 | 24 | uint Environment::frameworksVersion() const 25 | { 26 | return PLASMA_VERSION; 27 | } 28 | 29 | uint Environment::plasmaDesktopVersion() 30 | { 31 | if (m_plasmaDesktopVersion == -1) 32 | { 33 | m_plasmaDesktopVersion = identifyPlasmaDesktopVersion(); 34 | } 35 | 36 | return m_plasmaDesktopVersion; 37 | } 38 | 39 | uint Environment::makeVersion(uint major, uint minor, uint release) const 40 | { 41 | return (((major) << 16) | ((minor) << 8) | (release)); 42 | } 43 | 44 | uint Environment::identifyPlasmaDesktopVersion() 45 | { 46 | //! Identify Plasma Desktop version 47 | QProcess process; 48 | process.start("plasmashell", QStringList() << "-v"); 49 | process.waitForFinished(); 50 | QString output(process.readAllStandardOutput()); 51 | 52 | QStringList stringSplit = output.split(" "); 53 | 54 | if (stringSplit.count() >= 2) 55 | { 56 | qDebug() << " /////////////////////////"; 57 | QString cleanVersionString = stringSplit[1].remove("\n"); 58 | QStringList plasmaDesktopVersionParts = cleanVersionString.split("."); 59 | 60 | if (plasmaDesktopVersionParts.count() == 3) 61 | { 62 | uint maj = plasmaDesktopVersionParts[0].toUInt(); 63 | uint min = plasmaDesktopVersionParts[1].toUInt(); 64 | uint rel = plasmaDesktopVersionParts[2].toUInt(); 65 | 66 | if (maj > 0) 67 | { 68 | 69 | uint desktopVersion = makeVersion(maj, min, rel); 70 | 71 | QString message("Plasma Desktop version: " + QString::number(maj) + "." + QString::number(min) + "." + QString::number(rel) + " (" + 72 | QString::number(desktopVersion) + ")"); 73 | qDebug() << message; 74 | qDebug() << " /////////////////////////"; 75 | 76 | return desktopVersion; 77 | } 78 | } 79 | 80 | qDebug() << " /////////////////////////"; 81 | } 82 | 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /libappletdecoration/environment.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2019 Michail Vourlakos 3 | * 4 | * This file is part of Window Buttons Applet 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #ifndef ENVIRONMENT_H 10 | #define ENVIRONMENT_H 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | class Environment final : public QObject 17 | { 18 | Q_OBJECT 19 | Q_PROPERTY(uint frameworksVersion READ frameworksVersion NOTIFY frameworksVersionChanged) 20 | Q_PROPERTY(uint plasmaDesktopVersion READ plasmaDesktopVersion NOTIFY plasmaDesktopVersionChanged) 21 | 22 | public: 23 | virtual ~Environment(); 24 | 25 | bool compositingActive() const; 26 | bool isPlatformWayland() const; 27 | 28 | uint frameworksVersion() const; 29 | uint plasmaDesktopVersion(); 30 | 31 | static QObject *instance(QQmlEngine *engine, QJSEngine *scriptEngine) 32 | { 33 | Q_UNUSED(engine) 34 | Q_UNUSED(scriptEngine) 35 | 36 | // NOTE: QML engine is the owner of this resource 37 | return new Environment; 38 | } 39 | 40 | public slots: 41 | Q_INVOKABLE uint makeVersion(uint major, uint minor, uint release) const; 42 | 43 | signals: 44 | void frameworksVersionChanged(); 45 | void plasmaDesktopVersionChanged(); 46 | 47 | private: 48 | explicit Environment(QObject *parent = nullptr); 49 | 50 | void loadPlasmaDesktopVersion(); 51 | 52 | uint identifyPlasmaDesktopVersion(); 53 | 54 | private: 55 | int m_plasmaDesktopVersion{ -1 }; 56 | }; 57 | 58 | #endif // ENVIRONMENT_H 59 | -------------------------------------------------------------------------------- /libappletdecoration/kwinconfig.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 Christian Tallner 3 | * 4 | * This file is part of Window Buttons Applet 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | #include "kwinconfig.h" 9 | #include 10 | 11 | using org::kde::KWin; 12 | 13 | KWinConfig::KWinConfig(QObject *parent) : QObject(parent) , config(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String("/kwinrc"), KConfig::SimpleConfig) 14 | { 15 | group = config.group(QStringLiteral("Windows")); 16 | kwin_ptr = new KWin("org.kde.KWin", "/KWin", QDBusConnection::sessionBus(), this); 17 | } 18 | 19 | bool KWinConfig::borderlessMaximizedWindows() const 20 | { 21 | return group.exists() && group.hasKey(QStringLiteral("BorderlessMaximizedWindows")) && group.readEntry(QStringLiteral("BorderlessMaximizedWindows")) == QString("true"); 22 | } 23 | 24 | void KWinConfig::setBorderlessMaximizedWindows(bool isEnabled) 25 | { 26 | if(kwin_ptr != nullptr){ 27 | group.writeEntry(QStringLiteral("BorderlessMaximizedWindows"), isEnabled); 28 | group.sync(); 29 | kwin_ptr->reconfigure(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /libappletdecoration/kwinconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 Christian Tallner 3 | * 4 | * This file is part of Window Buttons Applet 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include "kwin_interface.h" 12 | #ifndef APPLET_WINDOWBUTTONS_KWINCONFIG_H 13 | #define APPLET_WINDOWBUTTONS_KWINCONFIG_H 14 | 15 | 16 | class KWinConfig : public QObject 17 | { 18 | Q_OBJECT 19 | Q_PROPERTY( 20 | bool borderlessMaximizedWindows 21 | READ borderlessMaximizedWindows 22 | WRITE setBorderlessMaximizedWindows 23 | NOTIFY borderlessMaximizedWindowsChanged 24 | ) 25 | 26 | public: 27 | explicit KWinConfig(QObject *parent = nullptr); 28 | 29 | bool borderlessMaximizedWindows() const; 30 | void setBorderlessMaximizedWindows(bool isEnabled); 31 | 32 | signals: 33 | void borderlessMaximizedWindowsChanged(); 34 | 35 | private: 36 | KConfig config; 37 | KConfigGroup group; 38 | org::kde::KWin *kwin_ptr = nullptr; 39 | }; 40 | 41 | #endif // APPLET_WINDOWBUTTONS_KWINCONFIG_H 42 | -------------------------------------------------------------------------------- /libappletdecoration/padding.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 7 | */ 8 | 9 | #include "padding.h" 10 | 11 | Padding::Padding(QObject *parent) : QObject(parent) 12 | { 13 | } 14 | 15 | Padding::~Padding() 16 | { 17 | } 18 | 19 | int Padding::top() const 20 | { 21 | return m_top; 22 | } 23 | 24 | void Padding::setTop(int top) 25 | { 26 | if (m_top == top) 27 | { 28 | return; 29 | } 30 | 31 | m_top = top; 32 | emit topChanged(); 33 | } 34 | 35 | int Padding::left() const 36 | { 37 | return m_left; 38 | } 39 | 40 | void Padding::setLeft(int left) 41 | { 42 | if (m_left == left) 43 | { 44 | return; 45 | } 46 | 47 | m_left = left; 48 | emit leftChanged(); 49 | } 50 | 51 | int Padding::bottom() const 52 | { 53 | return m_bottom; 54 | } 55 | 56 | void Padding::setBottom(int bottom) 57 | { 58 | if (m_bottom == bottom) 59 | { 60 | return; 61 | } 62 | 63 | m_bottom = bottom; 64 | emit bottomChanged(); 65 | } 66 | 67 | int Padding::right() const 68 | { 69 | return m_right; 70 | } 71 | 72 | void Padding::setRight(int right) 73 | { 74 | if (m_right == right) 75 | { 76 | return; 77 | } 78 | 79 | m_right = right; 80 | emit rightChanged(); 81 | } 82 | -------------------------------------------------------------------------------- /libappletdecoration/padding.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 7 | */ 8 | 9 | #ifndef PADDING_H 10 | #define PADDING_H 11 | 12 | #include 13 | 14 | class Padding : public QObject 15 | { 16 | Q_OBJECT 17 | 18 | Q_PROPERTY(int top READ top WRITE setTop NOTIFY topChanged); 19 | Q_PROPERTY(int left READ left WRITE setLeft NOTIFY leftChanged); 20 | Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY bottomChanged); 21 | Q_PROPERTY(int right READ right WRITE setRight NOTIFY rightChanged); 22 | 23 | public: 24 | explicit Padding(QObject *parent = nullptr); 25 | virtual ~Padding(); 26 | 27 | int top() const; 28 | void setTop(int top); 29 | 30 | int left() const; 31 | void setLeft(int left); 32 | 33 | int bottom() const; 34 | void setBottom(int bottom); 35 | 36 | int right() const; 37 | void setRight(int right); 38 | 39 | signals: 40 | void topChanged(); 41 | void leftChanged(); 42 | void bottomChanged(); 43 | void rightChanged(); 44 | 45 | private: 46 | int m_top = 0; 47 | int m_left = 0; 48 | int m_bottom = 0; 49 | int m_right = 0; 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /libappletdecoration/previewbridge.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2014 Martin Gräßlin 3 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 4 | * 5 | * This file is part of the libappletdecoration library 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 8 | */ 9 | 10 | #include "previewbridge.h" 11 | 12 | #include "previewbutton.h" 13 | #include "previewclient.h" 14 | #include "previewsettings.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | static const QString s_pluginName = QStringLiteral("org.kde.kdecoration3"); 22 | static const QString s_breezerc = QStringLiteral("breezerc"); 23 | 24 | PreviewBridge::PreviewBridge(QObject *parent) : KDecoration3::DecorationBridge(parent), m_lastCreatedClient(nullptr), m_lastCreatedSettings(nullptr), m_valid(false) 25 | { 26 | connect(this, &PreviewBridge::pluginChanged, this, &PreviewBridge::createFactory); 27 | 28 | const auto breezeRc = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + s_breezerc; 29 | 30 | KDirWatch::self()->addFile(breezeRc); 31 | 32 | connect(KDirWatch::self(), &KDirWatch::dirty, this, &PreviewBridge::settingsFileChanged); 33 | connect(KDirWatch::self(), &KDirWatch::created, this, &PreviewBridge::settingsFileChanged); 34 | } 35 | 36 | PreviewBridge::~PreviewBridge() = default; 37 | 38 | std::unique_ptr PreviewBridge::createClient(KDecoration3::DecoratedWindow *client, KDecoration3::Decoration *decoration) 39 | { 40 | auto ptr = std::make_unique(client, decoration); 41 | m_lastCreatedClient = ptr.get(); 42 | return ptr; 43 | } 44 | 45 | std::unique_ptr PreviewBridge::settings(KDecoration3::DecorationSettings *parent) 46 | { 47 | auto ptr = std::make_unique(parent); 48 | m_lastCreatedSettings = ptr.get(); 49 | return ptr; 50 | } 51 | 52 | void PreviewBridge::registerButton(PreviewButtonItem *button) 53 | { 54 | m_previewButtons.append(button); 55 | } 56 | 57 | void PreviewBridge::unregisterButton(PreviewButtonItem *button) 58 | { 59 | m_previewButtons.removeAll(button); 60 | } 61 | 62 | void PreviewBridge::setPlugin(const QString &plugin) 63 | { 64 | if (m_plugin == plugin) 65 | return; 66 | 67 | m_plugin = plugin; 68 | qDebug() << "Plugin changed to: " << m_plugin; 69 | emit pluginChanged(); 70 | } 71 | 72 | QString PreviewBridge::theme() const 73 | { 74 | return m_theme; 75 | } 76 | 77 | void PreviewBridge::setTheme(const QString &theme) 78 | { 79 | if (m_theme == theme) 80 | return; 81 | 82 | m_theme = theme; 83 | emit themeChanged(); 84 | } 85 | 86 | QString PreviewBridge::plugin() const 87 | { 88 | return m_plugin; 89 | } 90 | 91 | void PreviewBridge::createFactory() 92 | { 93 | m_factory.clear(); 94 | 95 | if (m_plugin.isNull()) 96 | { 97 | setValid(false); 98 | qDebug() << "Plugin not set"; 99 | return; 100 | } 101 | 102 | qDebug() << "Searching for plugins: " << m_plugin; 103 | 104 | const auto plugins = KPluginMetaData::findPluginById("org.kde.kdecoration3", m_plugin); 105 | 106 | m_factory = KPluginFactory::loadFactory(plugins).plugin; 107 | qDebug() << "Factory: " << !m_factory.isNull(); 108 | setValid(!m_factory.isNull()); 109 | reconfigure(); 110 | } 111 | 112 | bool PreviewBridge::isValid() const 113 | { 114 | return m_valid; 115 | } 116 | 117 | void PreviewBridge::setValid(bool valid) 118 | { 119 | if (m_valid == valid) 120 | return; 121 | 122 | m_valid = valid; 123 | emit validChanged(); 124 | } 125 | 126 | KDecoration3::Decoration *PreviewBridge::createDecoration(QObject *parent) 127 | { 128 | if (!m_valid) 129 | { 130 | return nullptr; 131 | } 132 | 133 | QVariantMap args({ { QStringLiteral("bridge"), QVariant::fromValue(this) } }); 134 | 135 | if (!m_theme.isNull()) 136 | { 137 | args.insert(QStringLiteral("theme"), m_theme); 138 | } 139 | 140 | return m_factory->create(parent, QVariantList({ args })); 141 | } 142 | 143 | KDecoration3::DecorationButton *PreviewBridge::createButton(KDecoration3::Decoration *decoration, KDecoration3::DecorationButtonType type, QObject *parent) 144 | { 145 | if (!m_valid) 146 | { 147 | return nullptr; 148 | } 149 | 150 | auto button = m_factory->create(parent, QVariantList({ QVariant::fromValue(type), QVariant::fromValue(decoration) })); 151 | 152 | if (!button) 153 | { 154 | // //! support decorations that have not been updated yet to KWin 5.23 decoration plugin approach 155 | // button = m_factory->create(QStringLiteral("button"), parent, QVariantList({QVariant::fromValue(type), 156 | // QVariant::fromValue(decoration)})); if (button) { 157 | // qWarning() << "Loading a KDecoration3::DecorationButton using the button keyword is deprecated in KWin 5.23, register the plugin without a keyword 158 | // instead" << m_plugin; 159 | // } 160 | 161 | qWarning() << "removed button" << (int) type << "from" << m_plugin; 162 | } 163 | 164 | return button; 165 | } 166 | 167 | void PreviewBridge::settingsFileChanged(const QString &filename) 168 | { 169 | if (!filename.endsWith(s_breezerc)) 170 | { 171 | return; 172 | } 173 | 174 | reconfigure(); 175 | } 176 | 177 | void PreviewBridge::reconfigure() 178 | { 179 | if (m_lastCreatedSettings) 180 | { 181 | emit m_lastCreatedSettings->decorationSettings()->reconfigured(); 182 | } 183 | } 184 | 185 | BridgeItem::BridgeItem(QObject *parent) : QObject(parent), m_bridge(new PreviewBridge()) 186 | { 187 | connect(m_bridge, &PreviewBridge::themeChanged, this, &BridgeItem::themeChanged); 188 | connect(m_bridge, &PreviewBridge::pluginChanged, this, &BridgeItem::pluginChanged); 189 | connect(m_bridge, &PreviewBridge::validChanged, this, &BridgeItem::validChanged); 190 | } 191 | 192 | BridgeItem::~BridgeItem() 193 | { 194 | m_bridge->deleteLater(); 195 | } 196 | -------------------------------------------------------------------------------- /libappletdecoration/previewbridge.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2014 Martin Gräßlin 3 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 4 | * 5 | * This file is part of the libappletdecoration library 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 8 | */ 9 | 10 | #ifndef KDECORATIONS_PREVIEW_BRIDGE_H 11 | #define KDECORATIONS_PREVIEW_BRIDGE_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | class KPluginFactory; 19 | 20 | class PreviewButtonItem; 21 | class PreviewClient; 22 | class PreviewSettings; 23 | 24 | class PreviewBridge : public KDecoration3::DecorationBridge 25 | { 26 | Q_OBJECT 27 | Q_PROPERTY(QString plugin READ plugin WRITE setPlugin NOTIFY pluginChanged) 28 | Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged) 29 | Q_PROPERTY(bool valid READ isValid NOTIFY validChanged) 30 | 31 | public: 32 | explicit PreviewBridge(QObject *parent = nullptr); 33 | virtual ~PreviewBridge(); 34 | std::unique_ptr createClient(KDecoration3::DecoratedWindow *client, KDecoration3::Decoration *decoration) override; 35 | std::unique_ptr settings(KDecoration3::DecorationSettings *parent) override; 36 | 37 | PreviewClient *lastCreatedClient() 38 | { 39 | return m_lastCreatedClient; 40 | } 41 | PreviewSettings *lastCreatedSettings() 42 | { 43 | return m_lastCreatedSettings; 44 | } 45 | 46 | void registerButton(PreviewButtonItem *button); 47 | void unregisterButton(PreviewButtonItem *button); 48 | 49 | void setPlugin(const QString &plugin); 50 | QString plugin() const; 51 | void setTheme(const QString &theme); 52 | QString theme() const; 53 | bool isValid() const; 54 | 55 | KDecoration3::Decoration *createDecoration(QObject *parent = nullptr); 56 | KDecoration3::DecorationButton *createButton(KDecoration3::Decoration *decoration, KDecoration3::DecorationButtonType type, QObject *parent = nullptr); 57 | 58 | public Q_SLOTS: 59 | void reconfigure(); 60 | 61 | Q_SIGNALS: 62 | void pluginChanged(); 63 | void themeChanged(); 64 | void validChanged(); 65 | 66 | private slots: 67 | void settingsFileChanged(const QString &filename); 68 | 69 | private: 70 | void createFactory(); 71 | void setValid(bool valid); 72 | PreviewClient *m_lastCreatedClient; 73 | PreviewSettings *m_lastCreatedSettings; 74 | QList m_previewButtons; 75 | QString m_plugin; 76 | QString m_theme; 77 | QPointer m_factory; 78 | bool m_valid; 79 | }; 80 | 81 | class BridgeItem : public QObject 82 | { 83 | Q_OBJECT 84 | Q_PROPERTY(QString plugin READ plugin WRITE setPlugin NOTIFY pluginChanged) 85 | Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged) 86 | Q_PROPERTY(bool valid READ isValid NOTIFY validChanged) 87 | Q_PROPERTY(PreviewBridge *bridge READ bridge CONSTANT) 88 | 89 | public: 90 | explicit BridgeItem(QObject *parent = nullptr); 91 | virtual ~BridgeItem(); 92 | 93 | void setPlugin(const QString &plugin) 94 | { 95 | m_bridge->setPlugin(plugin); 96 | } 97 | QString plugin() const 98 | { 99 | return m_bridge->plugin(); 100 | } 101 | void setTheme(const QString &theme) 102 | { 103 | m_bridge->setTheme(theme); 104 | } 105 | QString theme() const 106 | { 107 | return m_bridge->theme(); 108 | } 109 | bool isValid() const 110 | { 111 | return m_bridge->isValid(); 112 | } 113 | 114 | PreviewBridge *bridge() const 115 | { 116 | return m_bridge; 117 | } 118 | 119 | Q_SIGNALS: 120 | void pluginChanged(); 121 | void themeChanged(); 122 | void validChanged(); 123 | 124 | private: 125 | PreviewBridge *m_bridge; 126 | }; 127 | 128 | Q_DECLARE_METATYPE(PreviewBridge *) 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /libappletdecoration/previewbutton.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2014 Martin Gräßlin 3 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 4 | * 5 | * This file is part of the libappletdecoration library 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 8 | */ 9 | 10 | #ifndef KDECORATIONS_PREVIEW_BUTTON_ITEM_H 11 | #define KDECORATIONS_PREVIEW_BUTTON_ITEM_H 12 | 13 | #include "previewshareddecoration.h" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | class Padding; 21 | class PreviewBridge; 22 | class PreviewClient; 23 | 24 | class PreviewButtonItem : public QQuickPaintedItem 25 | { 26 | Q_OBJECT 27 | Q_PROPERTY(PreviewBridge *bridge READ bridge WRITE setBridge NOTIFY bridgeChanged) 28 | Q_PROPERTY(SharedDecoration *sharedDecoration READ sharedDecoration WRITE setSharedDecoration NOTIFY sharedDecorationChanged) 29 | 30 | Q_PROPERTY(bool isActive READ isActive WRITE setIsActive NOTIFY isActiveChanged); 31 | Q_PROPERTY(bool isMaximized READ isMaximized WRITE setIsMaximized NOTIFY isMaximizedChanged) 32 | Q_PROPERTY(bool isOnAllDesktops READ isOnAllDesktops WRITE setIsOnAllDesktops NOTIFY isOnAllDesktopsChanged) 33 | Q_PROPERTY(bool isKeepAbove READ isKeepAbove WRITE setIsKeepAbove NOTIFY isKeepAboveChanged) 34 | 35 | Q_PROPERTY(int localX READ localX WRITE setLocalX NOTIFY localXChanged) 36 | Q_PROPERTY(int localY READ localY WRITE setLocalY NOTIFY localYChanged) 37 | 38 | Q_PROPERTY(int type READ typeAsInt WRITE setType NOTIFY typeChanged) 39 | 40 | Q_PROPERTY(QString scheme READ scheme WRITE setScheme NOTIFY schemeChanged) 41 | Q_PROPERTY(Padding *padding READ padding NOTIFY paddingChanged) 42 | 43 | public: 44 | explicit PreviewButtonItem(QQuickItem *parent = nullptr); 45 | virtual ~PreviewButtonItem(); 46 | void paint(QPainter *painter) override; 47 | 48 | PreviewBridge *bridge() const; 49 | void setBridge(PreviewBridge *bridge); 50 | 51 | SharedDecoration *sharedDecoration() const; 52 | void setSharedDecoration(SharedDecoration *sharedDecoration); 53 | 54 | KDecoration3::Decoration *decoration() const; 55 | 56 | bool isActive() const; 57 | void setIsActive(bool active); 58 | 59 | bool isMaximized() const; 60 | void setIsMaximized(bool maximized); 61 | 62 | bool isOnAllDesktops() const; 63 | void setIsOnAllDesktops(bool onalldesktops); 64 | 65 | bool isKeepAbove() const; 66 | void setIsKeepAbove(bool keepabove); 67 | 68 | int localX() const; 69 | void setLocalX(int x); 70 | 71 | int localY() const; 72 | void setLocalY(int y); 73 | 74 | KDecoration3::DecorationButtonType type() const; 75 | int typeAsInt() const; 76 | void setType(KDecoration3::DecorationButtonType type); 77 | void setType(int type); 78 | 79 | QString scheme() const; 80 | void setScheme(QString scheme); 81 | 82 | Padding *padding() const; 83 | 84 | QRect visualGeometry() const; 85 | 86 | Q_SIGNALS: 87 | void bridgeChanged(); 88 | void isActiveChanged(); 89 | void isMaximizedChanged(); 90 | void isOnAllDesktopsChanged(); 91 | void isKeepAboveChanged(); 92 | void localXChanged(); 93 | void localYChanged(); 94 | void paddingChanged(); 95 | void schemeChanged(); 96 | void sharedDecorationChanged(); 97 | void typeChanged(); 98 | 99 | void clicked(); 100 | 101 | protected: 102 | void mouseDoubleClickEvent(QMouseEvent *event) override; 103 | void mouseMoveEvent(QMouseEvent *event) override; 104 | void mousePressEvent(QMouseEvent *event) override; 105 | void mouseReleaseEvent(QMouseEvent *event) override; 106 | void hoverEnterEvent(QHoverEvent *event) override; 107 | void hoverLeaveEvent(QHoverEvent *event) override; 108 | void hoverMoveEvent(QHoverEvent *event) override; 109 | void focusOutEvent(QFocusEvent *event) override; 110 | 111 | void componentComplete() override; 112 | 113 | private Q_SLOTS: 114 | void createButton(); 115 | void syncInternalGeometry(); 116 | 117 | void onButtonDamaged(); 118 | void onDecorationDamaged(const QRegion ®ion); 119 | 120 | private: 121 | QPointer m_bridge; 122 | QPointer m_client; 123 | QPointer m_sharedDecoration; 124 | QPointer m_lastAppliedDecoration; 125 | 126 | KDecoration3::DecorationButton *m_button = nullptr; 127 | KDecoration3::DecorationButtonType m_type = KDecoration3::DecorationButtonType::Custom; 128 | 129 | bool m_isActive{ true }; 130 | bool m_isMaximized{ false }; 131 | bool m_isOnAllDesktops{ false }; 132 | bool m_isKeepAbove{ false }; 133 | 134 | int m_localX; 135 | int m_localY; 136 | 137 | QString m_scheme; 138 | QRect m_internalGeometry; 139 | QRect m_fullGeometry; 140 | QRect m_visualGeometry; 141 | 142 | Padding *m_padding; 143 | }; 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /libappletdecoration/previewclient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2014 Martin Gräßlin 3 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 4 | * 5 | * This file is part of the libappletdecoration library 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 8 | */ 9 | 10 | #include "previewclient.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | PreviewClient::PreviewClient(KDecoration3::DecoratedWindow *c, KDecoration3::Decoration *decoration) 20 | : QObject(decoration), DecoratedWindowPrivate(c, decoration), m_icon(QIcon::fromTheme(QStringLiteral("start-here-kde"))), 21 | m_iconName(m_icon.name()) 22 | // , m_palette(new KWin::Decoration::DecorationPalette(QStringLiteral("kdeglobals"))) 23 | , 24 | m_active(true), m_closeable(true), m_keepBelow(false), m_keepAbove(false), m_maximizable(true), m_maximizedHorizontally(false), m_maximizedVertically(false), 25 | m_minimizable(true), m_modal(false), m_movable(true), m_resizable(true), m_shadeable(true), m_shaded(false), m_providesContextHelp(false), m_desktop(1), m_width(0), 26 | m_height(0), m_bordersTopEdge(false), m_bordersLeftEdge(false), m_bordersRightEdge(false), m_bordersBottomEdge(false) 27 | { 28 | connect(this, &PreviewClient::captionChanged, c, &KDecoration3::DecoratedWindow::captionChanged); 29 | connect(this, &PreviewClient::activeChanged, c, &KDecoration3::DecoratedWindow::activeChanged); 30 | connect(this, &PreviewClient::closeableChanged, c, &KDecoration3::DecoratedWindow::closeableChanged); 31 | connect(this, &PreviewClient::keepAboveChanged, c, &KDecoration3::DecoratedWindow::keepAboveChanged); 32 | connect(this, &PreviewClient::keepBelowChanged, c, &KDecoration3::DecoratedWindow::keepBelowChanged); 33 | connect(this, &PreviewClient::maximizableChanged, c, &KDecoration3::DecoratedWindow::maximizeableChanged); 34 | connect(this, &PreviewClient::maximizedChanged, c, &KDecoration3::DecoratedWindow::maximizedChanged); 35 | connect(this, &PreviewClient::maximizedVerticallyChanged, c, &KDecoration3::DecoratedWindow::maximizedVerticallyChanged); 36 | connect(this, &PreviewClient::maximizedHorizontallyChanged, c, &KDecoration3::DecoratedWindow::maximizedHorizontallyChanged); 37 | connect(this, &PreviewClient::minimizableChanged, c, &KDecoration3::DecoratedWindow::minimizeableChanged); 38 | // connect(this, &PreviewClient::modalChanged, c, &DecoratedWindow::modalChanged); 39 | connect(this, &PreviewClient::movableChanged, c, &KDecoration3::DecoratedWindow::moveableChanged); 40 | connect(this, &PreviewClient::onAllDesktopsChanged, c, &KDecoration3::DecoratedWindow::onAllDesktopsChanged); 41 | connect(this, &PreviewClient::resizableChanged, c, &KDecoration3::DecoratedWindow::resizeableChanged); 42 | connect(this, &PreviewClient::shadeableChanged, c, &KDecoration3::DecoratedWindow::shadeableChanged); 43 | connect(this, &PreviewClient::shadedChanged, c, &KDecoration3::DecoratedWindow::shadedChanged); 44 | connect(this, &PreviewClient::providesContextHelpChanged, c, &KDecoration3::DecoratedWindow::providesContextHelpChanged); 45 | // connect(this, &PreviewClient::onAllDesktopsChanged, c, &KDecoration3::DecoratedWindow::onAllDesktopsChanged); 46 | connect(this, &PreviewClient::widthChanged, c, &KDecoration3::DecoratedWindow::widthChanged); 47 | connect(this, &PreviewClient::heightChanged, c, &KDecoration3::DecoratedWindow::heightChanged); 48 | connect(this, &PreviewClient::iconChanged, c, &KDecoration3::DecoratedWindow::iconChanged); 49 | connect(this, &PreviewClient::paletteChanged, c, &KDecoration3::DecoratedWindow::paletteChanged); 50 | // connect(this, &PreviewClient::, c, &DecoratedWindow::); 51 | connect(this, &PreviewClient::maximizedVerticallyChanged, this, [this]() { emit maximizedChanged(isMaximized()); }); 52 | connect(this, &PreviewClient::maximizedHorizontallyChanged, this, [this]() { emit maximizedChanged(isMaximized()); }); 53 | connect(this, &PreviewClient::iconNameChanged, this, 54 | [this]() 55 | { 56 | m_icon = QIcon::fromTheme(m_iconName); 57 | emit iconChanged(m_icon); 58 | }); 59 | connect(this, &PreviewClient::desktopChanged, this, [this](int) { emit onAllDesktopsChanged(isOnAllDesktops()); }); 60 | /* connect(m_palette, &KWin::Decoration::DecorationPalette::changed, [this]() { 61 | emit paletteChanged(m_palette->palette()); 62 | });*/ 63 | auto emitEdgesChanged = [this, c]() { c->adjacentScreenEdgesChanged(adjacentScreenEdges()); }; 64 | connect(this, &PreviewClient::bordersTopEdgeChanged, this, emitEdgesChanged); 65 | connect(this, &PreviewClient::bordersLeftEdgeChanged, this, emitEdgesChanged); 66 | connect(this, &PreviewClient::bordersRightEdgeChanged, this, emitEdgesChanged); 67 | connect(this, &PreviewClient::bordersBottomEdgeChanged, this, emitEdgesChanged); 68 | 69 | setColorScheme("kdeglobals"); 70 | 71 | qApp->installEventFilter(this); 72 | } 73 | 74 | PreviewClient::~PreviewClient() = default; 75 | 76 | void PreviewClient::setIcon(const QIcon &pixmap) 77 | { 78 | m_icon = pixmap; 79 | emit iconChanged(m_icon); 80 | } 81 | 82 | qreal PreviewClient::width() const 83 | { 84 | return m_width; 85 | } 86 | 87 | qreal PreviewClient::height() const 88 | { 89 | return m_height; 90 | } 91 | 92 | qreal PreviewClient::scale() const 93 | { 94 | return 1; 95 | } 96 | 97 | qreal PreviewClient::nextScale() const 98 | { 99 | return 1; 100 | } 101 | 102 | QString PreviewClient::caption() const 103 | { 104 | return m_caption; 105 | } 106 | 107 | int PreviewClient::desktop() const 108 | { 109 | return m_desktop; 110 | } 111 | 112 | void PreviewClient::setDesktop(int desktop) 113 | { 114 | if (desktop == 0) 115 | { 116 | desktop = 1; 117 | } 118 | 119 | if (m_desktop == desktop) 120 | { 121 | return; 122 | } 123 | 124 | m_desktop = desktop; 125 | emit desktopChanged(m_desktop); 126 | } 127 | 128 | QIcon PreviewClient::icon() const 129 | { 130 | return m_icon; 131 | } 132 | 133 | QString PreviewClient::iconName() const 134 | { 135 | return m_iconName; 136 | } 137 | 138 | bool PreviewClient::isActive() const 139 | { 140 | return m_active; 141 | } 142 | 143 | bool PreviewClient::isCloseable() const 144 | { 145 | return m_closeable; 146 | } 147 | 148 | bool PreviewClient::isKeepAbove() const 149 | { 150 | return m_keepAbove; 151 | } 152 | 153 | bool PreviewClient::isKeepBelow() const 154 | { 155 | return m_keepBelow; 156 | } 157 | 158 | bool PreviewClient::isMaximizeable() const 159 | { 160 | return m_maximizable; 161 | } 162 | 163 | bool PreviewClient::isMaximized() const 164 | { 165 | return isMaximizedHorizontally() && isMaximizedVertically(); 166 | } 167 | 168 | bool PreviewClient::isMaximizedHorizontally() const 169 | { 170 | return m_maximizedHorizontally; 171 | } 172 | 173 | bool PreviewClient::isMaximizedVertically() const 174 | { 175 | return m_maximizedVertically; 176 | } 177 | 178 | bool PreviewClient::isMinimizeable() const 179 | { 180 | return m_minimizable; 181 | } 182 | 183 | bool PreviewClient::isModal() const 184 | { 185 | return m_modal; 186 | } 187 | 188 | bool PreviewClient::isMoveable() const 189 | { 190 | return m_movable; 191 | } 192 | 193 | bool PreviewClient::isOnAllDesktops() const 194 | { 195 | return desktop() == -1; 196 | } 197 | 198 | bool PreviewClient::isResizeable() const 199 | { 200 | return m_resizable; 201 | } 202 | 203 | bool PreviewClient::isShadeable() const 204 | { 205 | return m_shadeable; 206 | } 207 | 208 | bool PreviewClient::isShaded() const 209 | { 210 | return m_shaded; 211 | } 212 | 213 | bool PreviewClient::providesContextHelp() const 214 | { 215 | return m_providesContextHelp; 216 | } 217 | 218 | QString PreviewClient::windowClass() const 219 | { 220 | return QStringLiteral("kwin_preview"); 221 | } 222 | 223 | QPalette PreviewClient::palette() const 224 | { 225 | return m_palette->palette(); 226 | } 227 | 228 | QColor PreviewClient::color(KDecoration3::ColorGroup group, KDecoration3::ColorRole role) const 229 | { 230 | return m_palette->color(group, role); 231 | } 232 | 233 | void PreviewClient::setColorScheme(QString scheme) 234 | { 235 | if (m_colorScheme == scheme && !m_colorScheme.isEmpty()) 236 | { 237 | return; 238 | } 239 | 240 | m_colorScheme = scheme; 241 | 242 | if (m_palette) 243 | { 244 | m_palette->deleteLater(); 245 | } 246 | 247 | m_palette = new DecorationPalette(scheme); 248 | 249 | emit paletteChanged(m_palette->palette()); 250 | } 251 | 252 | Qt::Edges PreviewClient::adjacentScreenEdges() const 253 | { 254 | Qt::Edges edges; 255 | 256 | if (m_bordersBottomEdge) 257 | { 258 | edges |= Qt::BottomEdge; 259 | } 260 | 261 | if (m_bordersLeftEdge) 262 | { 263 | edges |= Qt::LeftEdge; 264 | } 265 | 266 | if (m_bordersRightEdge) 267 | { 268 | edges |= Qt::RightEdge; 269 | } 270 | 271 | if (m_bordersTopEdge) 272 | { 273 | edges |= Qt::TopEdge; 274 | } 275 | 276 | return edges; 277 | } 278 | 279 | bool PreviewClient::hasApplicationMenu() const 280 | { 281 | return true; 282 | } 283 | 284 | bool PreviewClient::isApplicationMenuActive() const 285 | { 286 | return false; 287 | } 288 | 289 | bool PreviewClient::bordersBottomEdge() const 290 | { 291 | return m_bordersBottomEdge; 292 | } 293 | 294 | bool PreviewClient::bordersLeftEdge() const 295 | { 296 | return m_bordersLeftEdge; 297 | } 298 | 299 | bool PreviewClient::bordersRightEdge() const 300 | { 301 | return m_bordersRightEdge; 302 | } 303 | 304 | bool PreviewClient::bordersTopEdge() const 305 | { 306 | return m_bordersTopEdge; 307 | } 308 | 309 | void PreviewClient::setBordersBottomEdge(bool enabled) 310 | { 311 | if (m_bordersBottomEdge == enabled) 312 | { 313 | return; 314 | } 315 | 316 | m_bordersBottomEdge = enabled; 317 | emit bordersBottomEdgeChanged(enabled); 318 | } 319 | 320 | void PreviewClient::setBordersLeftEdge(bool enabled) 321 | { 322 | if (m_bordersLeftEdge == enabled) 323 | { 324 | return; 325 | } 326 | 327 | m_bordersLeftEdge = enabled; 328 | emit bordersLeftEdgeChanged(enabled); 329 | } 330 | 331 | void PreviewClient::setBordersRightEdge(bool enabled) 332 | { 333 | if (m_bordersRightEdge == enabled) 334 | { 335 | return; 336 | } 337 | 338 | m_bordersRightEdge = enabled; 339 | emit bordersRightEdgeChanged(enabled); 340 | } 341 | 342 | void PreviewClient::setBordersTopEdge(bool enabled) 343 | { 344 | if (m_bordersTopEdge == enabled) 345 | { 346 | return; 347 | } 348 | 349 | m_bordersTopEdge = enabled; 350 | emit bordersTopEdgeChanged(enabled); 351 | } 352 | 353 | void PreviewClient::requestShowToolTip(const QString &text) 354 | { 355 | Q_UNUSED(text) 356 | // qDebug() << "tooltip show requested with text:" << text; 357 | } 358 | 359 | void PreviewClient::requestHideToolTip() 360 | { 361 | // qDebug() << "tooltip hide requested"; 362 | } 363 | 364 | QSizeF PreviewClient::size() const 365 | { 366 | return { m_width, m_height }; 367 | } 368 | 369 | void PreviewClient::requestShowWindowMenu(const QRect &rect) 370 | { 371 | Q_UNUSED(rect) 372 | emit showWindowMenuRequested(); 373 | } 374 | 375 | void PreviewClient::requestClose() 376 | { 377 | emit closeRequested(); 378 | } 379 | 380 | void PreviewClient::requestContextHelp() 381 | { 382 | qDebug() << "context help requested"; 383 | } 384 | 385 | void PreviewClient::requestToggleMaximization(Qt::MouseButtons buttons) 386 | { 387 | if (buttons.testFlag(Qt::LeftButton)) 388 | { 389 | const bool set = !isMaximized(); 390 | setMaximizedHorizontally(set); 391 | setMaximizedVertically(set); 392 | } 393 | else if (buttons.testFlag(Qt::RightButton)) 394 | { 395 | setMaximizedHorizontally(!isMaximizedHorizontally()); 396 | } 397 | else if (buttons.testFlag(Qt::MiddleButton)) 398 | { 399 | setMaximizedVertically(!isMaximizedVertically()); 400 | } 401 | } 402 | 403 | void PreviewClient::requestMinimize() 404 | { 405 | emit minimizeRequested(); 406 | } 407 | 408 | void PreviewClient::requestToggleKeepAbove() 409 | { 410 | setKeepAbove(!isKeepAbove()); 411 | } 412 | 413 | void PreviewClient::requestToggleKeepBelow() 414 | { 415 | setKeepBelow(!isKeepBelow()); 416 | } 417 | 418 | void PreviewClient::requestShowApplicationMenu(const QRect &rect, int actionId) 419 | { 420 | Q_UNUSED(rect); 421 | Q_UNUSED(actionId); 422 | } 423 | 424 | void PreviewClient::showApplicationMenu(int actionId) 425 | { 426 | Q_UNUSED(actionId) 427 | } 428 | 429 | void PreviewClient::requestToggleOnAllDesktops() 430 | { 431 | setDesktop(isOnAllDesktops() ? 1 : -1); 432 | } 433 | 434 | void PreviewClient::requestToggleShade() 435 | { 436 | setShaded(!isShaded()); 437 | } 438 | 439 | #define SETTER(type, name, variable) \ 440 | void PreviewClient::name(type variable) \ 441 | { \ 442 | if (m_##variable == variable) \ 443 | { \ 444 | return; \ 445 | } \ 446 | m_##variable = variable; \ 447 | emit variable##Changed(m_##variable); \ 448 | } 449 | 450 | #define SETTER2(name, variable) SETTER(bool, name, variable) 451 | 452 | SETTER(const QString &, setCaption, caption) 453 | SETTER(const QString &, setIconName, iconName) 454 | SETTER(int, setWidth, width) 455 | SETTER(int, setHeight, height) 456 | 457 | SETTER2(setActive, active) 458 | SETTER2(setCloseable, closeable) 459 | SETTER2(setMaximizable, maximizable) 460 | SETTER2(setKeepBelow, keepBelow) 461 | SETTER2(setKeepAbove, keepAbove) 462 | SETTER2(setMaximizedHorizontally, maximizedHorizontally) 463 | SETTER2(setMaximizedVertically, maximizedVertically) 464 | SETTER2(setMinimizable, minimizable) 465 | SETTER2(setModal, modal) 466 | SETTER2(setMovable, movable) 467 | SETTER2(setResizable, resizable) 468 | SETTER2(setShadeable, shadeable) 469 | SETTER2(setShaded, shaded) 470 | SETTER2(setProvidesContextHelp, providesContextHelp) 471 | 472 | #undef SETTER2 473 | #undef SETTER 474 | -------------------------------------------------------------------------------- /libappletdecoration/previewclient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2014 Martin Gräßlin 3 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 4 | * 5 | * This file is part of the libappletdecoration library 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 8 | */ 9 | 10 | #ifndef KDECORATIONS_PREVIEW_CLIENT_H 11 | #define KDECORATIONS_PREVIEW_CLIENT_H 12 | 13 | #include "decorationpalette.h" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | class QAbstractItemModel; 22 | 23 | class PreviewClient 24 | : public QObject 25 | , public KDecoration3::DecoratedWindowPrivate 26 | { 27 | Q_OBJECT 28 | Q_PROPERTY(KDecoration3::Decoration *decoration READ decoration CONSTANT) 29 | Q_PROPERTY(QString caption READ caption WRITE setCaption NOTIFY captionChanged) 30 | Q_PROPERTY(QIcon icon READ icon WRITE setIcon NOTIFY iconChanged) 31 | Q_PROPERTY(QString iconName READ iconName WRITE setIconName NOTIFY iconNameChanged) 32 | Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged) 33 | Q_PROPERTY(bool closeable READ isCloseable WRITE setCloseable NOTIFY closeableChanged) 34 | Q_PROPERTY(bool keepAbove READ isKeepAbove WRITE setKeepAbove NOTIFY keepAboveChanged) 35 | Q_PROPERTY(bool keepBelow READ isKeepBelow WRITE setKeepBelow NOTIFY keepBelowChanged) 36 | Q_PROPERTY(bool maximizable READ isMaximizeable WRITE setMaximizable NOTIFY maximizableChanged) 37 | Q_PROPERTY(bool maximized READ isMaximized NOTIFY maximizedChanged) 38 | Q_PROPERTY(bool maximizedVertically READ isMaximizedVertically WRITE setMaximizedVertically NOTIFY maximizedVerticallyChanged) 39 | Q_PROPERTY(bool maximizedHorizontally READ isMaximizedHorizontally WRITE setMaximizedHorizontally NOTIFY maximizedHorizontallyChanged) 40 | Q_PROPERTY(bool minimizable READ isMinimizeable WRITE setMinimizable NOTIFY minimizableChanged) 41 | Q_PROPERTY(bool modal READ isModal WRITE setModal NOTIFY modalChanged) 42 | Q_PROPERTY(bool movable READ isMoveable WRITE setMovable NOTIFY movableChanged) 43 | Q_PROPERTY(int desktop READ desktop WRITE setDesktop NOTIFY desktopChanged) 44 | Q_PROPERTY(bool onAllDesktops READ isOnAllDesktops NOTIFY onAllDesktopsChanged) 45 | Q_PROPERTY(bool resizable READ isResizeable WRITE setResizable NOTIFY resizableChanged) 46 | Q_PROPERTY(bool shadeable READ isShadeable WRITE setShadeable NOTIFY shadeableChanged) 47 | Q_PROPERTY(bool shaded READ isShaded WRITE setShaded NOTIFY shadedChanged) 48 | Q_PROPERTY(bool providesContextHelp READ providesContextHelp WRITE setProvidesContextHelp NOTIFY providesContextHelpChanged) 49 | Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged) 50 | Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged) 51 | Q_PROPERTY(bool bordersTopEdge READ bordersTopEdge WRITE setBordersTopEdge NOTIFY bordersTopEdgeChanged) 52 | Q_PROPERTY(bool bordersLeftEdge READ bordersLeftEdge WRITE setBordersLeftEdge NOTIFY bordersLeftEdgeChanged) 53 | Q_PROPERTY(bool bordersRightEdge READ bordersRightEdge WRITE setBordersRightEdge NOTIFY bordersRightEdgeChanged) 54 | Q_PROPERTY(bool bordersBottomEdge READ bordersBottomEdge WRITE setBordersBottomEdge NOTIFY bordersBottomEdgeChanged) 55 | public: 56 | explicit PreviewClient(KDecoration3::DecoratedWindow *client, KDecoration3::Decoration *decoration); 57 | virtual ~PreviewClient(); 58 | 59 | QString caption() const override; 60 | int desktop() const; 61 | QIcon icon() const override; 62 | bool isActive() const override; 63 | bool isCloseable() const override; 64 | bool isKeepAbove() const override; 65 | bool isKeepBelow() const override; 66 | bool isMaximizeable() const override; 67 | bool isMaximized() const override; 68 | bool isMaximizedVertically() const override; 69 | bool isMaximizedHorizontally() const override; 70 | bool isMinimizeable() const override; 71 | bool isModal() const override; 72 | bool isMoveable() const override; 73 | bool isOnAllDesktops() const override; 74 | bool isResizeable() const override; 75 | bool isShadeable() const override; 76 | bool isShaded() const override; 77 | bool providesContextHelp() const override; 78 | QString windowClass() const override; 79 | 80 | qreal width() const override; 81 | qreal height() const override; 82 | qreal scale() const override; 83 | qreal nextScale() const override; 84 | QPalette palette() const override; 85 | QColor color(KDecoration3::ColorGroup group, KDecoration3::ColorRole role) const override; 86 | Qt::Edges adjacentScreenEdges() const override; 87 | 88 | bool hasApplicationMenu() const override; 89 | bool isApplicationMenuActive() const override; 90 | 91 | void requestShowToolTip(const QString &text) override; 92 | void requestHideToolTip() override; 93 | 94 | QSizeF size() const override; 95 | 96 | void requestShowWindowMenu(const QRect &rect) override; 97 | 98 | void requestClose() override; 99 | void requestContextHelp() override; 100 | void requestToggleMaximization(Qt::MouseButtons buttons) override; 101 | void requestMinimize() override; 102 | void requestToggleKeepAbove() override; 103 | void requestToggleKeepBelow() override; 104 | void requestToggleShade() override; 105 | void requestShowApplicationMenu(const QRect &rect, int actionId) override; 106 | void requestToggleOnAllDesktops() override; 107 | 108 | void showApplicationMenu(int actionId) override; 109 | 110 | void setCaption(const QString &caption); 111 | void setActive(bool active); 112 | void setCloseable(bool closeable); 113 | void setMaximizable(bool maximizable); 114 | void setKeepBelow(bool keepBelow); 115 | void setKeepAbove(bool keepAbove); 116 | void setMaximizedHorizontally(bool maximized); 117 | void setMaximizedVertically(bool maximized); 118 | void setMinimizable(bool minimizable); 119 | void setModal(bool modal); 120 | void setMovable(bool movable); 121 | void setResizable(bool resizable); 122 | void setShadeable(bool shadeable); 123 | void setShaded(bool shaded); 124 | void setProvidesContextHelp(bool contextHelp); 125 | void setDesktop(int desktop); 126 | void setColorScheme(QString scheme); 127 | 128 | void setWidth(int width); 129 | void setHeight(int height); 130 | 131 | QString iconName() const; 132 | void setIconName(const QString &icon); 133 | void setIcon(const QIcon &icon); 134 | 135 | bool bordersTopEdge() const; 136 | bool bordersLeftEdge() const; 137 | bool bordersRightEdge() const; 138 | bool bordersBottomEdge() const; 139 | 140 | void setBordersTopEdge(bool enabled); 141 | void setBordersLeftEdge(bool enabled); 142 | void setBordersRightEdge(bool enabled); 143 | void setBordersBottomEdge(bool enabled); 144 | 145 | Q_SIGNALS: 146 | void captionChanged(const QString &); 147 | void iconChanged(const QIcon &); 148 | void iconNameChanged(const QString &); 149 | void activeChanged(bool); 150 | void closeableChanged(bool); 151 | void keepAboveChanged(bool); 152 | void keepBelowChanged(bool); 153 | void maximizableChanged(bool); 154 | void maximizedChanged(bool); 155 | void maximizedVerticallyChanged(bool); 156 | void maximizedHorizontallyChanged(bool); 157 | void minimizableChanged(bool); 158 | void modalChanged(bool); 159 | void movableChanged(bool); 160 | void onAllDesktopsChanged(bool); 161 | void resizableChanged(bool); 162 | void shadeableChanged(bool); 163 | void shadedChanged(bool); 164 | void providesContextHelpChanged(bool); 165 | void desktopChanged(int); 166 | void widthChanged(int); 167 | void heightChanged(int); 168 | void paletteChanged(const QPalette &); 169 | void bordersTopEdgeChanged(bool); 170 | void bordersLeftEdgeChanged(bool); 171 | void bordersRightEdgeChanged(bool); 172 | void bordersBottomEdgeChanged(bool); 173 | 174 | void showWindowMenuRequested(); 175 | void showApplicationMenuRequested(); 176 | void minimizeRequested(); 177 | void closeRequested(); 178 | 179 | private: 180 | QString m_caption; 181 | QIcon m_icon; 182 | QString m_iconName; 183 | QString m_colorScheme; 184 | DecorationPalette *m_palette{ nullptr }; 185 | bool m_active; 186 | bool m_closeable; 187 | bool m_keepBelow; 188 | bool m_keepAbove; 189 | bool m_maximizable; 190 | bool m_maximizedHorizontally; 191 | bool m_maximizedVertically; 192 | bool m_minimizable; 193 | bool m_modal; 194 | bool m_movable; 195 | bool m_resizable; 196 | bool m_shadeable; 197 | bool m_shaded; 198 | bool m_providesContextHelp; 199 | int m_desktop; 200 | qreal m_width; 201 | qreal m_height; 202 | bool m_bordersTopEdge; 203 | bool m_bordersLeftEdge; 204 | bool m_bordersRightEdge; 205 | bool m_bordersBottomEdge; 206 | }; 207 | 208 | #endif 209 | -------------------------------------------------------------------------------- /libappletdecoration/previewsettings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2014 Martin Gräßlin 3 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 4 | * 5 | * This file is part of the libappletdecoration library 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 8 | */ 9 | 10 | #include "previewsettings.h" 11 | 12 | #include "buttonsmodel.h" 13 | #include "previewbridge.h" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | BorderSizesModel::BorderSizesModel(QObject *parent) : QAbstractListModel(parent) 20 | { 21 | } 22 | 23 | BorderSizesModel::~BorderSizesModel() = default; 24 | 25 | QVariant BorderSizesModel::data(const QModelIndex &index, int role) const 26 | { 27 | if (!index.isValid() || index.row() < 0 || index.row() >= m_borders.count() || index.column() != 0) 28 | { 29 | return QVariant(); 30 | } 31 | 32 | if (role != Qt::DisplayRole && role != Qt::UserRole) 33 | { 34 | return QVariant(); 35 | } 36 | 37 | return QVariant::fromValue(m_borders.at(index.row())); 38 | } 39 | 40 | int BorderSizesModel::rowCount(const QModelIndex &parent) const 41 | { 42 | if (parent.isValid()) 43 | { 44 | return 0; 45 | } 46 | 47 | return m_borders.count(); 48 | } 49 | 50 | QHash BorderSizesModel::roleNames() const 51 | { 52 | QHash roles; 53 | roles.insert(Qt::DisplayRole, QByteArrayLiteral("display")); 54 | return roles; 55 | } 56 | 57 | PreviewSettings::PreviewSettings(KDecoration3::DecorationSettings *parent) 58 | : QObject(), KDecoration3::DecorationSettingsPrivate(parent), m_alphaChannelSupported(true), m_onAllDesktopsAvailable(true), m_closeOnDoubleClick(false), 59 | m_leftButtons( 60 | new ButtonsModel(QVector({ KDecoration3::DecorationButtonType::Minimize, KDecoration3::DecorationButtonType::Close, 61 | KDecoration3::DecorationButtonType::Menu, KDecoration3::DecorationButtonType::ApplicationMenu, 62 | KDecoration3::DecorationButtonType::OnAllDesktops }), 63 | this)), 64 | m_rightButtons( 65 | new ButtonsModel(QVector({ KDecoration3::DecorationButtonType::ContextHelp, KDecoration3::DecorationButtonType::Minimize, 66 | KDecoration3::DecorationButtonType::Maximize, KDecoration3::DecorationButtonType::Close }), 67 | this)), 68 | m_availableButtons( 69 | new ButtonsModel(QVector({ KDecoration3::DecorationButtonType::Menu, KDecoration3::DecorationButtonType::ApplicationMenu, 70 | KDecoration3::DecorationButtonType::OnAllDesktops, KDecoration3::DecorationButtonType::Minimize, 71 | KDecoration3::DecorationButtonType::Maximize, KDecoration3::DecorationButtonType::Close, 72 | KDecoration3::DecorationButtonType::ContextHelp, KDecoration3::DecorationButtonType::Shade, 73 | KDecoration3::DecorationButtonType::KeepBelow, KDecoration3::DecorationButtonType::KeepAbove }), 74 | this)), 75 | m_borderSizes(new BorderSizesModel(this)), m_borderSize(int(KDecoration3::BorderSize::Normal)), m_font(QFontDatabase::systemFont(QFontDatabase::TitleFont)) 76 | { 77 | connect(this, &PreviewSettings::alphaChannelSupportedChanged, parent, &KDecoration3::DecorationSettings::alphaChannelSupportedChanged); 78 | connect(this, &PreviewSettings::onAllDesktopsAvailableChanged, parent, &KDecoration3::DecorationSettings::onAllDesktopsAvailableChanged); 79 | connect(this, &PreviewSettings::closeOnDoubleClickOnMenuChanged, parent, &KDecoration3::DecorationSettings::closeOnDoubleClickOnMenuChanged); 80 | connect(this, &PreviewSettings::fontChanged, parent, &KDecoration3::DecorationSettings::fontChanged); 81 | auto updateLeft = [this, parent]() { parent->decorationButtonsLeftChanged(decorationButtonsLeft()); }; 82 | auto updateRight = [this, parent]() { parent->decorationButtonsRightChanged(decorationButtonsRight()); }; 83 | connect(m_leftButtons, &QAbstractItemModel::rowsRemoved, this, updateLeft); 84 | connect(m_leftButtons, &QAbstractItemModel::rowsMoved, this, updateLeft); 85 | connect(m_leftButtons, &QAbstractItemModel::rowsInserted, this, updateLeft); 86 | connect(m_rightButtons, &QAbstractItemModel::rowsRemoved, this, updateRight); 87 | connect(m_rightButtons, &QAbstractItemModel::rowsMoved, this, updateRight); 88 | connect(m_rightButtons, &QAbstractItemModel::rowsInserted, this, updateRight); 89 | } 90 | 91 | PreviewSettings::~PreviewSettings() = default; 92 | 93 | QAbstractItemModel *PreviewSettings::availableButtonsModel() const 94 | { 95 | return m_availableButtons; 96 | } 97 | 98 | QAbstractItemModel *PreviewSettings::leftButtonsModel() const 99 | { 100 | return m_leftButtons; 101 | } 102 | 103 | QAbstractItemModel *PreviewSettings::rightButtonsModel() const 104 | { 105 | return m_rightButtons; 106 | } 107 | 108 | bool PreviewSettings::isAlphaChannelSupported() const 109 | { 110 | return m_alphaChannelSupported; 111 | } 112 | 113 | bool PreviewSettings::isOnAllDesktopsAvailable() const 114 | { 115 | return m_onAllDesktopsAvailable; 116 | } 117 | 118 | void PreviewSettings::setAlphaChannelSupported(bool supported) 119 | { 120 | if (m_alphaChannelSupported == supported) 121 | { 122 | return; 123 | } 124 | 125 | m_alphaChannelSupported = supported; 126 | emit alphaChannelSupportedChanged(m_alphaChannelSupported); 127 | } 128 | 129 | void PreviewSettings::setOnAllDesktopsAvailable(bool available) 130 | { 131 | if (m_onAllDesktopsAvailable == available) 132 | { 133 | return; 134 | } 135 | 136 | m_onAllDesktopsAvailable = available; 137 | emit onAllDesktopsAvailableChanged(m_onAllDesktopsAvailable); 138 | } 139 | 140 | void PreviewSettings::setCloseOnDoubleClickOnMenu(bool enabled) 141 | { 142 | if (m_closeOnDoubleClick == enabled) 143 | { 144 | return; 145 | } 146 | 147 | m_closeOnDoubleClick = enabled; 148 | emit closeOnDoubleClickOnMenuChanged(enabled); 149 | } 150 | 151 | QVector PreviewSettings::decorationButtonsLeft() const 152 | { 153 | return m_leftButtons->buttons(); 154 | } 155 | 156 | QVector PreviewSettings::decorationButtonsRight() const 157 | { 158 | return m_rightButtons->buttons(); 159 | } 160 | 161 | void PreviewSettings::addButtonToLeft(int row) 162 | { 163 | QModelIndex index = m_availableButtons->index(row); 164 | 165 | if (!index.isValid()) 166 | { 167 | return; 168 | } 169 | 170 | m_leftButtons->add(index.data(Qt::UserRole).value()); 171 | } 172 | 173 | void PreviewSettings::addButtonToRight(int row) 174 | { 175 | QModelIndex index = m_availableButtons->index(row); 176 | 177 | if (!index.isValid()) 178 | { 179 | return; 180 | } 181 | 182 | m_rightButtons->add(index.data(Qt::UserRole).value()); 183 | } 184 | 185 | void PreviewSettings::setBorderSizesIndex(int index) 186 | { 187 | if (m_borderSize == index) 188 | { 189 | return; 190 | } 191 | 192 | m_borderSize = index; 193 | emit borderSizesIndexChanged(index); 194 | emit decorationSettings()->borderSizeChanged(borderSize()); 195 | } 196 | 197 | KDecoration3::BorderSize PreviewSettings::borderSize() const 198 | { 199 | return m_borderSizes->index(m_borderSize).data(Qt::UserRole).value(); 200 | } 201 | 202 | void PreviewSettings::setFont(const QFont &font) 203 | { 204 | if (m_font == font) 205 | { 206 | return; 207 | } 208 | 209 | m_font = font; 210 | emit fontChanged(m_font); 211 | } 212 | 213 | Settings::Settings(QObject *parent) : QObject(parent) 214 | { 215 | connect(this, &Settings::bridgeChanged, this, &Settings::createSettings); 216 | } 217 | 218 | Settings::~Settings() = default; 219 | 220 | void Settings::setBridge(PreviewBridge *bridge) 221 | { 222 | if (m_bridge == bridge) 223 | { 224 | return; 225 | } 226 | 227 | m_bridge = bridge; 228 | emit bridgeChanged(); 229 | } 230 | 231 | PreviewBridge *Settings::bridge() const 232 | { 233 | return m_bridge.data(); 234 | } 235 | 236 | void Settings::createSettings() 237 | { 238 | if (m_bridge.isNull()) 239 | { 240 | m_settings.reset(); 241 | } 242 | else 243 | { 244 | m_settings = std::make_shared(m_bridge.data()); 245 | m_previewSettings = m_bridge->lastCreatedSettings(); 246 | m_previewSettings->setBorderSizesIndex(m_borderSize); 247 | connect(this, &Settings::borderSizesIndexChanged, m_previewSettings, &PreviewSettings::setBorderSizesIndex); 248 | } 249 | 250 | emit settingsChanged(); 251 | } 252 | 253 | std::shared_ptr Settings::settings() const 254 | { 255 | return m_settings; 256 | } 257 | 258 | KDecoration3::DecorationSettings *Settings::settingsPointer() const 259 | { 260 | return m_settings.get(); 261 | } 262 | 263 | void Settings::setBorderSizesIndex(int index) 264 | { 265 | if (m_borderSize == index) 266 | { 267 | return; 268 | } 269 | 270 | m_borderSize = index; 271 | emit borderSizesIndexChanged(m_borderSize); 272 | } 273 | -------------------------------------------------------------------------------- /libappletdecoration/previewsettings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2014 Martin Gräßlin 3 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 4 | * 5 | * This file is part of the libappletdecoration library 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 8 | */ 9 | 10 | #ifndef KDECOARTIONS_PREVIEW_SETTINGS_H 11 | #define KDECOARTIONS_PREVIEW_SETTINGS_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | class ButtonsModel; 20 | class PreviewBridge; 21 | 22 | class BorderSizesModel : public QAbstractListModel 23 | { 24 | Q_OBJECT 25 | public: 26 | explicit BorderSizesModel(QObject *parent = 0); 27 | virtual ~BorderSizesModel(); 28 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 29 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 30 | QHash roleNames() const override; 31 | 32 | private: 33 | QList m_borders = 34 | QList({ KDecoration3::BorderSize::None, KDecoration3::BorderSize::NoSides, KDecoration3::BorderSize::Tiny, 35 | KDecoration3::BorderSize::Normal, KDecoration3::BorderSize::Large, KDecoration3::BorderSize::VeryLarge, 36 | KDecoration3::BorderSize::Huge, KDecoration3::BorderSize::VeryHuge, KDecoration3::BorderSize::Oversized }); 37 | }; 38 | 39 | class PreviewSettings 40 | : public QObject 41 | , public KDecoration3::DecorationSettingsPrivate 42 | { 43 | Q_OBJECT 44 | Q_PROPERTY(bool onAllDesktopsAvailable READ isOnAllDesktopsAvailable WRITE setOnAllDesktopsAvailable NOTIFY onAllDesktopsAvailableChanged) 45 | Q_PROPERTY(bool alphaChannelSupported READ isAlphaChannelSupported WRITE setAlphaChannelSupported NOTIFY alphaChannelSupportedChanged) 46 | Q_PROPERTY(bool closeOnDoubleClickOnMenu READ isCloseOnDoubleClickOnMenu WRITE setCloseOnDoubleClickOnMenu NOTIFY closeOnDoubleClickOnMenuChanged) 47 | Q_PROPERTY(QAbstractItemModel *leftButtonsModel READ leftButtonsModel CONSTANT) 48 | Q_PROPERTY(QAbstractItemModel *rightButtonsModel READ rightButtonsModel CONSTANT) 49 | Q_PROPERTY(QAbstractItemModel *availableButtonsModel READ availableButtonsModel CONSTANT) 50 | Q_PROPERTY(QAbstractItemModel *borderSizesModel READ borderSizesModel CONSTANT) 51 | Q_PROPERTY(int borderSizesIndex READ borderSizesIndex WRITE setBorderSizesIndex NOTIFY borderSizesIndexChanged) 52 | Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) 53 | public: 54 | explicit PreviewSettings(KDecoration3::DecorationSettings *parent); 55 | virtual ~PreviewSettings(); 56 | bool isAlphaChannelSupported() const override; 57 | bool isOnAllDesktopsAvailable() const override; 58 | bool isCloseOnDoubleClickOnMenu() const override 59 | { 60 | return m_closeOnDoubleClick; 61 | } 62 | KDecoration3::BorderSize borderSize() const override; 63 | 64 | void setOnAllDesktopsAvailable(bool available); 65 | void setAlphaChannelSupported(bool supported); 66 | void setCloseOnDoubleClickOnMenu(bool enabled); 67 | 68 | QAbstractItemModel *leftButtonsModel() const; 69 | QAbstractItemModel *rightButtonsModel() const; 70 | QAbstractItemModel *availableButtonsModel() const; 71 | QAbstractItemModel *borderSizesModel() const 72 | { 73 | return m_borderSizes; 74 | } 75 | 76 | QVector decorationButtonsLeft() const override; 77 | QVector decorationButtonsRight() const override; 78 | 79 | Q_INVOKABLE void addButtonToLeft(int row); 80 | Q_INVOKABLE void addButtonToRight(int row); 81 | 82 | int borderSizesIndex() const 83 | { 84 | return m_borderSize; 85 | } 86 | void setBorderSizesIndex(int index); 87 | 88 | QFont font() const override 89 | { 90 | return m_font; 91 | } 92 | void setFont(const QFont &font); 93 | 94 | Q_SIGNALS: 95 | void onAllDesktopsAvailableChanged(bool); 96 | void alphaChannelSupportedChanged(bool); 97 | void closeOnDoubleClickOnMenuChanged(bool); 98 | void borderSizesIndexChanged(int); 99 | void fontChanged(const QFont &); 100 | 101 | private: 102 | bool m_alphaChannelSupported; 103 | bool m_onAllDesktopsAvailable; 104 | bool m_closeOnDoubleClick; 105 | ButtonsModel *m_leftButtons; 106 | ButtonsModel *m_rightButtons; 107 | ButtonsModel *m_availableButtons; 108 | BorderSizesModel *m_borderSizes; 109 | int m_borderSize; 110 | QFont m_font; 111 | }; 112 | 113 | class Settings : public QObject 114 | { 115 | Q_OBJECT 116 | Q_PROPERTY(PreviewBridge *bridge READ bridge WRITE setBridge NOTIFY bridgeChanged) 117 | Q_PROPERTY(KDecoration3::DecorationSettings *settings READ settingsPointer NOTIFY settingsChanged) 118 | Q_PROPERTY(int borderSizesIndex READ borderSizesIndex WRITE setBorderSizesIndex NOTIFY borderSizesIndexChanged) 119 | public: 120 | explicit Settings(QObject *parent = nullptr); 121 | virtual ~Settings(); 122 | 123 | PreviewBridge *bridge() const; 124 | void setBridge(PreviewBridge *bridge); 125 | 126 | std::shared_ptr settings() const; 127 | KDecoration3::DecorationSettings *settingsPointer() const; 128 | int borderSizesIndex() const 129 | { 130 | return m_borderSize; 131 | } 132 | void setBorderSizesIndex(int index); 133 | 134 | Q_SIGNALS: 135 | void bridgeChanged(); 136 | void settingsChanged(); 137 | void borderSizesIndexChanged(int); 138 | 139 | private: 140 | void createSettings(); 141 | QPointer m_bridge; 142 | std::shared_ptr m_settings; 143 | PreviewSettings *m_previewSettings = nullptr; 144 | int m_borderSize = 3; 145 | }; 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /libappletdecoration/previewshareddecoration.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2019 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 7 | */ 8 | 9 | #include "previewshareddecoration.h" 10 | 11 | #include "previewbridge.h" 12 | #include "previewbutton.h" 13 | #include "previewsettings.h" 14 | 15 | #include 16 | 17 | SharedDecoration::SharedDecoration(QObject *parent) : QObject(parent) 18 | { 19 | connect(this, &SharedDecoration::bridgeChanged, this, &SharedDecoration::createDecoration); 20 | connect(this, &SharedDecoration::settingsChanged, this, &SharedDecoration::applySettings); 21 | } 22 | 23 | SharedDecoration::~SharedDecoration() 24 | { 25 | } 26 | 27 | PreviewBridge *SharedDecoration::bridge() const 28 | { 29 | return m_bridge.data(); 30 | } 31 | 32 | void SharedDecoration::setBridge(PreviewBridge *bridge) 33 | { 34 | if (m_bridge == bridge) 35 | { 36 | return; 37 | } 38 | 39 | if (m_bridge) 40 | { 41 | connect(m_bridge, &PreviewBridge::validChanged, this, &SharedDecoration::createDecoration); 42 | } 43 | 44 | m_bridge = bridge; 45 | 46 | connect(m_bridge, &PreviewBridge::validChanged, this, &SharedDecoration::createDecoration); 47 | 48 | emit bridgeChanged(); 49 | } 50 | 51 | KDecoration3::Decoration *SharedDecoration::decoration() const 52 | { 53 | return m_decoration; 54 | } 55 | 56 | Settings *SharedDecoration::settings() const 57 | { 58 | return m_settings.data(); 59 | } 60 | 61 | void SharedDecoration::setSettings(Settings *settings) 62 | { 63 | if (m_settings == settings) 64 | { 65 | return; 66 | } 67 | 68 | m_settings = settings; 69 | 70 | createDecoration(); 71 | 72 | emit settingsChanged(); 73 | } 74 | 75 | void SharedDecoration::applySettings() 76 | { 77 | if (!m_decoration || !m_settings) 78 | { 79 | return; 80 | } 81 | 82 | m_decoration->setSettings(m_settings->settings()); 83 | m_decoration->init(); 84 | } 85 | 86 | void SharedDecoration::createDecoration() 87 | { 88 | if (!m_bridge || !m_settings) 89 | { 90 | return; 91 | } 92 | 93 | bool newDecoration = (m_bridge->plugin() != m_lastPlugin || m_bridge->theme() != m_lastTheme); 94 | 95 | if (m_decoration && newDecoration) 96 | { 97 | m_decoration->deleteLater(); 98 | } 99 | 100 | if (newDecoration) 101 | { 102 | m_decoration = m_bridge->createDecoration(this); 103 | } 104 | 105 | if (m_decoration) 106 | { 107 | m_decoration->setSettings(m_settings->settings()); 108 | m_decoration->create(); 109 | m_decoration->init(); 110 | m_decoration->apply(m_decoration->nextState()->clone()); 111 | m_decoration->setObjectName("applet-window-buttons"); 112 | } 113 | 114 | m_lastPlugin = m_bridge->plugin(); 115 | m_lastTheme = m_bridge->theme(); 116 | 117 | emit decorationChanged(); 118 | } 119 | 120 | void SharedDecoration::initDecoration() 121 | { 122 | if (m_decoration) 123 | { 124 | m_decoration->init(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /libappletdecoration/previewshareddecoration.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2019 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 7 | */ 8 | 9 | #ifndef PREVIEWSHAREDDECORATION_H 10 | #define PREVIEWSHAREDDECORATION_H 11 | 12 | #include "previewbridge.h" 13 | #include "previewsettings.h" 14 | 15 | #include 16 | 17 | class PreviewBridge; 18 | class PreviewButton; 19 | class Settings; 20 | 21 | class SharedDecoration : public QObject 22 | { 23 | Q_OBJECT 24 | Q_PROPERTY(PreviewBridge *bridge READ bridge WRITE setBridge NOTIFY bridgeChanged) 25 | Q_PROPERTY(Settings *settings READ settings WRITE setSettings NOTIFY settingsChanged) 26 | 27 | public: 28 | explicit SharedDecoration(QObject *parent = nullptr); 29 | virtual ~SharedDecoration(); 30 | 31 | PreviewBridge *bridge() const; 32 | void setBridge(PreviewBridge *bridge); 33 | 34 | Settings *settings() const; 35 | void setSettings(Settings *settings); 36 | 37 | KDecoration3::Decoration *decoration() const; 38 | 39 | void initDecoration(); 40 | 41 | public Q_SLOTS: 42 | Q_INVOKABLE void createDecoration(); 43 | 44 | Q_SIGNALS: 45 | void bridgeChanged(); 46 | void decorationChanged(); 47 | void settingsChanged(); 48 | 49 | private Q_SLOTS: 50 | void applySettings(); 51 | 52 | private: 53 | QPointer m_bridge; 54 | QPointer m_decoration; 55 | QPointer m_settings; 56 | 57 | QString m_lastPlugin; 58 | QString m_lastTheme; 59 | }; 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /libappletdecoration/qml/AuroraeButton.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | import QtQuick 2.7 10 | 11 | import org.kde.plasma.plasmoid 2.0 12 | import org.kde.ksvg as KSvg 13 | 14 | import org.kde.appletdecoration 0.1 as AppletDecoration 15 | 16 | MouseArea{ 17 | id: button 18 | hoverEnabled: true 19 | 20 | property bool isActive: true 21 | property bool isOnAllDesktops: false 22 | property bool isKeepAbove: false 23 | property bool isMaximized: false 24 | readonly property bool isToggledActivated: { 25 | return ((isOnAllDesktops && buttonType === AppletDecoration.Types.OnAllDesktops) || 26 | (isKeepAbove && buttonType === AppletDecoration.Types.KeepAbove) 27 | ); 28 | } 29 | 30 | property bool monochromeIconsEnabled: false 31 | property color monochromeIconsColor: "white" 32 | 33 | property int topPadding: 0 34 | property int bottomPadding: 0 35 | property int leftPadding: 0 36 | property int rightPadding: 0 37 | property int buttonType: AppletDecoration.Types.Close 38 | property int duration: auroraeTheme ? auroraeTheme.duration : 0 39 | 40 | property QtObject auroraeTheme: null 41 | 42 | property string buttonImagePath: auroraeTheme ? auroraeTheme.themePath + '/' + auroraeTheme.monochromePrefix + iconName + '.' + auroraeTheme.themeType : "" 43 | 44 | property string iconName: { 45 | switch(buttonType){ 46 | case AppletDecoration.Types.Close: return "close"; 47 | case AppletDecoration.Types.Minimize: return "minimize"; 48 | case AppletDecoration.Types.Maximize: return (auroraeTheme.hasRestoreButton && button.isMaximized ? "restore" : "maximize"); 49 | case AppletDecoration.Types.OnAllDesktops: return "alldesktops"; 50 | case AppletDecoration.Types.KeepAbove: return "keepabove" 51 | default: return "close"; 52 | } 53 | } 54 | 55 | property string svgNormalElementId:{ 56 | return isActive ? "active-center" : "inactive-center"; 57 | } 58 | 59 | property string svgHoveredElementId:{ 60 | return containsPress || isToggledActivated ? "pressed-center" : "hover-center"; 61 | } 62 | 63 | KSvg.Svg { 64 | id: buttonSvg 65 | imagePath: buttonImagePath 66 | } 67 | 68 | // normal icon 69 | Item { 70 | id: svgNormalItem 71 | anchors.fill: parent 72 | anchors.topMargin: topPadding 73 | anchors.bottomMargin: bottomPadding 74 | anchors.leftMargin: leftPadding 75 | anchors.rightMargin: rightPadding 76 | 77 | opacity: !containsMouse && !containsPress && !isToggledActivated ? 1 : 0 78 | 79 | KSvg.SvgItem { 80 | x: (parent.width / 2) - (width / 2) 81 | y: (parent.height / 2 ) - (height / 2) 82 | 83 | width: auroraeTheme.buttonRatio * height 84 | height: minimumSide 85 | 86 | svg: buttonSvg 87 | elementId: svgNormalElementId 88 | 89 | readonly property int minimumSide: Math.min(parent.width,parent.height) 90 | } 91 | 92 | 93 | Behavior on opacity { 94 | NumberAnimation { 95 | duration: button.duration 96 | easing.type: Easing.Linear 97 | } 98 | } 99 | } 100 | 101 | //! monochromize icon 102 | Loader { 103 | anchors.fill: svgNormalItem 104 | active: monochromeIconsEnabled 105 | // sourceComponent: ColorOverlay { 106 | // color: monochromeIconsColor 107 | // source: svgNormalItem 108 | // } 109 | } 110 | 111 | // hovered icon 112 | KSvg.SvgItem { 113 | id: svgHoveredItem 114 | anchors.fill: parent 115 | anchors.topMargin: topPadding 116 | anchors.bottomMargin: bottomPadding 117 | anchors.leftMargin: leftPadding 118 | anchors.rightMargin: rightPadding 119 | 120 | opacity: Math.abs(svgNormalItem.opacity - 1) 121 | 122 | KSvg.SvgItem { 123 | x: (parent.width / 2) - (width / 2) 124 | y: (parent.height / 2 ) - (height / 2) 125 | 126 | width: auroraeTheme.buttonRatio * height 127 | height: minimumSide 128 | 129 | svg: buttonSvg 130 | elementId: svgHoveredElementId 131 | 132 | readonly property int minimumSide: Math.min(parent.width,parent.height) 133 | } 134 | } 135 | 136 | //! monochromize icon 137 | Loader { 138 | anchors.fill: svgHoveredItem 139 | active: monochromeIconsEnabled && svgHoveredItem.opacity>0 140 | // sourceComponent: ColorOverlay { 141 | // color: monochromeIconsColor 142 | // source: svgHoveredItem 143 | // } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /libappletdecoration/qmldir: -------------------------------------------------------------------------------- 1 | module org.kde.appletdecoration 2 | 3 | plugin appletdecorationplugin 4 | AuroraeButton 0.1 AuroraeButton.qml 5 | -------------------------------------------------------------------------------- /libappletdecoration/schemecolors.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | * 8 | */ 9 | 10 | #include "schemecolors.h" 11 | 12 | #include "commontools.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | using namespace Qt::StringLiterals; 23 | 24 | SchemeColors::SchemeColors(QObject *parent, QString scheme, bool plasmaTheme) : QObject(parent), m_basedOnPlasmaTheme(plasmaTheme) 25 | { 26 | QString pSchemeFile = possibleSchemeFile(scheme); 27 | 28 | if (QFileInfo(pSchemeFile).exists()) 29 | { 30 | setSchemeFile(pSchemeFile); 31 | m_schemeName = schemeName(pSchemeFile); 32 | 33 | //! track scheme file for changes 34 | 35 | //! do not create so many trackers 36 | /*KDirWatch::self()->addFile(m_schemeFile); 37 | 38 | connect(KDirWatch::self(), &KDirWatch::dirty, this, [ & ](const QString & path) { 39 | if (path == m_schemeFile) { 40 | updateScheme(); 41 | } 42 | });*/ 43 | } 44 | 45 | updateScheme(); 46 | } 47 | 48 | SchemeColors::~SchemeColors() 49 | { 50 | } 51 | 52 | QColor SchemeColors::backgroundColor() const 53 | { 54 | return m_activeBackgroundColor; 55 | } 56 | 57 | QColor SchemeColors::textColor() const 58 | { 59 | return m_activeTextColor; 60 | } 61 | 62 | QColor SchemeColors::inactiveBackgroundColor() const 63 | { 64 | return m_inactiveBackgroundColor; 65 | } 66 | 67 | QColor SchemeColors::inactiveTextColor() const 68 | { 69 | return m_inactiveTextColor; 70 | } 71 | 72 | QColor SchemeColors::highlightColor() const 73 | { 74 | return m_highlightColor; 75 | } 76 | 77 | QColor SchemeColors::highlightedTextColor() const 78 | { 79 | return m_highlightedTextColor; 80 | } 81 | 82 | QColor SchemeColors::positiveText() const 83 | { 84 | return m_positiveColor; 85 | } 86 | 87 | QColor SchemeColors::neutralText() const 88 | { 89 | return m_neutralText; 90 | } 91 | 92 | QColor SchemeColors::negativeText() const 93 | { 94 | return m_negativeText; 95 | } 96 | 97 | QColor SchemeColors::buttonTextColor() const 98 | { 99 | return m_buttonTextColor; 100 | } 101 | 102 | QColor SchemeColors::buttonBackgroundColor() const 103 | { 104 | return m_buttonBackgroundColor; 105 | } 106 | 107 | QColor SchemeColors::buttonHoverColor() const 108 | { 109 | return m_buttonHoverColor; 110 | } 111 | 112 | QColor SchemeColors::buttonFocusColor() const 113 | { 114 | return m_buttonFocusColor; 115 | } 116 | 117 | QString SchemeColors::schemeName() const 118 | { 119 | return m_schemeName; 120 | } 121 | 122 | QString SchemeColors::SchemeColors::schemeFile() const 123 | { 124 | return m_schemeFile; 125 | } 126 | 127 | void SchemeColors::setSchemeFile(QString file) 128 | { 129 | if (m_schemeFile == file) 130 | { 131 | return; 132 | } 133 | 134 | m_schemeFile = file; 135 | emit schemeFileChanged(); 136 | } 137 | 138 | QString SchemeColors::possibleSchemeFile(QString scheme) 139 | { 140 | if (scheme.startsWith("/") && scheme.endsWith("colors") && QFileInfo(scheme).exists()) 141 | { 142 | return scheme; 143 | } 144 | 145 | QString tempScheme = scheme; 146 | 147 | if (scheme == "kdeglobals") 148 | { 149 | QString settingsFile = QDir::homePath() + "/.config/kdeglobals"; 150 | 151 | if (QFileInfo(settingsFile).exists()) 152 | { 153 | KSharedConfigPtr filePtr = KSharedConfig::openConfig(settingsFile); 154 | KConfigGroup generalGroup = KConfigGroup(filePtr, u"General"_qs); 155 | tempScheme = generalGroup.readEntry("ColorScheme", "BreezeLight"); 156 | } 157 | } 158 | 159 | //! remove all whitespaces and "-" from scheme in order to access correctly its file 160 | QString schemeNameSimplified = tempScheme.simplified().remove(" ").remove("-"); 161 | 162 | return standardPath("color-schemes/" + schemeNameSimplified + ".colors"); 163 | } 164 | 165 | QString SchemeColors::schemeName(QString originalFile) 166 | { 167 | if (!(originalFile.startsWith("/") && originalFile.endsWith("colors") && QFileInfo(originalFile).exists())) 168 | { 169 | return ""; 170 | } 171 | 172 | QString fileNameNoExt = originalFile; 173 | 174 | int lastSlash = originalFile.lastIndexOf("/"); 175 | 176 | if (lastSlash >= 0) 177 | { 178 | fileNameNoExt.remove(0, lastSlash + 1); 179 | } 180 | 181 | if (fileNameNoExt.endsWith(".colors")) 182 | { 183 | fileNameNoExt.remove(".colors"); 184 | } 185 | 186 | KSharedConfigPtr filePtr = KSharedConfig::openConfig(originalFile); 187 | KConfigGroup generalGroup = KConfigGroup(filePtr, u"General"_qs); 188 | 189 | return generalGroup.readEntry("Name", fileNameNoExt); 190 | } 191 | 192 | void SchemeColors::updateScheme() 193 | { 194 | if (m_schemeFile.isEmpty() || !QFileInfo(m_schemeFile).exists()) 195 | { 196 | return; 197 | } 198 | 199 | KSharedConfigPtr filePtr = KSharedConfig::openConfig(m_schemeFile); 200 | KConfigGroup wmGroup = KConfigGroup(filePtr, u"WM"_qs); 201 | KConfigGroup selGroup = KConfigGroup(filePtr, u"Colors:Selection"_qs); 202 | KConfigGroup viewGroup = KConfigGroup(filePtr, u"Colors:View"_qs); 203 | // KConfigGroup windowGroup = KConfigGroup(filePtr, "Colors:Window"); 204 | KConfigGroup buttonGroup = KConfigGroup(filePtr, u"Colors:Button"_qs); 205 | 206 | if (!m_basedOnPlasmaTheme) 207 | { 208 | m_activeBackgroundColor = wmGroup.readEntry("activeBackground", QColor()); 209 | m_activeTextColor = wmGroup.readEntry("activeForeground", QColor()); 210 | m_inactiveBackgroundColor = wmGroup.readEntry("inactiveBackground", QColor()); 211 | m_inactiveTextColor = wmGroup.readEntry("inactiveForeground", QColor()); 212 | } 213 | else 214 | { 215 | m_activeBackgroundColor = viewGroup.readEntry("BackgroundNormal", QColor()); 216 | m_activeTextColor = viewGroup.readEntry("ForegroundNormal", QColor()); 217 | m_inactiveBackgroundColor = viewGroup.readEntry("BackgroundAlternate", QColor()); 218 | m_inactiveTextColor = viewGroup.readEntry("ForegroundInactive", QColor()); 219 | } 220 | 221 | m_highlightColor = selGroup.readEntry("BackgroundNormal", QColor()); 222 | m_highlightedTextColor = selGroup.readEntry("ForegroundNormal", QColor()); 223 | 224 | m_positiveColor = selGroup.readEntry("ForegroundPositive", QColor()); 225 | m_neutralText = selGroup.readEntry("ForegroundNeutral", QColor()); 226 | ; 227 | m_negativeText = selGroup.readEntry("ForegroundNegative", QColor()); 228 | 229 | m_buttonTextColor = buttonGroup.readEntry("ForegroundNormal", QColor()); 230 | m_buttonBackgroundColor = buttonGroup.readEntry("BackgroundNormal", QColor()); 231 | m_buttonHoverColor = buttonGroup.readEntry("DecorationHover", QColor()); 232 | m_buttonFocusColor = buttonGroup.readEntry("DecorationFocus", QColor()); 233 | 234 | emit colorsChanged(); 235 | } 236 | -------------------------------------------------------------------------------- /libappletdecoration/schemecolors.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | * 8 | */ 9 | 10 | #ifndef SCHEMECOLORS_H 11 | #define SCHEMECOLORS_H 12 | 13 | #include 14 | #include 15 | 16 | class SchemeColors : public QObject 17 | { 18 | Q_OBJECT 19 | Q_PROPERTY(QString schemeFile READ schemeFile NOTIFY schemeFileChanged) 20 | 21 | Q_PROPERTY(QColor backgroundColor READ backgroundColor NOTIFY colorsChanged) 22 | Q_PROPERTY(QColor textColor READ textColor NOTIFY colorsChanged) 23 | Q_PROPERTY(QColor inactiveBackgroundColor READ inactiveBackgroundColor NOTIFY colorsChanged) 24 | Q_PROPERTY(QColor inactiveTextColor READ inactiveTextColor NOTIFY colorsChanged) 25 | 26 | Q_PROPERTY(QColor highlightColor READ highlightColor NOTIFY colorsChanged) 27 | Q_PROPERTY(QColor highlightedTextColor READ highlightedTextColor NOTIFY colorsChanged) 28 | Q_PROPERTY(QColor positiveText READ positiveText NOTIFY colorsChanged) 29 | Q_PROPERTY(QColor neutralText READ neutralText NOTIFY colorsChanged) 30 | Q_PROPERTY(QColor negativeText READ negativeText NOTIFY colorsChanged) 31 | 32 | Q_PROPERTY(QColor buttonTextColor READ buttonTextColor NOTIFY colorsChanged) 33 | Q_PROPERTY(QColor buttonBackgroundColor READ buttonBackgroundColor NOTIFY colorsChanged) 34 | Q_PROPERTY(QColor buttonHoverColor READ buttonHoverColor NOTIFY colorsChanged) 35 | Q_PROPERTY(QColor buttonFocusColor READ buttonFocusColor NOTIFY colorsChanged) 36 | 37 | public: 38 | SchemeColors(QObject *parent, QString scheme, bool plasmaTheme = false); 39 | ~SchemeColors() override; 40 | 41 | QString schemeName() const; 42 | 43 | QString schemeFile() const; 44 | void setSchemeFile(QString file); 45 | 46 | QColor backgroundColor() const; 47 | QColor textColor() const; 48 | QColor inactiveBackgroundColor() const; 49 | QColor inactiveTextColor() const; 50 | QColor highlightColor() const; 51 | QColor highlightedTextColor() const; 52 | QColor positiveText() const; 53 | QColor neutralText() const; 54 | QColor negativeText() const; 55 | 56 | QColor buttonTextColor() const; 57 | QColor buttonBackgroundColor() const; 58 | QColor buttonHoverColor() const; 59 | QColor buttonFocusColor() const; 60 | 61 | static QString possibleSchemeFile(QString scheme); 62 | static QString schemeName(QString originalFile); 63 | 64 | signals: 65 | void colorsChanged(); 66 | void schemeFileChanged(); 67 | 68 | public slots: 69 | void updateScheme(); 70 | 71 | private: 72 | bool m_basedOnPlasmaTheme{ false }; 73 | 74 | QString m_schemeName; 75 | QString m_schemeFile; 76 | 77 | QColor m_activeBackgroundColor; 78 | QColor m_activeTextColor; 79 | 80 | QColor m_inactiveBackgroundColor; 81 | QColor m_inactiveTextColor; 82 | 83 | QColor m_highlightColor; 84 | QColor m_highlightedTextColor; 85 | QColor m_positiveColor; 86 | QColor m_neutralText; 87 | QColor m_negativeText; 88 | 89 | QColor m_buttonTextColor; 90 | QColor m_buttonBackgroundColor; 91 | QColor m_buttonHoverColor; 92 | QColor m_buttonFocusColor; 93 | }; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /libappletdecoration/schemesmodel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | * 8 | */ 9 | 10 | #include "schemesmodel.h" 11 | 12 | #include "commontools.h" 13 | #include "schemecolors.h" 14 | 15 | #include 16 | #include 17 | 18 | SchemesModel::SchemesModel(QObject *parent) : QAbstractListModel(parent) 19 | { 20 | initSchemes(); 21 | } 22 | 23 | SchemesModel::~SchemesModel() 24 | { 25 | qDeleteAll(m_schemes); 26 | } 27 | 28 | QVariant SchemesModel::data(const QModelIndex &index, int role) const 29 | { 30 | if (!index.isValid() || index.column() != 0 || index.row() < 0 || index.row() >= m_schemes.count()) 31 | { 32 | return QVariant(); 33 | } 34 | 35 | const SchemeColors *d = m_schemes[index.row()]; 36 | 37 | switch (role) 38 | { 39 | case Qt::DisplayRole: 40 | if (index.row() == 0) 41 | { 42 | return "Current"; 43 | } 44 | else if (index.row() == 1) 45 | { 46 | return "Plasma Theme"; 47 | } 48 | 49 | return d->schemeName(); 50 | 51 | case Qt::UserRole + 4: 52 | if (index.row() == 0) 53 | { 54 | return "kdeglobals"; 55 | } 56 | else if (index.row() == 1) 57 | { 58 | return "_plasmatheme_"; 59 | } 60 | 61 | return d->schemeFile(); 62 | 63 | case Qt::UserRole + 5: return d->backgroundColor(); 64 | 65 | case Qt::UserRole + 6: return d->textColor(); 66 | } 67 | 68 | return QVariant(); 69 | } 70 | 71 | int SchemesModel::rowCount(const QModelIndex &parent) const 72 | { 73 | if (parent.isValid()) 74 | { 75 | return 0; 76 | } 77 | 78 | return m_schemes.count(); 79 | } 80 | 81 | QHash SchemesModel::roleNames() const 82 | { 83 | QHash roles({ { Qt::DisplayRole, QByteArrayLiteral("display") }, 84 | { Qt::UserRole + 4, QByteArrayLiteral("file") }, 85 | { Qt::UserRole + 5, QByteArrayLiteral("backgroundColor") }, 86 | { Qt::UserRole + 6, QByteArrayLiteral("textColor") } }); 87 | return roles; 88 | } 89 | 90 | QColor SchemesModel::backgroundOf(const int &index) const 91 | { 92 | if (index == 0) 93 | { 94 | auto ind = indexOf(m_defaultSchemeFile); 95 | return ind >= 0 ? m_schemes[ind]->backgroundColor() : QColor("transparent"); 96 | } 97 | 98 | if (index > 0 && index < m_schemes.count()) 99 | { 100 | return m_schemes[index]->backgroundColor(); 101 | } 102 | 103 | return QColor("transparent"); 104 | } 105 | 106 | QString SchemesModel::defaultSchemeFile() const 107 | { 108 | auto ind = indexOf(m_defaultSchemeFile); 109 | 110 | return ind >= 0 ? m_schemes[ind]->schemeFile() : QString(); 111 | } 112 | 113 | void SchemesModel::initSchemes() 114 | { 115 | qDeleteAll(m_schemes); 116 | m_schemes.clear(); 117 | 118 | QString currentSchemePath = SchemeColors::possibleSchemeFile("kdeglobals"); 119 | insertSchemeInList(currentSchemePath); 120 | m_defaultSchemeFile = currentSchemePath; 121 | 122 | QStringList standardPaths = standardPathsFor("color-schemes"); 123 | 124 | QStringList registeredSchemes; 125 | 126 | for (auto path : standardPaths) 127 | { 128 | QDir directory(path); 129 | QStringList tempSchemes = directory.entryList(QStringList() << "*.colors" 130 | << "*.COLORS", 131 | QDir::Files); 132 | 133 | foreach (QString filename, tempSchemes) 134 | { 135 | if (!registeredSchemes.contains(filename)) 136 | { 137 | QString fullPath = path + "/" + filename; 138 | insertSchemeInList(fullPath); 139 | registeredSchemes << filename; 140 | } 141 | } 142 | } 143 | } 144 | 145 | void SchemesModel::insertSchemeInList(QString file) 146 | { 147 | SchemeColors *tempScheme = new SchemeColors(this, file); 148 | 149 | int atPos{ 0 }; 150 | 151 | for (int i = 0; i < m_schemes.count(); i++) 152 | { 153 | SchemeColors *s = m_schemes[i]; 154 | 155 | int result = QString::compare(tempScheme->schemeName(), s->schemeName(), Qt::CaseInsensitive); 156 | 157 | if (result < 0) 158 | { 159 | atPos = i; 160 | break; 161 | } 162 | else 163 | { 164 | atPos = i + 1; 165 | } 166 | } 167 | 168 | m_schemes.insert(atPos, tempScheme); 169 | } 170 | 171 | int SchemesModel::indexOf(QString file) const 172 | { 173 | if (file.isEmpty() || file == "kdeglobals") 174 | { 175 | return 0; 176 | } 177 | 178 | if (file == "_plasmatheme_") 179 | { 180 | return 1; 181 | } 182 | 183 | for (int i = 0; i < m_schemes.count(); i++) 184 | { 185 | SchemeColors *s = m_schemes[i]; 186 | 187 | if (s->schemeFile() == file) 188 | { 189 | return i; 190 | } 191 | } 192 | 193 | return -1; 194 | } 195 | -------------------------------------------------------------------------------- /libappletdecoration/schemesmodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | * 8 | */ 9 | 10 | #ifndef SCHEMESMODEL_H 11 | #define SCHEMESMODEL_H 12 | 13 | #include 14 | 15 | class SchemeColors; 16 | 17 | class SchemesModel : public QAbstractListModel 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | explicit SchemesModel(QObject *parent = nullptr); 23 | virtual ~SchemesModel(); 24 | 25 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 26 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 27 | QHash roleNames() const override; 28 | 29 | Q_INVOKABLE int indexOf(QString file) const; 30 | Q_INVOKABLE QColor backgroundOf(const int &index) const; 31 | 32 | Q_INVOKABLE QString defaultSchemeFile() const; 33 | private slots: 34 | void initSchemes(); 35 | 36 | private: 37 | void insertSchemeInList(QString file); 38 | 39 | private: 40 | QString m_defaultSchemeFile; 41 | QList m_schemes; 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /libappletdecoration/themeextended.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | * 8 | */ 9 | 10 | #include "themeextended.h" 11 | 12 | #include "commontools.h" 13 | #include "schemecolors.h" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define DEFAULTCOLORSCHEME "default.colors" 22 | 23 | ExtendedTheme::ExtendedTheme(QObject *parent) : QObject(parent) 24 | { 25 | load(); 26 | 27 | connect(&m_theme, &Plasma::Theme::themeChanged, this, &ExtendedTheme::load); 28 | connect(&m_theme, &Plasma::Theme::themeChanged, this, &ExtendedTheme::themeChanged); 29 | } 30 | 31 | ExtendedTheme::~ExtendedTheme() 32 | { 33 | m_colorsScheme->deleteLater(); 34 | } 35 | 36 | void ExtendedTheme::load() 37 | { 38 | loadThemePaths(); 39 | } 40 | 41 | QObject *ExtendedTheme::colors() const 42 | { 43 | return m_colorsScheme; 44 | } 45 | 46 | void ExtendedTheme::setOriginalSchemeFile(const QString &file) 47 | { 48 | if (m_originalSchemePath == file) 49 | { 50 | return; 51 | } 52 | 53 | m_originalSchemePath = file; 54 | 55 | qDebug() << "Window Buttons : plasma theme original colors ::: " << m_originalSchemePath; 56 | 57 | updateDefaultScheme(); 58 | 59 | emit themeChanged(); 60 | } 61 | 62 | //! WM records need to be updated based on the colors that 63 | //! plasma will use in order to be consistent. Such an example 64 | //! are the Breeze color schemes that have different values for 65 | //! WM and the plasma theme records 66 | void ExtendedTheme::updateDefaultScheme() 67 | { 68 | QString defaultFilePath = m_extendedThemeDir.path() + "/" + DEFAULTCOLORSCHEME; 69 | if (QFileInfo(defaultFilePath).exists()) 70 | { 71 | QFile(defaultFilePath).remove(); 72 | } 73 | 74 | QFile(m_originalSchemePath).copy(defaultFilePath); 75 | m_colorsSchemePath = defaultFilePath; 76 | 77 | updateDefaultSchemeValues(); 78 | 79 | if (m_colorsScheme) 80 | { 81 | disconnect(m_colorsScheme, &SchemeColors::colorsChanged, this, &ExtendedTheme::themeChanged); 82 | m_colorsScheme->deleteLater(); 83 | } 84 | 85 | m_colorsScheme = new SchemeColors(this, m_colorsSchemePath, true); 86 | connect(m_colorsScheme, &SchemeColors::colorsChanged, this, &ExtendedTheme::themeChanged); 87 | 88 | qDebug() << "Window Buttons : plasma theme default colors ::: " << m_colorsSchemePath; 89 | 90 | emit colorsChanged(); 91 | } 92 | 93 | void ExtendedTheme::updateDefaultSchemeValues() 94 | { 95 | //! update WM values based on original scheme 96 | KSharedConfigPtr originalPtr = KSharedConfig::openConfig(m_originalSchemePath); 97 | KSharedConfigPtr defaultPtr = KSharedConfig::openConfig(m_colorsSchemePath); 98 | 99 | if (originalPtr && defaultPtr) 100 | { 101 | KConfigGroup normalWindowGroup(originalPtr, u"Colors:Window"_qs); 102 | KConfigGroup defaultWMGroup(defaultPtr, u"WM"_qs); 103 | 104 | defaultWMGroup.writeEntry("activeBackground", normalWindowGroup.readEntry("BackgroundNormal", QColor())); 105 | defaultWMGroup.writeEntry("activeForeground", normalWindowGroup.readEntry("ForegroundNormal", QColor())); 106 | 107 | defaultWMGroup.sync(); 108 | } 109 | } 110 | 111 | void ExtendedTheme::loadThemePaths() 112 | { 113 | m_themePath = standardPath("plasma/desktoptheme/" + m_theme.themeName()); 114 | 115 | if (QDir(m_themePath + "/widgets").exists()) 116 | { 117 | m_themeWidgetsPath = m_themePath + "/widgets"; 118 | } 119 | else 120 | { 121 | m_themeWidgetsPath = standardPath("plasma/desktoptheme/default/widgets"); 122 | } 123 | 124 | qDebug() << "Window Buttons : current plasma theme ::: " << m_theme.themeName(); 125 | qDebug() << "Window Buttons : theme path ::: " << m_themePath; 126 | qDebug() << "Window Buttons : theme widgets path ::: " << m_themeWidgetsPath; 127 | 128 | //! clear kde connections 129 | for (auto &c : m_kdeConnections) 130 | { 131 | disconnect(c); 132 | } 133 | 134 | //! assign color schemes 135 | QString themeColorScheme = m_themePath + "/colors"; 136 | 137 | if (QFileInfo(themeColorScheme).exists()) 138 | { 139 | setOriginalSchemeFile(themeColorScheme); 140 | } 141 | else 142 | { 143 | //! when plasma theme uses the kde colors 144 | //! we track when kde color scheme is changing 145 | QString kdeSettingsFile = QDir::homePath() + "/.config/kdeglobals"; 146 | 147 | KDirWatch::self()->addFile(kdeSettingsFile); 148 | 149 | m_kdeConnections[0] = connect(KDirWatch::self(), &KDirWatch::dirty, this, 150 | [&, kdeSettingsFile](const QString &path) 151 | { 152 | if (path == kdeSettingsFile) 153 | { 154 | this->setOriginalSchemeFile(SchemeColors::possibleSchemeFile("kdeglobals")); 155 | } 156 | }); 157 | 158 | m_kdeConnections[1] = connect(KDirWatch::self(), &KDirWatch::created, this, 159 | [&, kdeSettingsFile](const QString &path) 160 | { 161 | if (path == kdeSettingsFile) 162 | { 163 | this->setOriginalSchemeFile(SchemeColors::possibleSchemeFile("kdeglobals")); 164 | } 165 | }); 166 | 167 | setOriginalSchemeFile(SchemeColors::possibleSchemeFile("kdeglobals")); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /libappletdecoration/themeextended.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | * 8 | */ 9 | 10 | #ifndef PLASMAEXTENDEDTHEME_H 11 | #define PLASMAEXTENDEDTHEME_H 12 | 13 | #include "schemecolors.h" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | class ExtendedTheme : public QObject 24 | { 25 | Q_OBJECT 26 | Q_PROPERTY(QObject *colors READ colors NOTIFY colorsChanged) 27 | 28 | public: 29 | ExtendedTheme(QObject *parent = nullptr); 30 | ~ExtendedTheme() override; 31 | ; 32 | 33 | QObject *colors() const; 34 | 35 | void load(); 36 | 37 | signals: 38 | void colorsChanged(); 39 | void themeChanged(); 40 | 41 | private: 42 | void loadThemePaths(); 43 | 44 | void setOriginalSchemeFile(const QString &file); 45 | void updateDefaultScheme(); 46 | void updateDefaultSchemeValues(); 47 | 48 | private: 49 | QString m_themePath; 50 | QString m_themeWidgetsPath; 51 | QString m_colorsSchemePath; 52 | QString m_originalSchemePath; 53 | 54 | std::array m_kdeConnections; 55 | 56 | QTemporaryDir m_extendedThemeDir; 57 | KConfigGroup m_themeGroup; 58 | Plasma::Theme m_theme; 59 | 60 | SchemeColors *m_colorsScheme{ nullptr }; 61 | }; 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /libappletdecoration/types.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #include "types.h" 10 | -------------------------------------------------------------------------------- /libappletdecoration/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of the libappletdecoration library 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #ifndef TYPES_H 10 | #define TYPES_H 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | class Types 17 | { 18 | Q_GADGET 19 | 20 | public: 21 | Types() = delete; 22 | ~Types(){}; 23 | 24 | enum ButtonType 25 | { 26 | Menu = 0, 27 | ApplicationMenu, 28 | OnAllDesktops, 29 | Minimize, 30 | Maximize, 31 | Close, 32 | ContextHelp, 33 | Shade, 34 | KeepBelow, 35 | KeepAbove, 36 | Custom 37 | }; 38 | Q_ENUM(ButtonType) 39 | 40 | enum Actions 41 | { 42 | ActionClose = 0, 43 | ToggleMinimize, 44 | ToggleMaximize, 45 | TogglePinToAllDesktops, 46 | ToggleKeepAbove 47 | }; 48 | Q_ENUM(Actions) 49 | 50 | enum ButtonSize 51 | { 52 | TinyButton = 0, 53 | NormalButton, 54 | LargeButton, 55 | VeryLargeButton, 56 | HugeButton, 57 | VeryHugeButton, 58 | OversizedButton 59 | }; 60 | Q_ENUM(ButtonSize) 61 | 62 | enum Visibility 63 | { 64 | AlwaysVisible = 0, 65 | ActiveWindow, 66 | ActiveMaximizedWindow, 67 | ShownWindowExists 68 | }; 69 | Q_ENUM(Visibility) 70 | 71 | enum HiddenState 72 | { 73 | SlideOut = 0, 74 | EmptySpace 75 | }; 76 | Q_ENUM(HiddenState) 77 | }; 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /package/contents/code/tools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of applet-window-buttons 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | function addButton(preparedArray, buttonType) { 10 | if (buttonType === AppletDecoration.Types.Close) { 11 | preparedArray.push({ 12 | buttonType: AppletDecoration.Types.Close, 13 | windowOperation: AppletDecoration.Types.ActionClose 14 | }); 15 | } else if (buttonType === AppletDecoration.Types.Maximize) { 16 | preparedArray.push({ 17 | buttonType: AppletDecoration.Types.Maximize, 18 | windowOperation: AppletDecoration.Types.ToggleMaximize 19 | }); 20 | } else if (buttonType === AppletDecoration.Types.Minimize) { 21 | preparedArray.push({ 22 | buttonType: AppletDecoration.Types.Minimize, 23 | windowOperation: AppletDecoration.Types.ToggleMinimize 24 | }); 25 | } else if (buttonType === AppletDecoration.Types.OnAllDesktops) { 26 | preparedArray.push({ 27 | buttonType: AppletDecoration.Types.OnAllDesktops, 28 | windowOperation: AppletDecoration.Types.TogglePinToAllDesktops 29 | }); 30 | } else if (buttonType === AppletDecoration.Types.Custom) { 31 | preparedArray.push({ 32 | buttonType: AppletDecoration.Types.Custom, 33 | windowOperation: -1 34 | }); 35 | } else if (buttonType === AppletDecoration.Types.KeepAbove) { 36 | preparedArray.push({ 37 | buttonType: AppletDecoration.Types.KeepAbove, 38 | windowOperation: AppletDecoration.Types.ToggleKeepAbove 39 | }); 40 | } 41 | } 42 | 43 | function indexOfSplitter(listModel) { 44 | for (var i = 0; i < listModel.count; ++i) { 45 | var item = listModel.get(i); 46 | 47 | if (item.buttonType === AppletDecoration.Types.Custom) { 48 | return i; 49 | } 50 | } 51 | 52 | return -1; 53 | } 54 | 55 | function initializeControlButtonsModel(buttons, toArray, toListModel, stopOnSeparator) { 56 | toArray.length = 0; 57 | 58 | for (var i = 0; i < buttons.length; ++i) { 59 | var type = Number(buttons[i]); 60 | 61 | if (type === AppletDecoration.Types.Custom && stopOnSeparator) { 62 | break; 63 | } 64 | 65 | addButton(toArray, Number(buttons[i])); 66 | } 67 | 68 | toListModel.clear() 69 | 70 | for (var i = 0; i < toArray.length; ++i) { 71 | toListModel.append(toArray[i]); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /package/contents/config/config.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * SPDX-FileCopyrightText: 2024 Christian Tallner 4 | * 5 | * This file is part of applet-window-buttons 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | 10 | import QtQuick 11 | import org.kde.plasma.configuration 12 | 13 | ConfigModel { 14 | ConfigCategory { 15 | name: i18n("General") 16 | icon: "preferences-desktop-display-color" 17 | source: "config/ConfigGeneral.qml" 18 | } 19 | 20 | ConfigCategory { 21 | name: i18n("Behavior") 22 | icon: "preferences-desktop" 23 | source: "config/ConfigBehavior.qml" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /package/contents/config/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | 12 | 13 | 14 | true 15 | 16 | 17 | 18 | org.kde.breeze 19 | 20 | 21 | 22 | _plasmatheme_ 23 | 24 | 25 | 26 | 27 | 28 | 29 | 5|4|3|10|2|9 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 0 40 | 41 | 42 | true 43 | 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 0 56 | 57 | 58 | false 59 | 60 | 61 | 62 | true 63 | 64 | 65 | 66 | 100 67 | 68 | 69 | 70 | 0 71 | 72 | 73 | 74 | 0 75 | 76 | 77 | 78 | true 79 | 80 | 81 | 82 | 4 83 | 84 | 85 | 86 | 2 87 | 88 | 89 | 90 | false 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /package/contents/ui/PlasmaTasksModel.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of applet-window-buttons 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | import QtQml.Models 2.2 10 | import QtQuick 2.7 11 | import org.kde.plasma.core 2.0 as PlasmaCore 12 | import org.kde.plasma.plasmoid 2.0 13 | import org.kde.taskmanager 0.1 as TaskManager 14 | 15 | Item { 16 | id: plasmaTasksItem 17 | 18 | property bool filterByScreen: true 19 | readonly property bool existsWindowActive: lastActiveTaskItem && tasksRepeater.count > 0 && (root.perScreenActive || lastActiveTaskItem.isActive) 20 | readonly property bool existsWindowShown: lastActiveTaskItem && tasksRepeater.count > 0 && !lastActiveTaskItem.isMinimized 21 | property Item lastActiveTaskItem: null 22 | 23 | function toggleMaximized() { 24 | if (lastActiveTaskItem) 25 | lastActiveTaskItem.toggleMaximized(); 26 | 27 | } 28 | 29 | function toggleMinimized() { 30 | if (lastActiveTaskItem) 31 | lastActiveTaskItem.toggleMinimized(); 32 | 33 | } 34 | 35 | function toggleClose() { 36 | if (lastActiveTaskItem) 37 | lastActiveTaskItem.toggleClose(); 38 | 39 | } 40 | 41 | function togglePinToAllDesktops() { 42 | if (lastActiveTaskItem) 43 | lastActiveTaskItem.togglePinToAllDesktops(); 44 | 45 | } 46 | 47 | function toggleKeepAbove() { 48 | if (lastActiveTaskItem) 49 | lastActiveTaskItem.toggleKeepAbove(); 50 | 51 | } 52 | 53 | // To get current activity name 54 | TaskManager.ActivityInfo { 55 | id: activityInfo 56 | } 57 | 58 | // To get virtual desktop name 59 | TaskManager.VirtualDesktopInfo { 60 | id: virtualDesktopInfo 61 | } 62 | 63 | TaskManager.TasksModel { 64 | id: tasksModel 65 | 66 | sortMode: TaskManager.TasksModel.SortVirtualDesktop 67 | groupMode: TaskManager.TasksModel.GroupDisabled 68 | screenGeometry: root.screenGeometry 69 | activity: activityInfo.currentActivity 70 | virtualDesktop: virtualDesktopInfo.currentDesktop 71 | filterByScreen: plasmaTasksItem.filterByScreen 72 | filterByVirtualDesktop: true 73 | filterByActivity: true 74 | } 75 | 76 | Repeater { 77 | id: tasksRepeater 78 | 79 | model: DelegateModel { 80 | model: tasksModel 81 | 82 | delegate: Item { 83 | id: task 84 | 85 | readonly property string title: display 86 | readonly property bool isMinimized: IsMinimized === true ? true : false 87 | readonly property bool isMaximized: IsMaximized === true ? true : false 88 | readonly property bool isActive: IsActive === true ? true : false 89 | readonly property bool isOnAllDesktops: IsOnAllVirtualDesktops === true ? true : false 90 | readonly property bool isKeepAbove: IsKeepAbove === true ? true : false 91 | readonly property bool isClosable: IsClosable === true ? true : false 92 | readonly property bool isMinimizable: IsMinimizable === true ? true : false 93 | readonly property bool isMaximizable: IsMaximizable === true ? true : false 94 | readonly property bool isVirtualDesktopsChangeable: IsVirtualDesktopsChangeable === true ? true : false 95 | 96 | function modelIndex() { 97 | return tasksModel.makeModelIndex(index); 98 | } 99 | 100 | function toggleMaximized() { 101 | tasksModel.requestToggleMaximized(modelIndex()); 102 | } 103 | 104 | function toggleMinimized() { 105 | tasksModel.requestToggleMinimized(modelIndex()); 106 | } 107 | 108 | function toggleClose() { 109 | tasksModel.requestClose(modelIndex()); 110 | } 111 | 112 | function togglePinToAllDesktops() { 113 | tasksModel.requestVirtualDesktops(modelIndex(), isOnAllDesktops ? [virtualDesktopInfo.currentDesktop] : []); 114 | } 115 | 116 | function toggleKeepAbove() { 117 | tasksModel.requestToggleKeepAbove(modelIndex()); 118 | } 119 | 120 | onIsActiveChanged: { 121 | if (isActive) 122 | plasmaTasksItem.lastActiveTaskItem = task; 123 | 124 | } 125 | Component.onDestruction: { 126 | if (plasmaTasksItem.lastActiveTaskItem === task) 127 | plasmaTasksItem.lastActiveTaskItem = null; 128 | 129 | } 130 | } 131 | 132 | } 133 | 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /package/contents/ui/config/ColorsComboBox.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of applet-window-buttons 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | import QtQuick 10 | import QtQuick.Controls 11 | import QtQuick.Layouts 12 | 13 | ComboBox { 14 | id: combobox 15 | 16 | Connections { 17 | function onClosed() { 18 | root.forceActiveFocus(); 19 | } 20 | 21 | target: popup 22 | } 23 | 24 | delegate: MouseArea { 25 | width: combobox.width 26 | height: combobox.height 27 | hoverEnabled: true 28 | onClicked: { 29 | combobox.currentIndex = index; 30 | selectedScheme = model.file; 31 | combobox.popup.close(); 32 | } 33 | 34 | Rectangle { 35 | id: delegateBackground 36 | 37 | readonly property color selectedColor: Qt.rgba(palette.highlight.r, palette.highlight.g, palette.highlight.b, 0.5) 38 | 39 | anchors.fill: parent 40 | color: { 41 | if (containsMouse) 42 | return palette.highlight; 43 | 44 | if (combobox.currentIndex === index) 45 | return selectedColor; 46 | 47 | return "transparent"; 48 | } 49 | 50 | RowLayout { 51 | id: delegateRow 52 | 53 | height: parent.height 54 | 55 | Item { 56 | Layout.leftMargin: 2 57 | width: 1.25 * label.height 58 | height: label.height 59 | opacity: ((file == "kdeglobals") || (file == "_plasmatheme_")) ? 0 : 1 60 | 61 | Rectangle { 62 | width: height 63 | height: 0.75 * label.height 64 | color: backgroundColor 65 | border.width: 1 66 | border.color: containsMouse || (combobox.currentIndex === index) ? palette.highlightedText : palette.text 67 | 68 | Rectangle { 69 | anchors.horizontalCenter: parent.right 70 | anchors.verticalCenter: parent.bottom 71 | width: parent.width 72 | height: parent.height 73 | color: textColor 74 | border.width: parent.border.width 75 | border.color: parent.border.color 76 | } 77 | 78 | } 79 | 80 | } 81 | 82 | Label { 83 | id: label 84 | 85 | text: display 86 | color: containsMouse ? palette.highlightedText : palette.text 87 | } 88 | 89 | } 90 | 91 | } 92 | 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /package/contents/ui/config/ConfigBehavior.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 Christian Tallner 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | import QtQuick 7 | import QtQuick.Layouts 8 | import QtQuick.Controls as QQC2 9 | import org.kde.kcmutils as KCM 10 | import org.kde.kirigami as Kirigami 11 | import org.kde.plasma.core as PlasmaCore 12 | import org.kde.appletdecoration as AppletDecoration 13 | import org.kde.plasma.plasmoid 14 | 15 | KCM.SimpleKCM { 16 | id: root 17 | 18 | property alias cfg_visibility: root.visibility 19 | property alias cfg_hiddenState: root.hiddenState 20 | property alias cfg_perScreenActive: perScreenActiveChk.checked 21 | property alias cfg_filterByScreen: filterByScreenChk.checked 22 | property alias cfg_inactiveStateEnabled: inactiveChk.checked 23 | property alias cfg_borderlessMaximizedWindows: root.borderlessMaximizedWindows 24 | 25 | // used as bridge to communicate properly between configuration and ui 26 | property int visibility 27 | property int hiddenState 28 | property bool borderlessMaximizedWindows: kwinConfig.borderlessMaximizedWindows 29 | property bool initialBorderlessMaximizedWindowsValue: kwinConfig.borderlessMaximizedWindows 30 | 31 | Component.onCompleted: { 32 | if(kwinConfig.borderlessMaximizedWindows !== plasmoid.configuration.borderlessMaximizedWindows){ 33 | root.borderlessMaximizedWindows = kwinConfig.borderlessMaximizedWindows 34 | plasmoid.configuration.borderlessMaximizedWindows = kwinConfig.borderlessMaximizedWindows 35 | } 36 | } 37 | 38 | // Signal is fired when the user clicks on the save or apply button in the config page. 39 | Plasmoid.configuration.onValueChanged: { 40 | // Only safe KWin Config if value changed. 41 | // Saving to KWin requires reloading KWin config, which is expensive and should be avoided. 42 | if (root.borderlessMaximizedWindows !== root.initialBorderlessMaximizedWindowsValue) { 43 | root.initialBorderlessMaximizedWindowsValue = root.borderlessMaximizedWindows 44 | kwinConfig.borderlessMaximizedWindows = borderlessMaximizedWindows 45 | } 46 | } 47 | 48 | AppletDecoration.KWinConfig { 49 | id: kwinConfig 50 | } 51 | 52 | Kirigami.FormLayout { 53 | id: form 54 | 55 | QQC2.RadioButton { 56 | id: alwaysVisibleBtn 57 | Kirigami.FormData.label: i18n("Show:") 58 | QQC2.ButtonGroup.group: visibilityBtnGroup 59 | text: i18n("Always visible") 60 | checked: root.visibility === AppletDecoration.Types.AlwaysVisible 61 | onCheckedChanged: { 62 | if (checked) 63 | root.visibility = AppletDecoration.Types.AlwaysVisible; 64 | 65 | } 66 | } 67 | 68 | QQC2.RadioButton { 69 | id: activeWindowBtn 70 | QQC2.ButtonGroup.group: visibilityBtnGroup 71 | text: i18n("Active window is present") 72 | checked: root.visibility === AppletDecoration.Types.ActiveWindow 73 | onCheckedChanged: { 74 | if (checked) 75 | root.visibility = AppletDecoration.Types.ActiveWindow; 76 | 77 | } 78 | } 79 | 80 | QQC2.RadioButton { 81 | id: activeMaximizedBtn 82 | QQC2.ButtonGroup.group: visibilityBtnGroup 83 | text: i18n("Active window is maximized") 84 | checked: root.visibility === AppletDecoration.Types.ActiveMaximizedWindow 85 | onCheckedChanged: { 86 | if (checked) 87 | root.visibility = AppletDecoration.Types.ActiveMaximizedWindow; 88 | 89 | } 90 | } 91 | 92 | QQC2.RadioButton { 93 | id: shownWindowBtn 94 | QQC2.ButtonGroup.group: visibilityBtnGroup 95 | text: i18n("At least one window is shown") 96 | checked: root.visibility === AppletDecoration.Types.ShownWindowExists 97 | onCheckedChanged: { 98 | if (checked) 99 | root.visibility = AppletDecoration.Types.ShownWindowExists; 100 | 101 | } 102 | } 103 | 104 | Item { 105 | Kirigami.FormData.isSection: true 106 | } 107 | 108 | QQC2.RadioButton { 109 | id: slideOutBtn 110 | Kirigami.FormData.label: i18n("Hidden State:") 111 | QQC2.ButtonGroup.group: hiddenStateBtnGroup 112 | text: i18n("Slide out animation") 113 | checked: root.hiddenState === AppletDecoration.Types.SlideOut 114 | enabled: root.visibility !== AppletDecoration.Types.AlwaysVisible 115 | onCheckedChanged: { 116 | if (checked) 117 | root.hiddenState = AppletDecoration.Types.SlideOut; 118 | 119 | } 120 | } 121 | 122 | QQC2.RadioButton { 123 | id: emptySpaceBtn 124 | QQC2.ButtonGroup.group: hiddenStateBtnGroup 125 | text: i18n("Preserve as empty space") 126 | checked: root.hiddenState === AppletDecoration.Types.EmptySpace 127 | enabled: root.visibility !== AppletDecoration.Types.AlwaysVisible 128 | onCheckedChanged: { 129 | if (checked) 130 | root.hiddenState = AppletDecoration.Types.EmptySpace; 131 | 132 | } 133 | } 134 | 135 | Item { 136 | Kirigami.FormData.isSection: true 137 | } 138 | 139 | QQC2.CheckBox { 140 | id: filterByScreenChk 141 | Kirigami.FormData.label: i18n("Filters:") 142 | text: i18n("Show only for windows in current screen") 143 | } 144 | 145 | QQC2.CheckBox { 146 | id: perScreenActiveChk 147 | text: i18n("Per-screen active window:") 148 | } 149 | 150 | Item { 151 | Kirigami.FormData.isSection: true 152 | } 153 | 154 | QQC2.CheckBox { 155 | id: inactiveChk 156 | Kirigami.FormData.label: i18n("Appearance:") 157 | text: i18n("Draw buttons inactive state when needed") 158 | } 159 | 160 | Item { 161 | Kirigami.FormData.isSection: true 162 | } 163 | 164 | QQC2.CheckBox { 165 | id: borderlessMaximizedWindowsChk 166 | Kirigami.FormData.label: i18n("KWin:") 167 | text: i18n("Borderless Maximized Windows") 168 | checked: root.borderlessMaximizedWindows 169 | onCheckedChanged: { 170 | root.borderlessMaximizedWindows = checked 171 | } 172 | } 173 | } 174 | 175 | QQC2.ButtonGroup { 176 | id: visibilityBtnGroup 177 | } 178 | 179 | QQC2.ButtonGroup { 180 | id: hiddenStateBtnGroup 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /package/contents/ui/config/ConfigGeneral.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * SPDX-FileCopyrightText: 2024 Christian Tallner 4 | * 5 | * This file is part of applet-window-buttons 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | 10 | import QtQuick 11 | import QtQuick.Layouts 12 | import QtQuick.Controls as QQC2 13 | import org.kde.kcmutils as KCM 14 | import org.kde.kirigami as Kirigami 15 | import org.kde.kitemmodels 16 | import org.kde.plasma.components as PlasmaComponents 17 | import org.kde.plasma.core as PlasmaCore 18 | import org.kde.appletdecoration as AppletDecoration 19 | 20 | KCM.SimpleKCM { 21 | id: root 22 | 23 | property alias cfg_useCurrentDecoration: root.useCurrent 24 | property alias cfg_selectedPlugin: root.selectedPlugin 25 | property alias cfg_selectedScheme: root.selectedScheme 26 | property alias cfg_selectedTheme: root.selectedTheme 27 | property alias cfg_buttons: root.currentButtons 28 | 29 | property alias cfg_buttonSizePercentage: buttonSizeSpn.value 30 | property alias cfg_useDecorationMetrics: decorationMetricsChk.checked 31 | property alias cfg_spacing: spacingSpn.value 32 | property alias cfg_lengthFirstMargin: lengthFirstSpn.value 33 | property alias cfg_lengthLastMargin: lengthLastSpn.value 34 | property alias cfg_lengthMarginsLock: lockItem.locked 35 | //property var title 36 | // used as bridge to communicate properly between configuration and ui 37 | property bool useCurrent 38 | property string selectedPlugin 39 | property string selectedScheme 40 | property string selectedTheme 41 | property string currentButtons 42 | // used from the ui 43 | readonly property bool selectedDecorationExists: decorations.decorationExists(root.selectedPlugin, root.selectedTheme) 44 | readonly property real centerFactor: 0.3 45 | readonly property int minimumWidth: 220 46 | property string currentPlugin: root.useCurrent || !selectedDecorationExists ? decorations.currentPlugin : root.selectedPlugin 47 | property string currentTheme: root.useCurrent || !selectedDecorationExists ? decorations.currentTheme : root.selectedTheme 48 | 49 | onSelectedPluginChanged: { 50 | console.log("Selected Plugin CHanged: ", root.selectedPlugin) 51 | } 52 | 53 | ///START Decoration Items 54 | AppletDecoration.Bridge { 55 | id: bridgeItem 56 | 57 | plugin: currentPlugin 58 | theme: currentTheme 59 | } 60 | 61 | AppletDecoration.Settings { 62 | id: settingsItem 63 | 64 | bridge: bridgeItem.bridge 65 | borderSizesIndex: 0 66 | } 67 | 68 | AppletDecoration.SharedDecoration { 69 | id: sharedDecorationItem 70 | 71 | bridge: bridgeItem.bridge 72 | settings: settingsItem 73 | } 74 | 75 | AppletDecoration.AuroraeTheme { 76 | id: auroraeThemeEngine 77 | 78 | readonly property bool isEnabled: decorations.isAurorae(root.currentPlugin, root.currentTheme) 79 | 80 | theme: isEnabled ? currentTheme : "" 81 | } 82 | 83 | AppletDecoration.DecorationsModel { 84 | id: decorations 85 | } 86 | 87 | AppletDecoration.ColorsModel { 88 | id: colorsModel 89 | } 90 | 91 | AppletDecoration.PlasmaThemeExtended { 92 | id: plasmaThemeExtended 93 | 94 | readonly property bool isActive: selectedScheme === "_plasmatheme_" 95 | } 96 | 97 | SystemPalette { 98 | id: palette 99 | } 100 | 101 | // sort decorations based on display name 102 | KSortFilterProxyModel { 103 | id: sortedDecorations 104 | 105 | sourceModel: decorations 106 | sortRoleName: 'display' 107 | sortOrder: Qt.AscendingOrder 108 | } 109 | 110 | ColumnLayout { 111 | id: mainColumn 112 | spacing: Kirigami.Units.largeSpacing 113 | Layout.fillWidth: true 114 | 115 | RowLayout { 116 | QQC2.Label { 117 | Layout.minimumWidth: Math.max(centerFactor * root.width, minimumWidth) 118 | text: i18n("Decoration:") 119 | horizontalAlignment: Text.AlignRight 120 | } 121 | 122 | DecorationsComboBox { 123 | id: decorationCmb 124 | 125 | Layout.minimumWidth: 180 126 | Layout.preferredWidth: 0.2 * root.width 127 | Layout.maximumWidth: 300 128 | } 129 | 130 | } 131 | 132 | RowLayout { 133 | visible: !auroraeThemeEngine.isEnabled 134 | 135 | QQC2.Label { 136 | Layout.minimumWidth: Math.max(centerFactor * root.width, minimumWidth) 137 | text: i18n("Colors:") 138 | horizontalAlignment: Text.AlignRight 139 | } 140 | 141 | ColorsComboBox { 142 | id: colorsCmbBox 143 | 144 | Layout.minimumWidth: 250 145 | Layout.preferredWidth: 0.3 * root.width 146 | Layout.maximumWidth: 380 147 | model: colorsModel 148 | textRole: "display" 149 | Component.onCompleted: { 150 | currentIndex = colorsModel.indexOf(plasmoid.configuration.selectedScheme); 151 | } 152 | } 153 | 154 | } 155 | 156 | GridLayout { 157 | rowSpacing: Kirigami.Units.largeSpacing 158 | columnSpacing: Kirigami.Units.largeSpacing 159 | columns: 2 160 | 161 | QQC2.Label { 162 | Layout.minimumWidth: Math.max(centerFactor * root.width, minimumWidth) 163 | text: i18n("Buttons:") 164 | horizontalAlignment: Text.AlignRight 165 | } 166 | 167 | OrderableListView { 168 | id: activeButtons 169 | 170 | readonly property color schemesBackgroundColor: plasmaThemeExtended.isActive ? plasmaThemeExtended.colors.backgroundColor : colorsModel.backgroundOf(colorsCmbBox.currentIndex) 171 | 172 | itemWidth: 38 173 | itemHeight: 38 174 | buttonsStr: root.currentButtons 175 | orientation: ListView.Horizontal 176 | color: !auroraeThemeEngine.isEnabled ? schemesBackgroundColor : auroraeThemeEngine.titleBackgroundColor 177 | buttonSize: buttonSizeSpn.value 178 | buttonsFirstMargin: lengthFirstSpn.value 179 | buttonsLastMargin: lengthLastSpn.value 180 | buttonsSpacing: spacingSpn.value 181 | } 182 | 183 | } 184 | 185 | ColumnLayout { 186 | id: visualSettings 187 | 188 | GridLayout { 189 | id: visualSettingsGroup1 190 | 191 | columns: 2 192 | 193 | QQC2.Label { 194 | Layout.minimumWidth: Math.max(centerFactor * root.width, minimumWidth) 195 | text: i18n("Metrics:") 196 | horizontalAlignment: Text.AlignRight 197 | visible: auroraeThemeEngine.isEnabled 198 | } 199 | 200 | QQC2.CheckBox { 201 | id: decorationMetricsChk 202 | 203 | text: i18n("Use from decoration if any are found") 204 | visible: auroraeThemeEngine.isEnabled 205 | } 206 | 207 | QQC2.Label { 208 | Layout.minimumWidth: Math.max(centerFactor * root.width, minimumWidth) 209 | text: i18n("Size:") 210 | horizontalAlignment: Text.AlignRight 211 | enabled: !(auroraeThemeEngine.isEnabled && decorationMetricsChk.checked) 212 | } 213 | 214 | QQC2.SpinBox { 215 | id: buttonSizeSpn 216 | 217 | from: 40 218 | to: 100 219 | // suffix: " %" 220 | enabled: !(auroraeThemeEngine.isEnabled && decorationMetricsChk.checked) 221 | } 222 | 223 | QQC2.Label { 224 | Layout.minimumWidth: Math.max(centerFactor * root.width, minimumWidth) 225 | text: i18n("Spacing:") 226 | horizontalAlignment: Text.AlignRight 227 | enabled: !(auroraeThemeEngine.isEnabled && decorationMetricsChk.checked) 228 | } 229 | 230 | QQC2.SpinBox { 231 | id: spacingSpn 232 | 233 | from: 0 234 | to: 24 235 | // suffix: " " + i18nc("pixels","px.") 236 | enabled: !(auroraeThemeEngine.isEnabled && decorationMetricsChk.checked) 237 | } 238 | 239 | } 240 | 241 | GridLayout { 242 | id: visualSettingsGroup2 243 | 244 | property int lockerHeight: firstLengthLbl.height + rowSpacing / 2 245 | 246 | columns: 3 247 | rows: 2 248 | flow: GridLayout.TopToBottom 249 | columnSpacing: visualSettingsGroup1.columnSpacing 250 | rowSpacing: visualSettingsGroup1.rowSpacing 251 | 252 | QQC2.Label { 253 | id: firstLengthLbl 254 | 255 | Layout.minimumWidth: Math.max(centerFactor * root.width, minimumWidth) 256 | text: plasmoid.configuration.formFactor === PlasmaCore.Types.Horizontal ? i18n("Left margin:") : i18n("Top margin:") 257 | horizontalAlignment: Text.AlignRight 258 | } 259 | 260 | QQC2.Label { 261 | Layout.minimumWidth: Math.max(centerFactor * root.width, minimumWidth) 262 | text: plasmoid.configuration.formFactor === PlasmaCore.Types.Horizontal ? i18n("Right margin:") : i18n("Bottom margin:") 263 | horizontalAlignment: Text.AlignRight 264 | enabled: !lockItem.locked 265 | } 266 | 267 | QQC2.SpinBox { 268 | // suffix: " " + i18nc("pixels","px.") 269 | 270 | id: lengthFirstSpn 271 | 272 | property int lastValue: -1 273 | 274 | from: 0 275 | to: 24 276 | onValueChanged: { 277 | if (lockItem.locked) { 278 | var step = value - lastValue > 0 ? 1 : -1; 279 | lastValue = value; 280 | lengthLastSpn.value = lengthLastSpn.value + step; 281 | } 282 | } 283 | Component.onCompleted: { 284 | lastValue = plasmoid.configuration.lengthFirstMargin; 285 | } 286 | } 287 | 288 | QQC2.SpinBox { 289 | id: lengthLastSpn 290 | 291 | from: 0 292 | to: 24 293 | // suffix: " " + i18nc("pixels","px.") 294 | enabled: !lockItem.locked 295 | } 296 | 297 | LockItem { 298 | id: lockItem 299 | 300 | Layout.minimumWidth: 40 301 | Layout.maximumWidth: 40 302 | Layout.alignment: Qt.AlignTop | Qt.AlignLeft 303 | Layout.minimumHeight: visualSettingsGroup2.lockerHeight 304 | Layout.maximumHeight: Layout.minimumHeight 305 | Layout.topMargin: firstLengthLbl.height / 2 306 | Layout.rowSpan: 2 307 | } 308 | 309 | } 310 | 311 | } 312 | 313 | } 314 | 315 | } 316 | -------------------------------------------------------------------------------- /package/contents/ui/config/DecorationsComboBox.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of applet-window-buttons 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | import QtQuick 10 | import QtQuick.Controls 11 | import QtQuick.Layouts 12 | import org.kde.kirigami as Kirigami 13 | 14 | ComboBox { 15 | id: combobox 16 | 17 | model: sortedDecorations 18 | textRole: "display" 19 | valueRole: "plugin" 20 | onActivated: { 21 | var index = combobox.currentIndex; 22 | if (index === -1) 23 | return ; 24 | 25 | console.log(currentTheme, combobox.currentText, combobox.currentValue); 26 | root.useCurrent = false; 27 | root.selectedPlugin = combobox.currentValue; 28 | root.selectedTheme = combobox.currentText; 29 | } 30 | Component.onCompleted: { 31 | combobox.currentIndex = combobox.find(root.currentTheme); 32 | } 33 | 34 | Connections { 35 | function onClosed() { 36 | root.forceActiveFocus(); 37 | } 38 | 39 | target: popup 40 | } 41 | 42 | delegate: MouseArea { 43 | height: combobox.height 44 | width: combobox.width 45 | hoverEnabled: true 46 | onClicked: { 47 | combobox.currentIndex = index; 48 | root.useCurrent = false; 49 | root.selectedPlugin = plugin; 50 | root.selectedTheme = theme; 51 | combobox.popup.close(); 52 | } 53 | 54 | Rectangle { 55 | id: delegateBackground 56 | 57 | readonly property color selectedColor: Qt.rgba(palette.highlight.r, palette.highlight.g, palette.highlight.b, 0.5) 58 | 59 | anchors.fill: parent 60 | color: { 61 | if (containsMouse) 62 | return palette.highlight; 63 | 64 | if (combobox.currentIndex === index) 65 | return selectedColor; 66 | 67 | return "transparent"; 68 | } 69 | 70 | Label { 71 | id: label 72 | 73 | anchors.left: parent.left 74 | anchors.leftMargin: Kirigami.Units.smallSpacing 75 | anchors.verticalCenter: parent.verticalCenter 76 | text: display 77 | color: containsMouse ? palette.highlightedText : palette.text 78 | } 79 | 80 | } 81 | 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /package/contents/ui/config/LockItem.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | * 4 | * This file is part of applet-window-buttons 5 | * 6 | * SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | import QtQuick 10 | import QtQuick.Controls 11 | import QtQuick.Layouts 12 | import org.kde.kirigami as Kirigami 13 | 14 | Item { 15 | id: main 16 | 17 | property bool locked: true 18 | readonly property int verticalSubHeight: height - (button.height / 2) 19 | 20 | SystemPalette { 21 | id: palette 22 | } 23 | 24 | ColumnLayout { 25 | id: column 26 | 27 | spacing: 0 28 | opacity: locked ? 1 : 0.5 29 | 30 | Rectangle { 31 | id: subRectTop 32 | 33 | Layout.minimumWidth: button.width / 2 + Layout.minimumHeight / 2 34 | Layout.minimumHeight: 3 35 | Layout.maximumWidth: Layout.minimumWidth 36 | Layout.maximumHeight: Layout.minimumHeight 37 | color: palette.text 38 | } 39 | 40 | Rectangle { 41 | Layout.leftMargin: subRectTop.Layout.minimumWidth - subRectTop.Layout.minimumHeight 42 | Layout.minimumWidth: subRectTop.Layout.minimumHeight 43 | Layout.minimumHeight: verticalSubHeight 44 | Layout.maximumWidth: Layout.minimumWidth 45 | Layout.maximumHeight: Layout.minimumHeight 46 | color: palette.text 47 | } 48 | 49 | Kirigami.Icon { 50 | id: button 51 | 52 | width: 24 53 | height: 24 54 | source: locked ? "lock" : "unlock" 55 | } 56 | 57 | Rectangle { 58 | Layout.leftMargin: subRectTop.Layout.minimumWidth - subRectTop.Layout.minimumHeight 59 | Layout.minimumWidth: subRectTop.Layout.minimumHeight 60 | Layout.minimumHeight: verticalSubHeight 61 | Layout.maximumWidth: Layout.minimumWidth 62 | Layout.maximumHeight: Layout.minimumHeight 63 | color: palette.text 64 | } 65 | 66 | Rectangle { 67 | Layout.minimumWidth: subRectTop.Layout.minimumWidth 68 | Layout.minimumHeight: subRectTop.Layout.minimumHeight 69 | Layout.maximumWidth: Layout.minimumWidth 70 | Layout.maximumHeight: Layout.minimumHeight 71 | color: palette.text 72 | } 73 | 74 | } 75 | 76 | MouseArea { 77 | anchors.fill: column 78 | onClicked: locked = !locked 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /package/contents/ui/config/OrderableListView.qml: -------------------------------------------------------------------------------- 1 | import "../../code/tools.js" as ModelTools 2 | /* 3 | * SPDX-FileCopyrightText: 2018 Michail Vourlakos 4 | * 5 | * This file is part of applet-window-buttons 6 | * 7 | * SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | import QtQuick 10 | import QtQuick.Controls 11 | import QtQuick.Layouts 12 | import org.kde.appletdecoration 0.1 as AppletDecoration 13 | import org.kde.plasma.core 2.0 as PlasmaCore 14 | 15 | Rectangle { 16 | /*Rectangle{ 17 | anchors.fill: parent 18 | color: "transparent" 19 | border.color: "red" 20 | border.width: 1 21 | }*/ 22 | 23 | id: listContent 24 | 25 | property int orientation 26 | property double itemWidth 27 | property double itemHeight 28 | property int buttonSize: 100 29 | property int buttonsFirstMargin: 0 30 | property int buttonsLastMargin: 0 31 | property int buttonsSpacing: 0 32 | property string buttonsStr 33 | property var tasksPreparedArray: [] 34 | readonly property int margin: 0 35 | readonly property double iconHeight: itemHeight * (buttonSize / 100) - margin * 2 36 | readonly property string appliedScheme: { 37 | if (selectedScheme === "_plasmatheme_") 38 | return plasmaThemeExtended.colors.schemeFile; 39 | else if (selectedScheme === "kdeglobals") 40 | return colorsModel.defaultSchemeFile(); 41 | return selectedScheme; 42 | } 43 | 44 | signal coordinatesChanged() 45 | signal modelOrderChanged() 46 | 47 | function initButtons() { 48 | if (!buttonsRecreator.running) 49 | buttonsRecreator.start(); 50 | 51 | } 52 | 53 | function initializeControlButtonsModel() { 54 | sharedDecorationItem.createDecoration(); 55 | var buttonsList = buttonsStr.split('|'); 56 | ModelTools.initializeControlButtonsModel(buttonsList, tasksPreparedArray, controlButtonsModel, false); 57 | listView.splitterIndex = ModelTools.indexOfSplitter(controlButtonsModel); 58 | coordinatesTimer.start(); 59 | } 60 | 61 | function buttonsListStr() { 62 | var str = ""; 63 | for (var i = 0; i < controlButtonsModel.count; ++i) { 64 | str = str + String(controlButtonsModel.get(i).buttonType); 65 | if (i !== controlButtonsModel.count - 1) 66 | str = str + "|"; 67 | 68 | } 69 | return str; 70 | } 71 | 72 | function triggerUpdateFromPlasma() { 73 | if (plasmaThemeExtended.isActive) 74 | listContent.initButtons(); 75 | 76 | } 77 | 78 | radius: 4 79 | anchors.margins: margin 80 | Layout.minimumWidth: width 81 | Layout.preferredWidth: Layout.minimumWidth 82 | Layout.maximumWidth: Layout.maximumWidth 83 | Layout.minimumHeight: height 84 | Layout.preferredHeight: Layout.minimumHeight 85 | Layout.maximumHeight: Layout.maximumHeight 86 | width: listView.childrenRect.width + 2 * margin //(itemWidth+listView.spacing) * (orientation == ListView.Vertical ? 1 : controlButtonsModel.count) + 2 * margin 87 | height: listView.childrenRect.height + 2 * margin //(itemHeight+listView.spacing) * (orientation == ListView.Horizontal ? 1 : controlButtonsModel.count) 88 | Component.onCompleted: { 89 | initButtons(); 90 | coordinatesChanged(); 91 | } 92 | 93 | Connections { 94 | function onCurrentPluginChanged() { 95 | listContent.initButtons(); 96 | } 97 | 98 | target: root 99 | } 100 | 101 | Connections { 102 | function onThemeChanged() { 103 | triggerUpdateFromPlasma(); 104 | } 105 | 106 | target: plasmaThemeExtended 107 | } 108 | 109 | ListModel { 110 | id: controlButtonsModel 111 | } 112 | 113 | SystemPalette { 114 | id: palette 115 | } 116 | 117 | ListView { 118 | id: listView 119 | 120 | property int splitterIndex: -1 121 | 122 | width: childrenRect.width 123 | height: itemHeight 124 | model: controlButtonsModel 125 | orientation: listContent.orientation 126 | delegate: auroraeThemeEngine.isEnabled ? auroraeButtonComponent : pluginButtonComponent 127 | currentIndex: loc.initIndex 128 | onWidthChanged: coordinatesTimer.start() 129 | 130 | moveDisplaced: Transition { 131 | NumberAnimation { 132 | properties: "x" 133 | duration: 150 134 | easing.type: Easing.Linear 135 | } 136 | 137 | } 138 | 139 | move: Transition { 140 | NumberAnimation { 141 | properties: "x" 142 | duration: 75 143 | easing.type: Easing.Linear 144 | } 145 | 146 | } 147 | 148 | } 149 | 150 | MouseArea { 151 | id: loc 152 | 153 | property int initButton: -1 // Original button in model 154 | property int initIndex: -1 // Original position in model 155 | property int index: listView.indexAt(mouseX, mouseY) // Item underneath cursor 156 | readonly property bool buttonIsDragged: initButton !== -1 || initIndex !== -1 157 | 158 | anchors.fill: parent 159 | pressAndHoldInterval: 200 160 | cursorShape: Qt.DragMoveCursor 161 | onPressAndHold: { 162 | initIndex = listView.indexAt(mouseX, mouseY); 163 | initButton = controlButtonsModel.get(initIndex).buttonType; 164 | } 165 | onReleased: { 166 | initIndex = -1; 167 | initButton = -1; 168 | } 169 | onPositionChanged: { 170 | if (containsPress && initIndex !== -1 && index !== -1 && index !== initIndex) { 171 | controlButtonsModel.move(initIndex, index, 1); 172 | initIndex = index; 173 | root.currentButtons = buttonsListStr(); 174 | listView.splitterIndex = ModelTools.indexOfSplitter(controlButtonsModel); 175 | } 176 | } 177 | } 178 | 179 | ///START Components 180 | Component { 181 | id: pluginButtonComponent 182 | 183 | Rectangle { 184 | id: decorationButton 185 | 186 | readonly property bool isVisibleButton: index >= 0 && index < listView.splitterIndex 187 | readonly property bool isFirstVisibleButton: index === 0 && listView.splitterIndex > 0 188 | readonly property bool isLastVisibleButton: index >= 0 && index === listView.splitterIndex - 1 189 | readonly property bool isButtonSplitter: index >= 0 && index === listView.splitterIndex 190 | property int leftMargin: 0 191 | property int rightMargin: 0 192 | 193 | y: (itemHeight - iconHeight) / 2 194 | width: isButtonSplitter && !loc.buttonIsDragged ? Math.min(listContent.iconHeight / 2, 6 + buttonsLastMargin) : listContent.iconHeight + leftMargin + rightMargin 195 | height: listContent.iconHeight + 2 * listContent.margin 196 | color: { 197 | if (listView.currentIndex === index) { 198 | if (index !== listView.splitterIndex) 199 | return palette.highlight; 200 | else 201 | return "#25ff0000"; 202 | } 203 | return "transparent"; 204 | } 205 | 206 | Binding { 207 | target: decorationButton 208 | property: "leftMargin" 209 | value: { 210 | if (loc.buttonIsDragged) 211 | return buttonsSpacing / 2; 212 | 213 | if (isFirstVisibleButton) 214 | return buttonsFirstMargin; 215 | else if (isVisibleButton) 216 | return buttonsSpacing; 217 | return listContent.margin; 218 | } 219 | } 220 | 221 | Binding { 222 | target: decorationButton 223 | property: "rightMargin" 224 | value: { 225 | if (loc.buttonIsDragged) 226 | return buttonsSpacing / 2; 227 | 228 | if (isLastVisibleButton) 229 | return buttonsLastMargin; 230 | 231 | return listContent.margin; 232 | } 233 | } 234 | 235 | AppletDecoration.Button { 236 | id: cButton 237 | 238 | function updateCoordinates() { 239 | var translated = cButton.mapToItem(listView, 0, 0); 240 | cButton.localX = translated.x; 241 | cButton.localY = translated.y; 242 | } 243 | 244 | anchors.left: parent.left 245 | anchors.verticalCenter: parent.verticalCenter 246 | anchors.leftMargin: parent.leftMargin 247 | opacity: listView.splitterIndex !== -1 && listView.splitterIndex < index ? 0.4 : 1 248 | width: isButtonSplitter ? parent.width : listContent.iconHeight 249 | height: isButtonSplitter ? parent.height : listContent.iconHeight 250 | bridge: bridgeItem.bridge 251 | sharedDecoration: sharedDecorationItem 252 | type: buttonType 253 | isOnAllDesktops: false 254 | isMaximized: false 255 | scheme: appliedScheme 256 | visible: buttonType !== AppletDecoration.Types.Custom 257 | 258 | Connections { 259 | function onCoordinatesChanged() { 260 | cButton.updateCoordinates(); 261 | } 262 | 263 | target: listContent 264 | } 265 | 266 | } 267 | 268 | Rectangle { 269 | height: parent.height - listContent.margin 270 | width: 4 271 | border.width: 1 272 | anchors.left: parent.left 273 | color: palette.highlight 274 | border.color: palette.highlight 275 | visible: buttonType === AppletDecoration.Types.Custom 276 | opacity: 0.75 277 | } 278 | 279 | Behavior on leftMargin { 280 | NumberAnimation { 281 | duration: 50 282 | easing.type: Easing.Linear 283 | } 284 | 285 | } 286 | 287 | Behavior on rightMargin { 288 | NumberAnimation { 289 | duration: 50 290 | easing.type: Easing.Linear 291 | } 292 | 293 | } 294 | 295 | } 296 | 297 | } 298 | 299 | Component { 300 | id: auroraeButtonComponent 301 | 302 | Rectangle { 303 | id: auroraeButton 304 | 305 | readonly property bool isVisibleButton: index >= 0 && index < listView.splitterIndex 306 | readonly property bool isFirstVisibleButton: index === 0 && listView.splitterIndex > 0 307 | readonly property bool isLastVisibleButton: index >= 0 && index === listView.splitterIndex - 1 308 | readonly property bool isButtonSplitter: index >= 0 && index === listView.splitterIndex 309 | property int leftMargin: 0 310 | property int rightMargin: 0 311 | 312 | y: (itemHeight - iconHeight) / 2 313 | width: isButtonSplitter && !loc.buttonIsDragged ? Math.min(listContent.iconHeight / 2, 6 + buttonsLastMargin) : auroraeThemeEngine.buttonRatio * listContent.iconHeight + leftMargin + rightMargin 314 | height: listContent.iconHeight + 2 * listContent.margin 315 | color: { 316 | if (listView.currentIndex === index) { 317 | if (index !== listView.splitterIndex) 318 | return palette.highlight; 319 | else 320 | return "#25ff0000"; 321 | } 322 | return "transparent"; 323 | } 324 | 325 | Binding { 326 | target: auroraeButton 327 | property: "leftMargin" 328 | value: { 329 | if (loc.buttonIsDragged) 330 | return buttonsSpacing / 2; 331 | 332 | if (isFirstVisibleButton) 333 | return buttonsFirstMargin; 334 | else if (isVisibleButton) 335 | return buttonsSpacing; 336 | return listContent.margin; 337 | } 338 | } 339 | 340 | Binding { 341 | target: auroraeButton 342 | property: "rightMargin" 343 | value: { 344 | if (loc.buttonIsDragged) 345 | return buttonsSpacing / 2; 346 | 347 | if (isLastVisibleButton) 348 | return buttonsLastMargin; 349 | 350 | return listContent.margin; 351 | } 352 | } 353 | 354 | AppletDecoration.AuroraeButton { 355 | anchors.left: parent.left 356 | anchors.verticalCenter: parent.verticalCenter 357 | anchors.leftMargin: parent.leftMargin 358 | opacity: listView.splitterIndex !== -1 && listView.splitterIndex < index ? 0.4 : 1 359 | width: auroraeThemeEngine.buttonRatio * height 360 | height: listContent.iconHeight 361 | isOnAllDesktops: false 362 | isMaximized: false 363 | buttonType: model.buttonType 364 | auroraeTheme: auroraeThemeEngine 365 | visible: buttonType !== AppletDecoration.Types.Custom 366 | } 367 | 368 | Rectangle { 369 | anchors.left: parent.left 370 | height: parent.height 371 | width: 4 372 | border.width: 1 373 | color: palette.highlight 374 | border.color: palette.highlight 375 | visible: buttonType === AppletDecoration.Types.Custom 376 | opacity: 0.75 377 | } 378 | 379 | Behavior on leftMargin { 380 | NumberAnimation { 381 | duration: 50 382 | easing.type: Easing.Linear 383 | } 384 | 385 | } 386 | 387 | Behavior on rightMargin { 388 | NumberAnimation { 389 | duration: 50 390 | easing.type: Easing.Linear 391 | } 392 | 393 | } 394 | 395 | } 396 | 397 | } 398 | ///END Components 399 | 400 | //! this timer is used in order to not call too many times the recreation 401 | //! of buttons with no reason. 402 | Timer { 403 | id: buttonsRecreator 404 | 405 | interval: 200 406 | onTriggered: { 407 | initializeControlButtonsModel(); 408 | } 409 | } 410 | 411 | //! this timer is used in order to call the relative coordinates updater at the end 412 | //! of the buttons moving 413 | Timer { 414 | id: coordinatesTimer 415 | 416 | interval: 350 417 | onTriggered: { 418 | listContent.coordinatesChanged(); 419 | } 420 | } 421 | 422 | } 423 | -------------------------------------------------------------------------------- /package/metadata.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Window Buttons 3 | Comment=Window buttons for your panels 4 | 5 | Encoding=UTF-8 6 | Icon=focus-windows 7 | Keywords=window buttons 8 | Type=Service 9 | 10 | X-Plasma-API=declarativeappletscript 11 | X-Plasma-MainScript=ui/main.qml 12 | 13 | X-KDE-PluginInfo-Author=Michail Vourlakos 14 | X-KDE-PluginInfo-Category=Windows and Tasks 15 | X-KDE-PluginInfo-Email=mvourlakos@gmail.com 16 | X-KDE-PluginInfo-License=GPLv2 17 | X-KDE-PluginInfo-Name=org.kde.windowbuttons 18 | X-KDE-PluginInfo-Version=0.11.1 19 | X-KDE-PluginInfo-Website=https://github.com/psifidotos/applet-window-buttons 20 | X-KDE-ServiceTypes=Plasma/Applet 21 | 22 | -------------------------------------------------------------------------------- /package/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "KPackageStructure": "Plasma/Applet", 3 | "KPlugin": { 4 | "Authors": [ 5 | { 6 | "Email": "mvourlakos@gmail.com", 7 | "Name": "Michail Vourlakos" 8 | } 9 | ], 10 | "Category": "Windows and Tasks", 11 | "Description": "Window buttons for your panels", 12 | "Icon": "focus-windows", 13 | "Id": "org.kde.windowbuttons", 14 | "License": "GPLv2", 15 | "Name": "Window Buttons", 16 | "Version": "0.11.1", 17 | "Website": "https://github.com/psifidotos/applet-window-buttons" 18 | }, 19 | "Keywords": "window buttons", 20 | "X-Plasma-API": "declarativeappletscript", 21 | "X-Plasma-MainScript": "ui/main.qml", 22 | "X-Plasma-API-Minimum-Version": "6.0" 23 | } 24 | -------------------------------------------------------------------------------- /uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-FileCopyrightText: 2018 Michail Vourlakos 3 | # SPDX-License-Identifier: GPL-2.0-or-later 4 | # Summary: Uninstallation script 5 | # This script was written and tested on openSuSe Leap 42.1 6 | if [ -f build/install_manifest.txt ]; then 7 | echo "Uninstallation file exists..." 8 | sudo xargs -d '\n' rm < build/install_manifest.txt 9 | else 10 | echo "Uninstallation file does not exist." 11 | fi 12 | --------------------------------------------------------------------------------