diff --git a/kcmkwin/kwinrules/CMakeLists.txt b/kcmkwin/kwinrules/CMakeLists.txt --- a/kcmkwin/kwinrules/CMakeLists.txt +++ b/kcmkwin/kwinrules/CMakeLists.txt @@ -1,14 +1,23 @@ # KI18N Translation Domain for this library add_definitions(-DTRANSLATION_DOMAIN=\"kcmkwinrules\") add_definitions(-DKCMRULES) + ########### next target ############### include_directories(../../) -set(kwinrules_MOC_HDRS yesnobox.h ../../cursor.h ../../plugins/platforms/x11/standalone/x11cursor.h) +set(kwinrules_MOC_HDRS ../../cursor.h ../../plugins/platforms/x11/standalone/x11cursor.h) qt5_wrap_cpp(kwinrules_MOC_SRCS ${kwinrules_MOC_HDRS}) -set(kwinrules_SRCS ../../rulebooksettings.cpp ruleswidget.cpp ruleslist.cpp kwinsrc.cpp detectwidget.cpp main.cpp ${kwinrules_MOC_SRCS}) -ki18n_wrap_ui(kwinrules_SRCS ruleslist.ui detectwidget.ui editshortcut.ui ruleswidgetbase.ui) +set(kwinrules_SRCS + ../../rulebooksettings.cpp + optionsmodel.cpp + ruleitem.cpp + rulesmodel.cpp + rulesdialog.cpp + main.cpp + kwinsrc.cpp + ${kwinrules_MOC_SRCS} +) kconfig_add_kcfg_files(kwinrules_SRCS ../../rulesettings.kcfgc) kconfig_add_kcfg_files(kwinrules_SRCS ../../rulebooksettingsbase.kcfgc) @@ -24,6 +33,7 @@ set(kcm_libs Qt5::Concurrent Qt5::X11Extras + Qt5::QuickWidgets KF5::Completion KF5::ConfigWidgets @@ -43,13 +53,33 @@ ########### next target ############### -set(kcm_kwinrules_PART_SRCS kcm.cpp ${kwinrules_SRCS}) +set(kcmkwinrules_qml_SRCS + kcmrules.cpp + ${kwinrules_SRCS} +) + +add_library(kcm_kwinrules_qml MODULE ${kcmkwinrules_qml_SRCS}) + +target_link_libraries(kcm_kwinrules_qml + Qt5::Quick + + KF5::I18n + KF5::ConfigWidgets + KF5::CoreAddons + KF5::QuickAddons + KF5::WindowSystem + + ${kcm_libs} + ${kwin_kcm_rules_XCB_LIBS} +) -add_library(kcm_kwinrules MODULE ${kcm_kwinrules_PART_SRCS}) +kcoreaddons_desktop_to_json(kcm_kwinrules_qml "kcm_kwinrules_qml.desktop" SERVICE_TYPES kcmodule.desktop) -target_link_libraries(kcm_kwinrules ${kcm_libs} ${kwin_kcm_rules_XCB_LIBS}) +# This desktop file is installed only for retrocompatibility with sycoca +install(TARGETS kcm_kwinrules_qml DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms) +install(FILES kcm_kwinrules_qml.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) -install(TARGETS kcm_kwinrules DESTINATION ${PLUGIN_INSTALL_DIR}) +kpackage_install_package(package kcm_kwinrules_qml kcms) ########### install files ############### diff --git a/kcmkwin/kwinrules/detectwidget.h b/kcmkwin/kwinrules/detectwidget.h deleted file mode 100644 --- a/kcmkwin/kwinrules/detectwidget.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2004 Lubos Lunak - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - - -#ifndef __DETECTWIDGET_H__ -#define __DETECTWIDGET_H__ - -#include -#include - -#include "../../rules.h" -//Added by qt3to4: -#include -#include - -#include "ui_detectwidget.h" - -namespace KWin -{ - -class DetectWidget - : public QWidget, public Ui_DetectWidget -{ - Q_OBJECT -public: - explicit DetectWidget(QWidget* parent = nullptr); -}; - -class DetectDialog - : public QDialog -{ - Q_OBJECT -public: - explicit DetectDialog(QWidget* parent = nullptr, const char* name = nullptr); - void detect(int secs = 0); - QByteArray selectedClass() const; - bool selectedWholeClass() const; - QByteArray selectedRole() const; - bool selectedWholeApp() const; - NET::WindowType selectedType() const; - QString selectedTitle() const; - Rules::StringMatch titleMatch() const; - QByteArray selectedMachine() const; - - const QVariantMap &windowInfo() const { - return m_windowInfo; - } - -Q_SIGNALS: - void detectionDone(bool); -private Q_SLOTS: - void selectWindow(); -private: - void executeDialog(); - QByteArray wmclass_class; - QByteArray wmclass_name; - QByteArray role; - NET::WindowType type; - QString title; - QByteArray extrarole; - QByteArray machine; - DetectWidget* widget; - QVariantMap m_windowInfo; -}; - -} // namespace - -#endif diff --git a/kcmkwin/kwinrules/detectwidget.cpp b/kcmkwin/kwinrules/detectwidget.cpp deleted file mode 100644 --- a/kcmkwin/kwinrules/detectwidget.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2004 Lubos Lunak - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "detectwidget.h" -#include "../../plugins/platforms/x11/standalone/x11cursor.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -Q_DECLARE_METATYPE(NET::WindowType) - -namespace KWin -{ - -DetectWidget::DetectWidget(QWidget* parent) - : QWidget(parent) -{ - setupUi(this); -} - -DetectDialog::DetectDialog(QWidget* parent, const char* name) - : QDialog(parent) -{ - setObjectName(name); - setModal(true); - setLayout(new QVBoxLayout); - - widget = new DetectWidget(this); - layout()->addWidget(widget); - - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, this); - layout()->addWidget(buttons); - - connect(buttons, SIGNAL(accepted()), SLOT(accept())); - connect(buttons, SIGNAL(rejected()), SLOT(reject())); -} - -void DetectDialog::detect(int secs) -{ - QTimer::singleShot(secs*1000, this, SLOT(selectWindow())); -} - -void DetectDialog::executeDialog() -{ - static const char* const types[] = { - I18N_NOOP("Normal Window"), - I18N_NOOP("Desktop"), - I18N_NOOP("Dock (panel)"), - I18N_NOOP("Toolbar"), - I18N_NOOP("Torn-Off Menu"), - I18N_NOOP("Dialog Window"), - I18N_NOOP("Override Type"), - I18N_NOOP("Standalone Menubar"), - I18N_NOOP("Utility Window"), - I18N_NOOP("Splash Screen") - }; - widget->class_label->setText(wmclass_class + QLatin1String(" (") + wmclass_name + ' ' + wmclass_class + ')'); - widget->role_label->setText(role); - widget->match_role->setEnabled(!role.isEmpty()); - if (type == NET::Unknown) - widget->type_label->setText(i18n("Unknown - will be treated as Normal Window")); - else - widget->type_label->setText(i18n(types[ type ])); - widget->title_label->setText(title); - widget->machine_label->setText(machine); - widget->adjustSize(); - adjustSize(); - if (width() < 4*height()/3) - resize(4*height()/3, height()); - emit detectionDone(exec() == QDialog::Accepted); -} - -QByteArray DetectDialog::selectedClass() const -{ - if (widget->match_whole_class->isChecked()) - return wmclass_name + ' ' + wmclass_class; - return wmclass_class; -} - -bool DetectDialog::selectedWholeClass() const -{ - return widget->match_whole_class->isChecked(); -} - -QByteArray DetectDialog::selectedRole() const -{ - if (widget->match_role->isChecked()) - return role; - return ""; -} - -QString DetectDialog::selectedTitle() const -{ - return title; -} - -Rules::StringMatch DetectDialog::titleMatch() const -{ - return widget->match_title->isChecked() ? Rules::ExactMatch : Rules::UnimportantMatch; -} - -bool DetectDialog::selectedWholeApp() const -{ - return !widget->match_type->isChecked(); -} - -NET::WindowType DetectDialog::selectedType() const -{ - return type; -} - -QByteArray DetectDialog::selectedMachine() const -{ - return machine; -} - -void DetectDialog::selectWindow() -{ - QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KWin"), - QStringLiteral("/KWin"), - QStringLiteral("org.kde.KWin"), - QStringLiteral("queryWindowInfo")); - QDBusPendingReply async = QDBusConnection::sessionBus().asyncCall(message); - - QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(async, this); - connect(callWatcher, &QDBusPendingCallWatcher::finished, this, - [this](QDBusPendingCallWatcher *self) { - QDBusPendingReply reply = *self; - self->deleteLater(); - if (!reply.isValid()) { - emit detectionDone(false); - return; - } - m_windowInfo = reply.value(); - wmclass_class = m_windowInfo.value("resourceClass").toByteArray(); - wmclass_name = m_windowInfo.value("resourceName").toByteArray(); - role = m_windowInfo.value("role").toByteArray(); - type = m_windowInfo.value("type").value(); - title = m_windowInfo.value("caption").toString(); - machine = m_windowInfo.value("clientMachine").toByteArray(); - executeDialog(); - } - ); -} - -} // namespace - diff --git a/kcmkwin/kwinrules/detectwidget.ui b/kcmkwin/kwinrules/detectwidget.ui deleted file mode 100644 --- a/kcmkwin/kwinrules/detectwidget.ui +++ /dev/null @@ -1,229 +0,0 @@ - - - KWin::DetectWidget - - - - 0 - 0 - 450 - 300 - - - - - - - Information About Selected Window - - - true - - - - 0 - - - - - Class: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - false - - - - - - - - true - - - - - - - false - - - - - - - Role: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - false - - - - - - - - true - - - - - - - false - - - - - - - Type: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - false - - - - - - - - true - - - - - - - false - - - - - - - Title: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - false - - - - - - - - true - - - - - - - false - - - - - - - Machine: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - false - - - - - - - - true - - - - - - - false - - - - - - - - - - Match by primary class name and - - - true - - - - - - Secondary class name (resulting in term in brackets) - - - - - - - Window role (can be used to select windows by function) - - - - - - - Window type (eg. all dialogs, but not the main windows) - - - - - - - Window title (very specific, can fail due to content changes or translation) - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 0 - - - - - - - - - diff --git a/kcmkwin/kwinrules/editshortcut.ui b/kcmkwin/kwinrules/editshortcut.ui deleted file mode 100644 --- a/kcmkwin/kwinrules/editshortcut.ui +++ /dev/null @@ -1,161 +0,0 @@ - - EditShortcut - - - - 0 - 0 - 1194 - 447 - - - - - - - A single shortcut can be easily assigned or cleared using the two buttons. Only shortcuts with modifiers can be used.<p> -It is possible to have several possible shortcuts, and the first available shortcut will be used. The shortcuts are specified using shortcut sets separated by " - ". One set is specified as <i>base</i>+(<i>list</i>), where base are modifiers and list is a list of keys.<br> -For example "<b>Shift+Alt+(123) Shift+Ctrl+(ABC)</b>" will first try <b>Shift+Alt+1</b>, then others with <b>Shift+Ctrl+C</b> as the last one. - - - Qt::RichText - - - true - - - - - - - QFrame::HLine - - - QFrame::Sunken - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 40 - 20 - - - - - - - - &Single Shortcut - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 40 - 20 - - - - - - - - C&lear - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 40 - 20 - - - - - - - - - - QFrame::HLine - - - QFrame::Sunken - - - - - - - - KLineEdit - QWidget -
klineedit.h
-
-
- - - - pushButton1 - clicked() - EditShortcut - editShortcut() - - - 20 - 20 - - - 20 - 20 - - - - - pushButton2 - clicked() - EditShortcut - clearShortcut() - - - 20 - 20 - - - 20 - 20 - - - - -
diff --git a/kcmkwin/kwinrules/kcm.cpp b/kcmkwin/kwinrules/kcm.cpp deleted file mode 100644 --- a/kcmkwin/kwinrules/kcm.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2004 Lubos Lunak - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kcm.h" - -#include -//Added by qt3to4: -#include -#include -#include -#include -#include - -#include "ruleslist.h" -#include -#include - -K_PLUGIN_FACTORY(KCMRulesFactory, - registerPlugin(); - ) - -namespace KWin -{ - -KCMRules::KCMRules(QWidget *parent, const QVariantList &) - : KCModule(parent) -{ - QVBoxLayout *layout = new QVBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - - widget = new KCMRulesList(this); - layout->addWidget(widget); - connect(widget, SIGNAL(changed(bool)), SLOT(moduleChanged(bool))); - KAboutData *about = new KAboutData(QStringLiteral("kcmkwinrules"), - i18n("Window-Specific Settings Configuration Module"), - QString(), QString(), KAboutLicense::GPL, i18n("(c) 2004 KWin and KControl Authors")); - about->addAuthor(i18n("Lubos Lunak"), QString(), "l.lunak@kde.org"); - setAboutData(about); - setButtons(KCModule::Help | KCModule::Apply); -} - -void KCMRules::load() -{ - widget->load(); - emit KCModule::changed(false); -} - -void KCMRules::save() -{ - widget->save(); - emit KCModule::changed(false); - // Send signal to all kwin instances - QDBusMessage message = - QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); - QDBusConnection::sessionBus().send(message); - -} - -QString KCMRules::quickHelp() const -{ - return i18n("

Window-specific Settings

Here you can customize window settings specifically only" - " for some windows.

" - "

Please note that this configuration will not take effect if you do not use" - " KWin as your window manager. If you do use a different window manager, please refer to its documentation" - " for how to customize window behavior.

"); -} - -void KCMRules::moduleChanged(bool state) -{ - emit KCModule::changed(state); -} - -} - -// i18n freeze :-/ -#if 0 -I18N_NOOP("Remember settings separately for every window") -I18N_NOOP("Show internal settings for remembering") -I18N_NOOP("Internal setting for remembering") -#endif - - -#include "kcm.moc" diff --git a/kcmkwin/kwinrules/kcm_kwinrules_qml.desktop b/kcmkwin/kwinrules/kcm_kwinrules_qml.desktop new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/kcm_kwinrules_qml.desktop @@ -0,0 +1,164 @@ +[Desktop Entry] +Exec=kcmshell5 kwinrules_qml +Icon=preferences-system-windows-actions +Categories=Qt;KDE;X-KDE-settings-looknfeel; +Type=Service + +X-KDE-ServiceTypes=KCModule +X-KDE-Library=kcm_kwinrules_qml +X-KDE-ParentApp=kcontrol +X-KDE-System-Settings-Parent-Category=windowmanagement +X-KDE-Weight=120 + +X-KDE-FormFactors=desktop,tablet + +Name=Window Rules +Name[ar]=قواعد النوافذ +Name[bg]=Правила за прозорци +Name[bs]=Pravila prozora +Name[ca]=Regles de les finestres +Name[ca@valencia]=Regles de les finestres +Name[cs]=Pravidla oken +Name[da]=Vinduesregler +Name[de]=Fensterregeln +Name[el]=Κανόνες παραθύρου +Name[en_GB]=Window Rules +Name[es]=Reglas de las ventanas +Name[et]=Akna reeglid +Name[eu]=Leihoaren arauak +Name[fi]=Ikkunasäännöt +Name[fr]=Règles de la fenêtre +Name[ga]=Rialacha Fuinneog +Name[gl]=Regras da xanela +Name[gu]=વિન્ડો નિયમો +Name[he]=כללי חלון +Name[hi]=विंडो निय +Name[hr]=Pravila prozora +Name[hu]=Ablakszabályok +Name[ia]=Regulas de fenestra +Name[id]=Peraturan Window +Name[is]=Gluggahegðunarreglur +Name[it]=Regole delle finestre +Name[ja]=ウィンドウルール +Name[kk]=Терезе тәртібі +Name[km]=ក្បួន​បង្អួច +Name[kn]=ವಿಂಡೋ ನಿಯಮಗಳು +Name[ko]=창 규칙 +Name[lt]=Langų taisyklės +Name[lv]=Loga noteikumi +Name[mr]=चौकट नियम +Name[nb]=Vindusregler +Name[nds]=Finsterbedregen +Name[nl]=Vensterregels +Name[nn]=Vindaugsreglar +Name[pa]=ਵਿੰਡੋ ਨਿਯਮ +Name[pl]=Zasady okien +Name[pt]=Regras das Janelas +Name[pt_BR]=Regras das janelas +Name[ro]=Reguli fereastră +Name[ru]=Особые параметры окон +Name[si]=කවුළු නීති +Name[sk]=Pravidlá okien +Name[sl]=Pravila za okna +Name[sr]=Правила прозора +Name[sr@ijekavian]=Правила прозора +Name[sr@ijekavianlatin]=Pravila prozora +Name[sr@latin]=Pravila prozora +Name[sv]=Fönsterregler +Name[th]=กฎต่าง ๆ ของหน้าต่าง +Name[tr]=Pencere Kuralları +Name[ug]=كۆزنەك بەلگىلىمىسى +Name[uk]=Правила вікон +Name[wa]=Rîles des finiesses +Name[x-test]=xxWindow Rulesxx +Name[zh_CN]=窗口规则 +Name[zh_TW]=視窗規則 + +Comment=Individual Window Behavior +Comment[bs]=Ponašanje pojedinog prozora +Comment[ca]=Comportament individual de les finestres +Comment[ca@valencia]=Comportament individual de les finestres +Comment[cs]=Chování individuálních oken +Comment[da]=Opførsel af enkeltvinduer +Comment[de]=Individuelles Fensterverhalten +Comment[el]=Συμπεριφορά ανεξάρτητου παραθύρου +Comment[en_GB]=Individual Window Behaviour +Comment[es]=Comportamiento de las ventanas individuales +Comment[et]=Konkreetse akna käitumine +Comment[eu]=Leihoen banakako portaera +Comment[fi]=Yksittäisten ikkunoiden toiminta +Comment[fr]=Comportement individuel des fenêtres +Comment[gl]=Comportamento individual das xanelas +Comment[he]=התנהגות חלונות ספציפים +Comment[hu]=Egyéni ablakműveletek +Comment[ia]=Comportamento de fenestra individual +Comment[id]=Perilaku Window Individu +Comment[it]=Comportamento della singola finestra +Comment[ja]=個別のウィンドウの挙動 +Comment[ko]=개별 창 동작 +Comment[lt]=Individuali langų elgsena +Comment[nb]=Oppførsel for individuelle vinduer +Comment[nds]=Bedregen vun enkelte Finstern +Comment[nl]=Individueel venstergedrag +Comment[nn]=Åtferd for einskildvindauge +Comment[pa]=ਵੱਖ-ਵੱਖ ਵਿੰਡੋ ਰਵੱਈਆ +Comment[pl]=Wyjątkowe okna +Comment[pt]=Comportamento das Janelas Individuais +Comment[pt_BR]=Comportamento das janelas individuais +Comment[ru]=Особые параметры конкретных окон +Comment[sk]=Individuálne správanie okien +Comment[sl]=Obnašanje posameznih oken +Comment[sr]=Понашање појединачних прозора +Comment[sr@ijekavian]=Понашање појединачних прозора +Comment[sr@ijekavianlatin]=Ponašanje pojedinačnih prozora +Comment[sr@latin]=Ponašanje pojedinačnih prozora +Comment[sv]=Individuellt fönsterbeteende +Comment[tr]=Bireysel Pencere Davranışı +Comment[uk]=Поведінка окремих вікон +Comment[x-test]=xxIndividual Window Behaviorxx +Comment[zh_CN]=个别窗口行为 +Comment[zh_TW]=個別視窗行為 + +X-KDE-Keywords=size,position,state,window behavior,windows,specific,workarounds,remember,rules +X-KDE-Keywords[bs]=veličina,pozicija,grad,reagiranje prozora,prozori,specifičan,workarounds,sjećati se,pravila +X-KDE-Keywords[ca]=mida,posició,estat,comportament de la finestra,finestres,específic,solucions alternatives,recorda,regles +X-KDE-Keywords[ca@valencia]=mida,posició,estat,comportament de la finestra,finestres,específic,solucions alternatives,recorda,regles +X-KDE-Keywords[da]=størrelse,position,tilstand,vinduesopførsel,vinduer,specifikt,workarounds,husk,regler +X-KDE-Keywords[de]=Größe,Position,Status,Fensterverhalten,Fenster,Regeln +X-KDE-Keywords[el]=μέγεθος,θέση,κατάσταση,συμπεριφορά παραθύρου,παράθυρα,ειδική,εναλλακτικές,απομνημόνευση,κανόνες +X-KDE-Keywords[en_GB]=size,position,state,window behaviour,windows,specific,workarounds,remember,rules +X-KDE-Keywords[es]=tamaño,posición,estado,comportamiento de las ventanas,ventanas,específicos,soluciones,recordatorio,reglas +X-KDE-Keywords[et]=suurus,asukoht,olek,akende käitumine,aknad,meeldejätmine,reeglid +X-KDE-Keywords[eu]=tamaina,posizio,egoera,leihoaren portaera,leihoak,zehatz,konponbide,gogorarazpen,arau +X-KDE-Keywords[fi]=koko,sijainti,tila,ikkunoiden toiminta,ikkunat,erikoisasetukset,ikkunakohtaiset,korjaukset,muista,muistaminen,säännöt +X-KDE-Keywords[fr]=taille, position, état, comportement de la fenêtre, fenêtres, spécifique, contournements, rappel, règles +X-KDE-Keywords[ga]=méid,ionad,staid,oibriú na bhfuinneog,fuinneoga,sainiúil,réitigh seiftithe,meabhraigh,rialacha +X-KDE-Keywords[gl]=tamaño,posición,estado,comportamento da xanela,xanelas,específico,regra +X-KDE-Keywords[hu]=méret,elhelyezkedés,állapot,ablakműködés,ablakok,specifikus,kerülő megoldások,megjegyzés,szabályok +X-KDE-Keywords[ia]=grandor,position,stato,comportamento de fenestra,fenestras,specific,workarounds,memora,regulas +X-KDE-Keywords[id]=ukuran,posisi,kondisi,perilaku window,window,spesifik,sekeliling,ingat,peraturan +X-KDE-Keywords[it]=dimensione,posizione,stato,comportamento della finestra,finestre,specifico,espedienti,ricorda,regole +X-KDE-Keywords[kk]=size,position,state,window behavior,windows,specific,workarounds,remember,rules +X-KDE-Keywords[km]=size,position,state,window behavior,windows,specific,workarounds,remember,rules +X-KDE-Keywords[ko]=size,position,state,window behavior,windows,specific,workarounds,remember,rules,크기,위치,창 행동,창,창 지정,규칙 +X-KDE-Keywords[lt]=dydis,pozicija,vieta,būsena,busena,lango elgsena,langų elgsena,langu elgsena,langas,langai,apėjimas,apejimas,apėjimai,apejimai,specifiniai,tam tikri,tam tikros,tam tikrų,tam tikru,įsiminti,isiminti,atsiminti,prisiminti,taisyklės,taisykles +X-KDE-Keywords[nb]=størrelse,plassering,vindusoppførsel,vindu,bestemt,løsninger,husk,regler +X-KDE-Keywords[nds]=Grött,Positschoon,Tostand,Finsterbedregen,Finstern,besünner,Ümto,wohren,Regeln +X-KDE-Keywords[nl]=grootte,positie,status,venstergedrag,vensters,specifiek,er omheen gewerkt,herinneren,regels +X-KDE-Keywords[nn]=storleik,plassering,tilstand,vindaugsåtferd,vindauge,einskild,løysingar,unntak,hugs,reglar +X-KDE-Keywords[pl]=rozmiar,pozycja,stan,zachowanie okna,okna,specyficzne,obejścia,zapamiętaj,reguły +X-KDE-Keywords[pt]=tamanho,posição,estado,comportamento da janela,janelas,específico,alternativas,recordar,regras +X-KDE-Keywords[pt_BR]=tamanho,posição,estado,comportamento da janela,janelas,específico,alternativas,lembrar,regras +X-KDE-Keywords[ru]=size,position,state,window behavior,windows,specific,workarounds,remember,rules,размер,позиция,состояние,поведение окон,окна,специальный,специальные возможности,запомнить,правила +X-KDE-Keywords[sk]=veľkosť,poloha,stav,správanie okien,okná,špecifický,workaroundy,pamätať,pravidlá +X-KDE-Keywords[sl]=velikost,položaj,stanje,obnašanje oken,okna,določeno,popravki,pomnjenje,pravila +X-KDE-Keywords[sr]=size,position,state,window behavior,windows,specific,workarounds,remember,rules,величина,положај,стање,понашање прозора,прозор,заобилазак,запамти,правила +X-KDE-Keywords[sr@ijekavian]=size,position,state,window behavior,windows,specific,workarounds,remember,rules,величина,положај,стање,понашање прозора,прозор,заобилазак,запамти,правила +X-KDE-Keywords[sr@ijekavianlatin]=size,position,state,window behavior,windows,specific,workarounds,remember,rules,veličina,položaj,stanje,ponašanje prozora,prozor,zaobilazak,zapamti,pravila +X-KDE-Keywords[sr@latin]=size,position,state,window behavior,windows,specific,workarounds,remember,rules,veličina,položaj,stanje,ponašanje prozora,prozor,zaobilazak,zapamti,pravila +X-KDE-Keywords[sv]=storlek,position,tillstånd,fönsterbeteende,fönster,specifik,kom ihåg,regler +X-KDE-Keywords[tr]=boyut,konum,durum,pencere davranışı,pencere,özel,etrafından dolanmalar,anımsa,kurallar +X-KDE-Keywords[uk]=size,position,state,window behavior,windows,specific,workarounds,remember,rules,розмір,розташування,місце,стан,поведінка,вікно,вікна,поведінка вікон,окрема,специфічна,окремо,запам’ятати,пам’ять,правило,правила +X-KDE-Keywords[x-test]=xxsizexx,xxpositionxx,xxstatexx,xxwindow behaviorxx,xxwindowsxx,xxspecificxx,xxworkaroundsxx,xxrememberxx,xxrulesxx +X-KDE-Keywords[zh_CN]=size,position,state,window behavior,windows,specific,workarounds,remember,rules,大小,位置,窗口行为,特定,记住,规则 +X-KDE-Keywords[zh_TW]=size,position,state,window behavior,windows,specific,workarounds,remember,rules diff --git a/kcmkwin/kwinrules/kcmrules.h b/kcmkwin/kwinrules/kcmrules.h new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/kcmrules.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include "rulebooksettings.h" +#include "rulesmodel.h" + +#include + +#include + + +namespace KWin +{ + +class KCMKWinRules : public KQuickAddons::ConfigModule +{ + Q_OBJECT + + Q_PROPERTY(QStringList ruleBookModel READ ruleBookModel NOTIFY ruleBookModelChanged) + Q_PROPERTY(int editingIndex READ editingIndex NOTIFY editingIndexChanged) + Q_PROPERTY(RulesModel *rulesModel MEMBER m_rulesModel CONSTANT) + +public: + explicit KCMKWinRules(QObject *parent, const QVariantList &arguments); + ~KCMKWinRules() override; + + Q_INVOKABLE void editRule(int index); + + Q_INVOKABLE void createRule(); + Q_INVOKABLE void removeRule(int index); + Q_INVOKABLE void moveRule(int sourceIndex, int destIndex); + + Q_INVOKABLE void exportRule(int index); + Q_INVOKABLE void importRules(); + +public slots: + void load() override; + void save() override; + +signals: + void ruleBookModelChanged(); + void editingIndexChanged(); + +private slots: + void updateNeedsSave(); + void updateState(); + +private: + QStringList ruleBookModel() const; + int editingIndex() const; + void saveCurrentRule(); + +private: + RuleBookSettings *m_ruleBook; + QVector m_rules; + RulesModel* m_rulesModel; + + int m_editingIndex = -1; +}; + +} // namespace diff --git a/kcmkwin/kwinrules/kcmrules.cpp b/kcmkwin/kwinrules/kcmrules.cpp new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/kcmrules.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2004 Lubos Lunak + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "kcmrules.h" + +#include +#include + +#include +#include +#include +#include + + +namespace +{ + const QString s_configFile { QLatin1String("kwinrulesrc") }; +} + +namespace KWin +{ + +KCMKWinRules::KCMKWinRules(QObject *parent, const QVariantList &arguments) + : KQuickAddons::ConfigModule(parent, arguments) + , m_ruleBook(new RuleBookSettings(this)) + , m_rulesModel(new RulesModel(this)) +{ + auto about = new KAboutData(QStringLiteral("kcm_kwinrules_qml"), + i18n("Window Rules"), + QStringLiteral("1.0"), + QString(), + KAboutLicense::GPL); + about->addAuthor(i18n("Ismael Asensio"), + i18n("Author"), + QStringLiteral("isma.af@gmail.com")); + setAboutData(about); + + setQuickHelp(i18n("

Window-specific Settings

Here you can customize window settings specifically only" + " for some windows.

" + "

Please note that this configuration will not take effect if you do not use" + " KWin as your window manager. If you do use a different window manager, please refer to its documentation" + " for how to customize window behavior.

")); + + connect(m_rulesModel, &RulesModel::descriptionChanged, this, [this]{ + if (m_editingIndex >=0 && m_editingIndex < m_ruleBook->count()) { + m_rules.at(m_editingIndex)->description = m_rulesModel->description(); + emit ruleBookModelChanged(); + } + } ); + connect(m_rulesModel, &RulesModel::dataChanged, this, &KCMKWinRules::updateNeedsSave); +} + +KCMKWinRules::~KCMKWinRules() { + qDeleteAll(m_rules); +} + + +QStringList KCMKWinRules::ruleBookModel() const +{ + QStringList ruleDescriptionList; + for (const Rules *rule : qAsConst(m_rules)) { + ruleDescriptionList.append(rule->description); + } + return ruleDescriptionList; +} + + +void KCMKWinRules::load() +{ + m_ruleBook->load(); + m_rules = m_ruleBook->rules(); + + setNeedsSave(false); + emit ruleBookModelChanged(); + + // Check if current index is no longer valid + if (m_editingIndex >= m_rules.count()) { + m_editingIndex = -1; + pop(); + emit editingIndexChanged(); + } + // Reset current index for rule editor + if (m_editingIndex > 0) { + m_rulesModel->importFromRules(m_rules.at(m_editingIndex)); + } +} + +void KCMKWinRules::save() +{ + saveCurrentRule(); + m_ruleBook->setRules(m_rules); + m_ruleBook->save(); + + QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); + QDBusConnection::sessionBus().send(message); +} + +void KCMKWinRules::updateState() +{ + m_ruleBook->setCount(m_rules.count()); + + emit editingIndexChanged(); + emit ruleBookModelChanged(); + + updateNeedsSave(); +} + +void KCMKWinRules::updateNeedsSave() +{ + setNeedsSave(true); + emit needsSaveChanged(); +} + +void KCMKWinRules::saveCurrentRule() +{ + if (m_editingIndex < 0) { + return; + } + if (needsSave()) { + delete(m_rules[m_editingIndex]); + m_rules[m_editingIndex] = m_rulesModel->exportToRules(); + } +} + + +int KCMKWinRules::editingIndex() const +{ + return m_editingIndex; +} + +void KCMKWinRules::editRule(int index) +{ + if (index < 0 || index >= m_rules.count()) { + return; + } + saveCurrentRule(); + + m_editingIndex = index; + m_rulesModel->importFromRules(m_rules.at(m_editingIndex)); + + emit editingIndexChanged(); + + // Show and move to Rules Editor page + if (depth() < 2) { + push(QStringLiteral("RulesEditor.qml")); + } + setCurrentIndex(1); +} + +void KCMKWinRules::createRule() +{ + + m_rules.append(new Rules()); + updateState(); + + const int newIndex = m_rules.count() - 1; + editRule(newIndex); + + saveCurrentRule(); +} + +void KCMKWinRules::removeRule(int index) +{ + if (index < 0 || index >= m_rules.count()) { + return; + } + + if (m_editingIndex == index) { + m_editingIndex = -1; + pop(); + } + + delete(m_rules.at(index)); + m_rules.removeAt(index); + + updateState(); +} + +void KCMKWinRules::moveRule(int sourceIndex, int destIndex) +{ + const int lastIndex = m_rules.count() - 1; + if (sourceIndex == destIndex + || (sourceIndex < 0 || sourceIndex > lastIndex) + || (destIndex < 0 || destIndex > lastIndex)) { + return; + } + + m_rules.move(sourceIndex, destIndex); + + if (m_editingIndex == sourceIndex) { + m_editingIndex = destIndex; + emit editingIndexChanged(); + } else if (m_editingIndex > sourceIndex && m_editingIndex <= destIndex) { + m_editingIndex -= 1; + emit editingIndexChanged(); + } else if (m_editingIndex < sourceIndex && m_editingIndex >= destIndex) { + m_editingIndex += 1; + emit editingIndexChanged(); + } + + emit ruleBookModelChanged(); +} + +void KCMKWinRules::exportRule(int index) +{ + Q_ASSERT(index >= 0 && index < m_rules.count()); + + saveCurrentRule(); + + const QString description = m_rules.at(index)->description; + const QString defaultPath = QDir(QDir::home()).filePath(description + QStringLiteral(".kwinrule")); + const QString path = QFileDialog::getSaveFileName(nullptr, i18n("Export Rules"), defaultPath, + i18n("KWin Rules (*.kwinrule)")); + if (path.isEmpty()) + return; + + const auto config = KSharedConfig::openConfig(path, KConfig::SimpleConfig); + RuleSettings settings(config, m_rules.at(index)->description); + + settings.setDefaults(); + m_rules.at(index)->write(&settings); + settings.save(); +} + +void KCMKWinRules::importRules() +{ + QString path = QFileDialog::getOpenFileName(nullptr, + i18n("Import Rules"), + QDir::home().absolutePath(), + i18n("KWin Rules (*.kwinrule)")); + + if (path.isEmpty()) { + return; + } + + const auto config = KSharedConfig::openConfig(path, KConfig::SimpleConfig); + const QStringList groups = config->groupList(); + if (groups.isEmpty()) { + return; + } + + for (const QString &groupName : groups) { + RuleSettings settings(config, groupName); + + const bool remove = settings.deleteRule(); + const QString importDescription = settings.description(); + if (importDescription.isEmpty()) { + continue; + } + + // Try to find a rule with the same description to replace + int newIndex = -2; + for (int index = 0; index < m_rules.count(); index++) { + if (m_rules.at(index)->description == importDescription) { + newIndex = index; + break; + } + } + + if (remove) { + removeRule(newIndex); + continue; + } + + Rules *newRule = new Rules(&settings); + + if (newIndex < 0) { + m_rules.append(newRule); + } else { + delete m_rules[newIndex]; + m_rules[newIndex] = newRule; + } + + // Reset rule editor if the current rule changed when importing + if (m_editingIndex == newIndex) { + m_rulesModel->importFromRules(m_rules.at(m_editingIndex)); + } + } + + updateState(); +} + +K_PLUGIN_CLASS_WITH_JSON(KCMKWinRules, "kcm_kwinrules_qml.json"); + +} // namespace + +#include "kcmrules.moc" diff --git a/kcmkwin/kwinrules/main.cpp b/kcmkwin/kwinrules/main.cpp --- a/kcmkwin/kwinrules/main.cpp +++ b/kcmkwin/kwinrules/main.cpp @@ -22,8 +22,8 @@ #include #include -#include "ruleswidget.h" #include "rulebooksettings.h" +#include "rulesdialog.h" #include "../../rules.h" #include diff --git a/kcmkwin/kwinrules/optionsmodel.h b/kcmkwin/kwinrules/optionsmodel.h new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/optionsmodel.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KWIN_OPTIONS_MODEL_H +#define KWIN_OPTIONS_MODEL_H + +#include + +#include +#include +#include + + +namespace KWin { + +class OptionsModel : public QAbstractListModel +{ + Q_OBJECT + //TODO: After Qt 5.14 the QML ComboBox will allow to use the valueRole directly + // instead of changing the index. Remove this exposed property + Q_PROPERTY(int selectedIndex READ selectedIndex NOTIFY selectedIndexChanged) + +public: + struct Data { + Data(const QVariant &value, const QString &text, const QIcon &icon = {}, const QString &description = {}) + : value(value) + , text(text) + , icon(icon) + , description(description) + {} + Data(const QVariant &value, const QString &text, const QString &description) + : value(value) + , text(text) + , description(description) + {} + + QVariant value; + QString text; + QIcon icon; + QString description; + }; + +public: + OptionsModel() : QAbstractListModel(), m_data(), m_index(0) {}; + OptionsModel(const QList &data) : QAbstractListModel(), m_data(data), m_index(0) {}; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QHash roleNames() const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + QVariant value() const; + void setValue(QVariant value); + void resetValue(); + + void updateModelData(const QList &data); + + //TODO: Remove after Qt 5.14 + int selectedIndex() const; + +signals: + void selectedIndexChanged(int index); + +public: + QList m_data; + +protected: + int m_index = 0; +}; + +class RulePolicy : public OptionsModel +{ +public: + enum Type { + NoPolicy, + StringMatch, + SetRule, + ForceRule + }; + +public: + RulePolicy(Type type) + : OptionsModel(policyOptions(type)) + , m_type(type) + {}; + + Type type() const; + int value() const; + QString policyKey(const QString &key) const; + +private: + static QList policyOptions(RulePolicy::Type type); + +private: + Type m_type; +}; + +} //namespace + +#endif //KWIN_OPTIONS_MODEL_H diff --git a/kcmkwin/kwinrules/optionsmodel.cpp b/kcmkwin/kwinrules/optionsmodel.cpp new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/optionsmodel.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "optionsmodel.h" + +#include + + +namespace KWin +{ + +QHash OptionsModel::roleNames() const +{ + return { + {Qt::DisplayRole, QByteArrayLiteral("text")}, + {Qt::UserRole, QByteArrayLiteral("value")}, + {Qt::DecorationRole, QByteArrayLiteral("icon")}, + {Qt::ToolTipRole, QByteArrayLiteral("description")}, + {Qt::UserRole + 1, QByteArrayLiteral("iconName")}, + }; +} + +int OptionsModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } + return m_data.size(); +} + +QVariant OptionsModel::data(const QModelIndex &index, int role) const +{ + if (!checkIndex(index, CheckIndexOption::IndexIsValid | CheckIndexOption::ParentIsInvalid)) { + return QVariant(); + } + + const Data data = m_data.at(index.row()); + + switch (role) { + case Qt::DisplayRole: + return data.text; + case Qt::UserRole: + return data.value; + case Qt::DecorationRole: + return data.icon; + case Qt::UserRole + 1: + return data.icon.name(); + case Qt::ToolTipRole: + return data.description; + } + return QVariant(); +} + +int OptionsModel::selectedIndex() const +{ + return m_index; +} + +QVariant OptionsModel::value() const +{ + if (m_data.isEmpty()) { + return QVariant(); + } + return m_data.at(m_index).value; +} + +void OptionsModel::setValue(QVariant value) +{ + if (this->value() == value) { + return; + } + for (int index = 0; index < m_data.count(); index++) { + if (m_data.at(index).value != value) { + continue; + } + if (m_index != index) { + m_index = index; + emit selectedIndexChanged(index); + } + } +} + +void OptionsModel::resetValue() +{ + m_index = 0; + emit selectedIndexChanged(m_index); +} + +void OptionsModel::updateModelData(const QList &data) { + beginResetModel(); + m_data = data; + endResetModel(); +} + + +RulePolicy::Type RulePolicy::type() const +{ + return m_type; +} + +int RulePolicy::value() const +{ + if (m_type == RulePolicy::NoPolicy) { + return Rules::Apply; // To simplify external checks when rule has no policy + } + return OptionsModel::value().toInt(); +} + +QString RulePolicy::policyKey(const QString &key) const +{ + switch (m_type) { + case NoPolicy: + return QString(); + case StringMatch: + return QStringLiteral("%1match").arg(key); + case SetRule: + case ForceRule: + return QStringLiteral("%1rule").arg(key); + } + + return QString(); +} + +QList RulePolicy::policyOptions(RulePolicy::Type type) +{ + static const auto stringMatchOptions = QList { + {Rules::UnimportantMatch, i18n("Unimportant")}, + {Rules::ExactMatch, i18n("Exact Match")}, + {Rules::SubstringMatch, i18n("Substring Match")}, + {Rules::RegExpMatch, i18n("Regular Expression")} + }; + + static const auto setRuleOptions = QList { + {Rules::DontAffect, + i18n("Do Not Affect"), + i18n("The window property will not be affected and therefore the default handling for it will be used." + "\nSpecifying this will block more generic window settings from taking effect.")}, + {Rules::Apply, + i18n("Apply Initially"), + i18n("The window property will be only set to the given value after the window is created." + "\nNo further changes will be affected.")}, + {Rules::Remember, + i18n("Remember"), + i18n("The value of the window property will be remembered and, every time the window" + " is created, the last remembered value will be applied.")}, + {Rules::Force, + i18n("Force"), + i18n("The window property will be always forced to the given value.")}, + {Rules::ApplyNow, + i18n("Apply Now"), + i18n("The window property will be set to the given value immediately and will not be affected later" + "\n(this action will be deleted afterwards).")}, + {Rules::ForceTemporarily, + i18n("Force Temporarily"), + i18n("The window property will be forced to the given value until it is hidden" + "\n(this action will be deleted after the window is hidden).")} + }; + + static auto forceRuleOptions = QList { + setRuleOptions.at(0), // Rules::DontAffect + setRuleOptions.at(3), // Rules::Force + setRuleOptions.at(5), // Rules::ForceTemporarily + }; + + switch (type) { + case NoPolicy: + return {}; + case StringMatch: + return stringMatchOptions; + case SetRule: + return setRuleOptions; + case ForceRule: + return forceRuleOptions; + } + return {}; +} + +} //namespace diff --git a/kcmkwin/kwinrules/package/contents/ui/OptionsComboBox.qml b/kcmkwin/kwinrules/package/contents/ui/OptionsComboBox.qml new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/package/contents/ui/OptionsComboBox.qml @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 as QQC2 + +import org.kde.kirigami 2.10 as Kirigami + + +QQC2.ComboBox { + id: optionsCombo + + textRole: "text" + //FIXME: After Qt 5.14 this can be replaced by the new implemented properties: + // valueRole: "value"` + // currentValue: model.value + + property var currentValue + property var values: [] + + currentIndex: model.selectedIndex + + onActivated: (index) => { + currentValue = values[index]; + } + + delegate: QQC2.ItemDelegate { + highlighted: optionsCombo.highlightedIndex == index + width: parent.width + + contentItem: RowLayout { + Kirigami.Icon { + source: model.icon + Layout.preferredHeight: Kirigami.Units.iconSizes.small + Layout.preferredWidth: Kirigami.Units.iconSizes.small + } + QQC2.Label { + text: model.text + color: highlighted ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.textColor + Layout.fillWidth: true + } + } + + QQC2.ToolTip { + text: model.description + visible: hovered && (model.description != "") + } + + Component.onCompleted: { + values[index] = model.value; + optionsCombo.popup.width = Math.max(implicitWidth, optionsCombo.width, optionsCombo.popup.width); + } + } +} diff --git a/kcmkwin/kwinrules/package/contents/ui/RuleItemDelegate.qml b/kcmkwin/kwinrules/package/contents/ui/RuleItemDelegate.qml new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/package/contents/ui/RuleItemDelegate.qml @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 as QQC2 +import org.kde.kirigami 2.10 as Kirigami + +Kirigami.AbstractListItem { + id: ruleDelegate + + property bool ruleEnabled: model.enabled + + Kirigami.Theme.colorSet: Kirigami.Theme.View + + RowLayout { + anchors { + left: parent.left + right: parent.right + margins: Kirigami.Units.smallSpacing + } + + QQC2.CheckBox { + id: itemEnabled + opacity: model.selectable ? 1 : 0 + checked: model.enabled + onToggled: { model.enabled = checked; } + } + + Kirigami.Icon { + id: itemIcon + source: model.icon + Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium + Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium + Layout.rightMargin: Kirigami.Units.smallSpacing + QQC2.ToolTip { + text: model.description + visible: hovered && (model.description != "") + } + } + + QQC2.Label { + text: model.name + Layout.minimumWidth: 12 * Kirigami.Units.gridUnit + elide: Text.ElideRight + } + + Item { + Layout.fillWidth: true + } + + OptionsComboBox { + id: policyCombo + Layout.minimumWidth: 6 * Kirigami.Units.gridUnit + Layout.maximumWidth: 12 * Kirigami.Units.gridUnit + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + flat: true + + visible: count > 0 + enabled: ruleEnabled + + model: policyModel + onActivated: { + policy = currentValue; + } + } + + ValueEditor { + id: valueEditor + Layout.minimumWidth: 9 * Kirigami.Units.gridUnit + Layout.maximumWidth: policyCombo.visible ? 20 * Kirigami.Units.gridUnit + : 32 * Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing + Layout.fillWidth: true + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + + enabled: model.enabled + + ruleValue: model.value + ruleOptions: model.options + controlType: model.type + + onValueEdited: (value) => { + model.value = value; + } + } + } +} diff --git a/kcmkwin/kwinrules/package/contents/ui/RulesEditor.qml b/kcmkwin/kwinrules/package/contents/ui/RulesEditor.qml new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/package/contents/ui/RulesEditor.qml @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 as QQC2 +import org.kde.kirigami 2.10 as Kirigami +import org.kde.kcm 1.2 + + +ScrollViewKCM { + id: rulesEditor + property var rulesModel: kcm.rulesModel + + title: rulesModel.description + + header: RowLayout { + id: filterBar + Kirigami.SearchField { + id: searchField + + Layout.fillWidth: true + placeholderText: i18n("Search...") + focusSequence: "Ctrl+F" + + onTextChanged: { + rulesModel.filter.searchText = text; + } + } + QQC2.ToolButton { + id: showAllButton + icon.name: checked ? 'view-visible' : 'view-hidden' + text: i18n("Show All Rules") + checkable: true + enabled: searchField.text.trim() == "" + Binding { + target: rulesModel.filter + property: "showAll" + value: showAllButton.checked + } + } + } + + view: ListView { + id: rulesView + clip: true + + model: rulesModel.filter + delegate: RuleItemDelegate {} + section { + property: "section" + delegate: Kirigami.ListSectionHeader { label: section } + } + } + + // FIXME: InlineMessage.qml:241:13: QML Label: Binding loop detected for property "verticalAlignment" + footer: GridLayout { + id: kcmFooter + columns: 2 + + QQC2.Button { + Layout.fillWidth: true + text: i18n("Detect window properties") + icon.name: "edit-find" // TODO: Better icon for "Detect window properties" + onClicked: { + rulesModel.detectWindowProperties(detection_delay.value); + } + } + + QQC2.SpinBox { + id: detection_delay + from: 0 + to: 30 + textFromValue: (value, locale) => { + return (value == 0) ? i18n("Instantly") + : i18np("After 1 second", "After %1 seconds", value) + } + } + + Kirigami.InlineMessage { + id: warningMessage + + Layout.columnSpan: kcmFooter.columns + Layout.fillWidth: true + Layout.fillHeight: true + + visible: rulesModel.showWarning + text: i18n("You have specified the window class as unimportant.\n" + + "This means the settings will possibly apply to windows from all " + + "applications. If you really want to create a generic setting, it is " + + "recommended you at least limit the window types to avoid special window " + + "types.") + } + } +} diff --git a/kcmkwin/kwinrules/package/contents/ui/RulesList.qml b/kcmkwin/kwinrules/package/contents/ui/RulesList.qml new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/package/contents/ui/RulesList.qml @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 as QQC2 +import org.kde.kcm 1.2 +import org.kde.kirigami 2.5 as Kirigami + +ScrollViewKCM { + id: rulesListKCM + + property int dragIndex: -1 + property int dropIndex: -1 + + // FIXME: ScrollViewKCM.qml:73:13: QML Control: Binding loop detected for property "implicitHeight" + implicitWidth: Kirigami.Units.gridUnit * 35 + implicitHeight: Kirigami.Units.gridUnit * 25 + + ConfigModule.columnWidth: Kirigami.Units.gridUnit * 22 + ConfigModule.buttons: ConfigModule.Apply + + view: ListView { + id: ruleBookView + clip: true + + model: kcm.ruleBookModel + delegate: Kirigami.DelegateRecycler { + width: ruleBookView.width + sourceComponent: ruleBookDelegate + } + currentIndex: kcm.editingIndex + + Rectangle { + id: dropIndicator + x: 0 + z: 100 + width: parent.width + height: Kirigami.Units.smallSpacing + color: Kirigami.Theme.highlightColor + visible: (dropIndex >= 0) && (dropIndex != dragIndex) + + Connections { + target: rulesListKCM + onDropIndexChanged: { + if (dropIndex >= 0) { + // TODO: After Qt 5.13 we can use ListView.itemAtIndex(index) + var dropItem = ruleBookView.contentItem.children[dropIndex]; + dropIndicator.y = (dropIndex < dragIndex) ? dropItem.y : dropItem.y + dropItem.height; + } + } + } + } + } + + footer: Kirigami.ActionToolBar { + Layout.fillWidth: true + alignment: Qt.AlignRight + + actions: [ + Kirigami.Action { + text: i18n("Import") + iconName: "document-import" + onTriggered: kcm.importRules(); + } + , + Kirigami.Action { + text: i18n("New") + iconName: "list-add-symbolic" + onTriggered: kcm.createRule(); + } + ] + } + + Component { + id: ruleBookDelegate + Kirigami.AbstractListItem { + id: ruleBookItem + + RowLayout { + //FIXME: If not used within DelegateRecycler, item goes on top of the first item when clicked + //FIXME: Improve visuals and behavior when dragging on the list. + Kirigami.ListItemDragHandle { + listItem: ruleBookItem + listView: ruleBookView + onMoveRequested: { + dragIndex = oldIndex; + dropIndex = newIndex; + } + onDropped: { + if (dropIndex >= 0 && dropIndex != dragIndex) { + kcm.moveRule(dragIndex, dropIndex); + } + dragIndex = -1; + dropIndex = -1; + } + } + + QQC2.Label { + text: modelData + } + + Kirigami.ActionToolBar { + Layout.fillWidth: true + alignment: Qt.AlignRight + display: QQC2.Button.IconOnly + opacity: ruleBookItem.hovered ? 1 : 0 + focus: false + + actions: [ + Kirigami.Action { + text: i18n("Edit") + iconName: "edit-entry" + onTriggered: kcm.editRule(index); + } + , + Kirigami.Action { + text: i18n("Export") + iconName: "document-export" + onTriggered: kcm.exportRule(index); + } + , + Kirigami.Action { + text: i18n("Delete") + iconName: "entry-delete" + onTriggered: kcm.removeRule(index); + } + ] + } + } + } + } +} diff --git a/kcmkwin/kwinrules/package/contents/ui/ValueEditor.qml b/kcmkwin/kwinrules/package/contents/ui/ValueEditor.qml new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/package/contents/ui/ValueEditor.qml @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 as QQC2 + +import org.kde.kirigami 2.10 as Kirigami +import org.kde.kquickcontrols 2.0 as KQC +import org.kde.kcms.kwinrules 1.0 + + +Loader { + id: valueEditor + focus: true + + property var ruleValue + property var ruleOptions + property int controlType + + signal valueEdited(var value) + + sourceComponent: { + switch (controlType) { + case RuleItem.Boolean: return booleanEditor + case RuleItem.String: return stringEditor + case RuleItem.Integer: return integerEditor + case RuleItem.Option: return optionEditor + case RuleItem.FlagsOption: return flagsEditor + case RuleItem.Percentage: return percentageEditor + case RuleItem.Coordinate: return coordinateEditor + case RuleItem.Shortcut: return shortcutEditor + default: return emptyEditor + } + } + + Component { + id: emptyEditor + Item {} + } + + Component { + id: booleanEditor + RowLayout { + Item { + Layout.fillWidth: true + } + QQC2.Switch { + text: checked ? i18n("Yes") : i18n("No") + checked: ruleValue + onToggled: valueEditor.valueEdited(checked) + } + } + } + + Component { + id: stringEditor + QQC2.TextField { + property bool isTextEdited: false + text: ruleValue + onTextEdited: { isTextEdited = true; } + onEditingFinished: { + if (isTextEdited) { valueEditor.valueEdited(text); } + isTextEdited = false; + } + } + } + + Component { + id: integerEditor + QQC2.SpinBox { + editable: true + value: ruleValue + onValueModified: valueEditor.valueEdited(value) + } + } + + Component { + id: optionEditor + OptionsComboBox { + flat: true + model: ruleOptions + onActivated: (index) => { + valueEditor.valueEdited(currentValue); + } + } + } + + Component { + id: flagsEditor + RowLayout { + Layout.minimumWidth: 10 * Kirigami.Units.gridUnit + Layout.alignment: Qt.AlignRight; + spacing: 0 + Repeater { + id: flagsRepeater + model: ruleOptions + + QQC2.ToolButton { + property int bit: model.value + icon.name: model.iconName + checkable: true + checked: (ruleValue & (1 << bit)) == (1 << bit) + QQC2.ToolTip.text: model.text + QQC2.ToolTip.visible: hovered + onToggled: { + valueEditor.valueEdited((ruleValue & ~(1 << bit)) | (checked << bit)); + } + } + } + } + } + + Component { + id: percentageEditor + RowLayout { + QQC2.Slider { + id: slider + Layout.fillWidth: true + from: 0 + to: 100 + value: ruleValue + onMoved: valueEditor.valueEdited(Math.round(slider.value)) + } + QQC2.Label { + text: i18n("%1 %", Math.round(slider.value)) + width: 2 * Kirigami.Units.gridUnit + } + } + } + + Component { + id: coordinateEditor + RowLayout { + id: coordItem + spacing: Kirigami.Units.smallSpacing + + property var coords: ruleValue ? ruleValue.split(',') : [0, 0] + property int coordWidth: (coordItem.width - coordSeparator.width) / 2 - coordItem.spacing + + QQC2.SpinBox { + id: coordX + editable: true + implicitWidth: coordWidth + from: 0 + to: 4098 + value: coords[0] + onValueModified: valueEditor.valueEdited(coordX.value + "," + coordY.value) + } + QQC2.Label { + id: coordSeparator + text: i18nc("(x, y) coordinates separator in size/position","x") + horizontalAlignment: Text.AlignHCenter + } + QQC2.SpinBox { + id: coordY + editable: true + from: 0 + to: 4098 + implicitWidth: coordWidth + value: coords[1] + onValueModified: valueEditor.valueEdited(coordX.value + "," + coordY.value) + } + } + } + + Component { + id: shortcutEditor + RowLayout { + Item { + Layout.fillWidth: true + } + KQC.KeySequenceItem { + keySequence: ruleValue + onCaptureFinished: valueEditor.valueEdited(keySequence) + } + } + } +} diff --git a/kcmkwin/kwinrules/package/metadata.desktop b/kcmkwin/kwinrules/package/metadata.desktop new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/package/metadata.desktop @@ -0,0 +1,19 @@ +[Desktop Entry] +Icon=preferences-system-windows-actions +Type=Service +Keywords= +X-KDE-ParentApp= +X-KDE-System-Settings-Parent-Category=applicationstyle +X-KDE-PluginInfo-Author=Ismael Asensio +X-KDE-PluginInfo-Email=isma.af@gmail.com +X-KDE-PluginInfo-License=GPL-2.0+ +X-KDE-PluginInfo-Name=kcm_kwinrules_qml +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website=https://www.kde.org/plasma-desktop +X-KDE-ServiceTypes=Plasma/Generic +X-Plasma-API=declarativeappletscript +X-Plasma-MainScript=ui/RulesList.qml +X-KDE-FormFactors=desktop,tablet + +Name=Window Rules (QML) +Comment=Individual Window Behavior diff --git a/kcmkwin/kwinrules/regenerateindex.sh b/kcmkwin/kwinrules/regenerateindex.sh new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/regenerateindex.sh @@ -0,0 +1 @@ +/home/isma/kde/usr/bin/kpackagetool5 --generate-index -g -p /home/isma/kde/usr/share/kpackage/kcms diff --git a/kcmkwin/kwinrules/ruleitem.h b/kcmkwin/kwinrules/ruleitem.h new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/ruleitem.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KWIN_RULEITEM_H +#define KWIN_RULEITEM_H + +#include "optionsmodel.h" + +#include + + +namespace KWin +{ + +class RuleItemPrivate; + +class RuleItem : public QObject +{ + Q_OBJECT + +public: + enum Type { + Undefined, + Boolean, + String, + Integer, + Option, + FlagsOption, + Percentage, + Coordinate, + Shortcut + }; + Q_ENUM(Type) + + enum Flags { + NoFlags = 0, + AlwaysEnabled = 1u << 0, + StartEnabled = 1u << 1, + AffectsWarning = 1u << 2, + AffectsDescription = 1u << 3, + AllFlags = 0b1111 + }; + +public: + RuleItem() {}; + RuleItem(const QString &key, + const RulePolicy::Type policyType, + const Type type, + const QString &name, + const QString §ion, + const QString &iconName = QStringLiteral("window"), + const QList &options = {} + ); + ~RuleItem(); + + QString key() const; + QString name() const; + QString section() const; + QIcon icon() const; + QString iconName() const; + + bool isEnabled() const; + void setEnabled(bool enabled); + + QString description() const; + void setDescription(const QString &description); + + bool hasFlag(uint flag) const; + void setFlags(uint flags, bool active=true); + + Type type() const; + QVariant value() const; + void setValue(QVariant value); + + QVariant options() const; + void setOptionsData(const QList &data); + + RulePolicy::Type policyType() const; + int policy() const; // int belongs to anonymous enum in Rules:: + void setPolicy(int policy); // int belongs to anonymous enum in Rules:: + QVariant policyModel() const; + QString policyKey() const; + + void reset(); + +private: + static QVariant typedValue(const QVariant &value, const Type type); + +private: + RuleItemPrivate *d; + RulePolicy *p; + OptionsModel *o; +}; + +} //namespace + +#endif //KWIN_RULEITEM_H diff --git a/kcmkwin/kwinrules/ruleitem.cpp b/kcmkwin/kwinrules/ruleitem.cpp new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/ruleitem.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ruleitem.h" + + +namespace KWin +{ + +class RuleItemPrivate +{ +public: + RuleItemPrivate(const QString &key, const QString &name, const QString §ion, const QString &iconName) + : m_key(key) + , m_name(name) + , m_section(section) + , m_icon(QIcon::fromTheme(iconName)) + , m_enabled(false) + , m_flags(0) + {}; + +public: + QString m_key; + QString m_name; + QString m_section; + QIcon m_icon; + + bool m_enabled; + + QString m_description; + uint m_flags; + + RuleItem::Type m_type; + QVariant m_value; +}; + + +RuleItem::RuleItem(const QString &key, + const RulePolicy::Type policyType, + const RuleItem::Type type, + const QString &name, + const QString §ion, + const QString &iconName, + const QList &options + ) + : d(new RuleItemPrivate(key, name, section, iconName)) + , p(new RulePolicy(policyType)) + , o(nullptr) +{ + d->m_type = type; + if (type == Option || type == FlagsOption) { + o = new OptionsModel(options); + } + + reset(); +} + +RuleItem::~RuleItem() +{ + delete d; + delete p; + delete o; +} + +void RuleItem::reset() +{ + d->m_enabled = hasFlag(AlwaysEnabled) | hasFlag(StartEnabled); + d->m_value = typedValue(QVariant(), d->m_type); + p->resetValue(); + if (o) { + o->resetValue(); + } +} + +QString RuleItem::key() const +{ + return d->m_key; +} + +QString RuleItem::name() const +{ + return d->m_name; +} + +QString RuleItem::section() const +{ + return d->m_section; +} + +QString RuleItem::iconName() const +{ + return d->m_icon.name(); +} + +QIcon RuleItem::icon() const +{ + return d->m_icon; +} + +QString RuleItem::description() const +{ + return d->m_description; +} + +void RuleItem::setDescription(const QString& description) +{ + d->m_description = description; +} + +bool RuleItem::isEnabled() const +{ + return d->m_enabled; +} + +void RuleItem::setEnabled(bool enabled) +{ + d->m_enabled = enabled | hasFlag(AlwaysEnabled); +} + +bool RuleItem::hasFlag(uint flag) const +{ + return (d->m_flags & flag) == flag; +} + +void RuleItem::setFlags(uint flags, bool active) +{ + if (active) { + d->m_flags |= flags; + } else { + d->m_flags &= (AllFlags ^ flags); + } +} + +RuleItem::Type RuleItem::type() const +{ + return d->m_type; +} + +QVariant RuleItem::value() const +{ + if (d->m_type == Option) { + return o->value(); + } + return d->m_value; +} + +void RuleItem::setValue(QVariant value) +{ + if (d->m_type == Option) { + o->setValue(value); + } + d->m_value = typedValue(value, d->m_type); +} + +QVariant RuleItem::options() const +{ + if (!o) { + return QVariant(); + } + return QVariant::fromValue(o); +} + +void RuleItem::setOptionsData(const QList &data) +{ + if (!o) { + if (d->m_type != Option && d->m_type != FlagsOption) { + return; + } + o = new OptionsModel(); + } + o->updateModelData(data); + o->setValue(d->m_value); +} + +int RuleItem::policy() const +{ + return p->value(); +} + +void RuleItem::setPolicy(int policy) +{ + p->setValue(policy); +} + +RulePolicy::Type RuleItem::policyType() const +{ + return p->type(); +} + +QVariant RuleItem::policyModel() const +{ + return QVariant::fromValue(p); +} + +QString RuleItem::policyKey() const +{ + return p->policyKey(d->m_key); +} + +QVariant RuleItem::typedValue(const QVariant &value, const RuleItem::Type type) +{ + switch (type) { + case Undefined: + case Option: + return value; + case Boolean: + return value.toBool(); + case Integer: + case Percentage: + return value.toInt(); + case FlagsOption: + // HACK: Currently, the only user of this is "types" property + if (value.toInt() == -1) { //NET:AllTypesMask + return 0x3FF - 0x040; //All possible flags minus NET::Override (deprecated) + } + return value.toInt(); + case Coordinate: + if (value.toString().isEmpty()) { + return QStringLiteral("0,0"); + } + return value.toString(); + case String: + case Shortcut: + return value.toString(); + } + + return value; +} + +} //namespace + diff --git a/kcmkwin/kwinrules/kcm.h b/kcmkwin/kwinrules/rulesdialog.h rename from kcmkwin/kwinrules/kcm.h rename to kcmkwin/kwinrules/rulesdialog.h --- a/kcmkwin/kwinrules/kcm.h +++ b/kcmkwin/kwinrules/rulesdialog.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2004 Lubos Lunak + * Copyright (c) 2020 Ismael Asensio * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,35 +17,37 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#ifndef KWIN_RULESDIALOG_H +#define KWIN_RULESDIALOG_H -#ifndef __KCM_H__ -#define __KCM_H__ +#include "rulesmodel.h" +#include "../../rules.h" -#include -#include - -class KConfig; +#include namespace KWin { -class KCMRulesList; +class Rules; -class KCMRules - : public KCModule +class RulesDialog : public QDialog { Q_OBJECT + public: - KCMRules(QWidget *parent, const QVariantList &args); - void load() override; - void save() override; - QString quickHelp() const override; -protected Q_SLOTS: - void moduleChanged(bool state); + explicit RulesDialog(QWidget* parent = nullptr, const char* name = nullptr); + + Rules* edit(Rules* r, const QVariantMap& info, bool show_hints); + +protected: + void accept() override; + private: - KCMRulesList* widget; + RulesModel* m_rulesModel; + QWidget *m_quickWidget; + Rules* m_rules; }; } // namespace -#endif +#endif // KWIN_RULESDIALOG_H diff --git a/kcmkwin/kwinrules/rulesdialog.cpp b/kcmkwin/kwinrules/rulesdialog.cpp new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/rulesdialog.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2004 Lubos Lunak + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "rulesdialog.h" + +#include +#include +#include +#include +#include + +#include + + +namespace KWin +{ + +RulesDialog::RulesDialog(QWidget* parent, const char* name) + : QDialog(parent) + , m_rulesModel(new RulesModel(this)) +{ + setObjectName(name); + setModal(true); + setWindowTitle(i18n("Edit Window-Specific Settings")); + setWindowIcon(QIcon::fromTheme("preferences-system-windows-actions")); + setLayout(new QVBoxLayout); + + // Init RuleEditor QML QuickView + QQuickView *quickView = new QQuickView(); + quickView->setSource(QUrl::fromLocalFile(QStandardPaths::locate( + QStandardPaths::GenericDataLocation, + QStringLiteral("kpackage/kcms/kcm_kwinrules_qml/contents/ui/RulesEditor.qml")))); + quickView->setResizeMode(QQuickView::SizeRootObjectToView); + quickView->rootObject()->setProperty("rulesModel", QVariant::fromValue(m_rulesModel)); + + m_quickWidget = QWidget::createWindowContainer(quickView, this); + m_quickWidget->setMinimumSize(QSize(680, 700)); + layout()->addWidget(m_quickWidget); + + QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + connect(buttons, SIGNAL(accepted()), SLOT(accept())); + connect(buttons, SIGNAL(rejected()), SLOT(reject())); + layout()->addWidget(buttons); +} + +// window is set only for Alt+F3/Window-specific settings, because the dialog +// is then related to one specific window +Rules* RulesDialog::edit(Rules* r, const QVariantMap& info, bool show_hints) +{ + Q_UNUSED(show_hints); + + m_rules = r; + + m_rulesModel->importFromRules(m_rules); + if (!info.isEmpty()) { + m_rulesModel->prefillProperties(info); + } + + exec(); + + return m_rules; +} + +void RulesDialog::accept() +{ + m_rules = m_rulesModel->exportToRules(); + QDialog::accept(); +} + +} diff --git a/kcmkwin/kwinrules/ruleslist.h b/kcmkwin/kwinrules/ruleslist.h deleted file mode 100644 --- a/kcmkwin/kwinrules/ruleslist.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2004 Lubos Lunak - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - - -#ifndef __RULESLIST_H__ -#define __RULESLIST_H__ - -#include "ui_ruleslist.h" -#include "rulebooksettings.h" - -namespace KWin -{ -class Rules; - -class KCMRulesList - : public QWidget, Ui_KCMRulesList -{ - Q_OBJECT -public: - explicit KCMRulesList(QWidget* parent = nullptr); - ~KCMRulesList() override; - void load(); - void save(); -Q_SIGNALS: - void changed(bool); -private Q_SLOTS: - void newClicked(); - void modifyClicked(); - void deleteClicked(); - void moveupClicked(); - void movedownClicked(); - void exportClicked(); - void importClicked(); - void activeChanged(); -private: - QVector m_rules; - RuleBookSettings m_settings; -}; - -} // namespace - -#endif diff --git a/kcmkwin/kwinrules/ruleslist.cpp b/kcmkwin/kwinrules/ruleslist.cpp deleted file mode 100644 --- a/kcmkwin/kwinrules/ruleslist.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 2004 Lubos Lunak - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "ruleslist.h" - -#include -#include -#include - -#include "../../rules.h" -#include "rulesettings.h" -#include "ruleswidget.h" - -namespace KWin -{ - -KCMRulesList::KCMRulesList(QWidget* parent) - : QWidget(parent) -{ - setupUi(this); - // connect both current/selected, so that current==selected (stupid QListBox :( ) - connect(rules_listbox, SIGNAL(itemChanged(QListWidgetItem*)), - SLOT(activeChanged())); - connect(rules_listbox, SIGNAL(itemSelectionChanged()), - SLOT(activeChanged())); - connect(new_button, SIGNAL(clicked()), - SLOT(newClicked())); - connect(modify_button, SIGNAL(clicked()), - SLOT(modifyClicked())); - connect(delete_button, SIGNAL(clicked()), - SLOT(deleteClicked())); - connect(moveup_button, SIGNAL(clicked()), - SLOT(moveupClicked())); - connect(movedown_button, SIGNAL(clicked()), - SLOT(movedownClicked())); - connect(export_button, SIGNAL(clicked()), - SLOT(exportClicked())); - connect(import_button, SIGNAL(clicked()), - SLOT(importClicked())); - connect(rules_listbox, SIGNAL(itemDoubleClicked(QListWidgetItem*)), - SLOT(modifyClicked())); - load(); -} - -KCMRulesList::~KCMRulesList() -{ - qDeleteAll(m_rules); - m_rules.clear(); -} - -void KCMRulesList::activeChanged() -{ - QListWidgetItem *item = rules_listbox->currentItem(); - int itemRow = rules_listbox->row(item); - - if (item != nullptr) // make current==selected - rules_listbox->setCurrentItem(item, QItemSelectionModel::ClearAndSelect); - modify_button->setEnabled(item != nullptr); - delete_button->setEnabled(item != nullptr); - export_button->setEnabled(item != nullptr); - moveup_button->setEnabled(item != nullptr && itemRow > 0); - movedown_button->setEnabled(item != nullptr && itemRow < (rules_listbox->count() - 1)); -} - -void KCMRulesList::newClicked() -{ - RulesDialog dlg(this); - Rules* rule = dlg.edit(nullptr, {}, false); - if (rule == nullptr) - return; - int pos = rules_listbox->currentRow() + 1; - rules_listbox->insertItem(pos , rule->description); - rules_listbox->setCurrentRow(pos, QItemSelectionModel::ClearAndSelect); - m_rules.insert(m_rules.begin() + pos, rule); - emit changed(true); -} - -void KCMRulesList::modifyClicked() -{ - int pos = rules_listbox->currentRow(); - if (pos == -1) - return; - RulesDialog dlg(this); - Rules *rule = dlg.edit(m_rules[pos], {}, false); - if (rule == m_rules[pos]) - return; - delete m_rules[pos]; - m_rules[pos] = rule; - rules_listbox->item(pos)->setText(rule->description); - emit changed(true); -} - -void KCMRulesList::deleteClicked() -{ - int pos = rules_listbox->currentRow(); - Q_ASSERT(pos != -1); - delete rules_listbox->takeItem(pos); - m_rules.erase(m_rules.begin() + pos); - emit changed(true); -} - -void KCMRulesList::moveupClicked() -{ - int pos = rules_listbox->currentRow(); - Q_ASSERT(pos != -1); - if (pos > 0) { - QListWidgetItem * item = rules_listbox->takeItem(pos); - rules_listbox->insertItem(pos - 1 , item); - rules_listbox->setCurrentItem(item, QItemSelectionModel::ClearAndSelect); - Rules *rule = m_rules[pos]; - m_rules[pos] = m_rules[pos - 1]; - m_rules[pos - 1] = rule; - } - emit changed(true); -} - -void KCMRulesList::movedownClicked() -{ - int pos = rules_listbox->currentRow(); - Q_ASSERT(pos != -1); - if (pos < int(rules_listbox->count()) - 1) { - QListWidgetItem * item = rules_listbox->takeItem(pos); - rules_listbox->insertItem(pos + 1 , item); - rules_listbox->setCurrentItem(item, QItemSelectionModel::ClearAndSelect); - Rules *rule = m_rules[pos]; - m_rules[pos] = m_rules[pos + 1]; - m_rules[pos + 1] = rule; - } - emit changed(true); -} - -void KCMRulesList::exportClicked() -{ - int pos = rules_listbox->currentRow(); - Q_ASSERT(pos != -1); - QString path = QFileDialog::getSaveFileName(this, i18n("Export Rules"), QDir::home().absolutePath(), - i18n("KWin Rules (*.kwinrule)")); - if (path.isEmpty()) - return; - const auto cfg = KSharedConfig::openConfig(path, KConfig::SimpleConfig); - RuleSettings settings(cfg, m_rules[pos]->description); - settings.setDefaults(); - m_rules[pos]->write(&settings); - settings.save(); -} - -void KCMRulesList::importClicked() -{ - QString path = QFileDialog::getOpenFileName(this, i18n("Import Rules"), QDir::home().absolutePath(), - i18n("KWin Rules (*.kwinrule)")); - if (path.isEmpty()) - return; - const auto config = KSharedConfig::openConfig(path, KConfig::SimpleConfig); - QStringList groups = config->groupList(); - if (groups.isEmpty()) - return; - - int pos = qMax(0, rules_listbox->currentRow()); - for (const QString &group : groups) { - RuleSettings settings(config, group); - const bool remove = settings.deleteRule(); - Rules *new_rule = new Rules(&settings); - - // try to replace existing rule first - for (int i = 0; i < m_rules.count(); ++i) { - if (m_rules[i]->description == new_rule->description) { - delete m_rules[i]; - if (remove) { - m_rules.remove(i); - delete rules_listbox->takeItem(i); - delete new_rule; - pos = qMax(0, rules_listbox->currentRow()); // might have changed! - } else - m_rules[i] = new_rule; - new_rule = nullptr; - break; - } - } - - // don't add "to be deleted" if not present - if (remove) { - delete new_rule; - new_rule = nullptr; - } - - // plain insertion - if (new_rule) { - m_rules.insert(pos, new_rule); - rules_listbox->insertItem(pos++, new_rule->description); - } - } - emit changed(true); -} - -void KCMRulesList::load() -{ - rules_listbox->clear(); - m_settings.load(); - m_rules = m_settings.rules(); - for (const auto rule : qAsConst(m_rules)) { - rules_listbox->addItem(rule->description); - } - - if (m_rules.count() > 0) - rules_listbox->setCurrentItem(rules_listbox->item(0)); - else - rules_listbox->setCurrentItem(nullptr); - activeChanged(); -} - -void KCMRulesList::save() -{ - m_settings.setRules(m_rules); - m_settings.save(); -} - -} // namespace - diff --git a/kcmkwin/kwinrules/ruleslist.ui b/kcmkwin/kwinrules/ruleslist.ui deleted file mode 100644 --- a/kcmkwin/kwinrules/ruleslist.ui +++ /dev/null @@ -1,122 +0,0 @@ - - - KWin::KCMRulesList - - - - 0 - 0 - 600 - 480 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - &New... - - - - - - - &Modify... - - - - - - - Delete - - - - - - - - - - Move &Up - - - - - - - Move &Down - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 294 - - - - - - - - Qt::Horizontal - - - - - - - Qt::Horizontal - - - - - - - &Import - - - - - - - &Export - - - - - - - Qt::Horizontal - - - - - - - - diff --git a/kcmkwin/kwinrules/rulesmodel.h b/kcmkwin/kwinrules/rulesmodel.h new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/rulesmodel.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KWIN_RULES_MODEL_H +#define KWIN_RULES_MODEL_H + +#include "ruleitem.h" +#include "rulesettings.h" +#include + +#include +#include +#include + +#ifdef KWIN_BUILD_ACTIVITIES +#include +#endif + + +namespace KWin +{ + +class RulesFilterModel; + +class RulesModel : public QAbstractListModel +{ + Q_OBJECT + + Q_PROPERTY(QString description READ description NOTIFY descriptionChanged) + Q_PROPERTY(bool showWarning READ isWarningShown NOTIFY showWarningChanged) + Q_PROPERTY(RulesFilterModel *filter MEMBER m_filterModel CONSTANT) + +public: + enum RulesRole { + NameRole = Qt::DisplayRole, + DescriptionRole = Qt::ToolTipRole, + IconRole = Qt::DecorationRole, + IconNameRole = Qt::UserRole + 1, + KeyRole, + SectionRole, + EnabledRole, + SelectableRole, + ValueRole, + TypeRole, + PolicyRole, + PolicyModelRole, + OptionsModelRole + }; + +public: + explicit RulesModel(QObject *parent = nullptr); + ~RulesModel(); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QHash roleNames() const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex & index, const QVariant & value, int role) override; + + bool hasRule(const QString &key) const; + RuleItem *ruleItem(const QString &key) const; + + void readFromSettings(RuleSettings *settings); + void writeToSettings(RuleSettings *settings) const; + + void importFromRules(Rules *rules); + Rules *exportToRules() const; + + void prefillProperties(const QVariantMap &info); + + QString description() const; + bool isWarningShown() const; + +public slots: + void detectWindowProperties(int secs); + +signals: + void descriptionChanged(); + void showWarningChanged(); + +private: + void populateRuleList(); + RuleItem *addRule(RuleItem *rule); + QString defaultDescription() const; + + static const QHash x11PropertyHash(); + + QList windowTypesModelData() const; + QList virtualDesktopsModelData() const; + QList activitiesModelData() const; + QList placementModelData() const; + QList focusModelData() const; + QList colorSchemesModelData() const; + +private slots: + void selectX11Window(); + +private: + QList m_ruleList; + QHash m_rules; + RulesFilterModel *m_filterModel; +#ifdef KWIN_BUILD_ACTIVITIES + KActivities::Consumer *m_activities; +#endif +}; + + +class RulesFilterModel : public QSortFilterProxyModel +{ + Q_OBJECT + Q_PROPERTY(bool showAll READ showAll WRITE setShowAll NOTIFY showAllChanged) + Q_PROPERTY(QString searchText WRITE setSearchText) + +public: + explicit RulesFilterModel(QObject *parent) : QSortFilterProxyModel(parent) {}; + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; + + void setSearchText(const QString &text); + bool showAll() const; + void setShowAll(bool showAll); + +signals: + void showAllChanged(); + +private: + bool m_isSearching = false; + bool m_showAll = false; +}; + +} + +#endif diff --git a/kcmkwin/kwinrules/rulesmodel.cpp b/kcmkwin/kwinrules/rulesmodel.cpp new file mode 100644 --- /dev/null +++ b/kcmkwin/kwinrules/rulesmodel.cpp @@ -0,0 +1,847 @@ +/* + * Copyright (c) 2004 Lubos Lunak + * Copyright (c) 2020 Ismael Asensio + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "rulesmodel.h" +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace KWin +{ + +RulesModel::RulesModel(QObject *parent) + : QAbstractListModel(parent) + , m_filterModel(new RulesFilterModel(this)) +{ + qmlRegisterUncreatableType("org.kde.kcms.kwinrules", 1, 0, "RuleItem", + QStringLiteral("Do not create objects of type RuleItem")); + qmlRegisterUncreatableType("org.kde.kcms.kwinrules", 1, 0, "RulesFilterModel", + QStringLiteral("Do not create objects of type RulesFilterModel")); + + m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + m_filterModel->setSourceModel(this); + + populateRuleList(); +} + +RulesModel::~RulesModel() +{ +} + +QHash< int, QByteArray > RulesModel::roleNames() const +{ + return { + {KeyRole, QByteArrayLiteral("key")}, + {NameRole, QByteArrayLiteral("name")}, + {IconRole, QByteArrayLiteral("icon")}, + {IconNameRole, QByteArrayLiteral("iconName")}, + {SectionRole, QByteArrayLiteral("section")}, + {DescriptionRole, QByteArrayLiteral("description")}, + {EnabledRole, QByteArrayLiteral("enabled")}, + {SelectableRole, QByteArrayLiteral("selectable")}, + {ValueRole, QByteArrayLiteral("value")}, + {TypeRole, QByteArrayLiteral("type")}, + {PolicyRole, QByteArrayLiteral("policy")}, + {PolicyModelRole, QByteArrayLiteral("policyModel")}, + {OptionsModelRole, QByteArrayLiteral("options")}, + }; +} + +int RulesModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } + return m_ruleList.size(); +} + +QVariant RulesModel::data(const QModelIndex &index, int role) const +{ + if (!checkIndex(index, CheckIndexOption::IndexIsValid | CheckIndexOption::ParentIsInvalid)) { + return QVariant(); + } + + const RuleItem *rule = m_ruleList.at(index.row()); + + switch (role) { + case KeyRole: + return rule->key(); + case NameRole: + return rule->name(); + case IconRole: + return rule->icon(); + case IconNameRole: + return rule->iconName(); + case DescriptionRole: + return rule->description(); + case SectionRole: + return rule->section(); + case EnabledRole: + return rule->isEnabled(); + case SelectableRole: + return !rule->hasFlag(RuleItem::AlwaysEnabled); + case ValueRole: + return rule->value(); + case TypeRole: + return rule->type(); + case PolicyRole: + return rule->policy(); + case PolicyModelRole: + return rule->policyModel(); + case OptionsModelRole: + return rule->options(); + } + return QVariant(); +} + +bool RulesModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!checkIndex(index, CheckIndexOption::IndexIsValid | CheckIndexOption::ParentIsInvalid)) { + return false; + } + + RuleItem *rule = m_ruleList.at(index.row()); + + switch (role) { + case EnabledRole: + if (value.toBool() == rule->isEnabled()) { + return true; + } + rule->setEnabled(value.toBool()); + break; + case ValueRole: + if (value == rule->value()) { + return true; + } + rule->setValue(value); + break; + case PolicyRole: + if (value.toInt() == rule->policy()) { + return true; + } + rule->setPolicy(value.toInt()); + break; + default: + return false; + } + + emit dataChanged(index, index, QVector{role}); + + if (rule->hasFlag(RuleItem::AffectsDescription)) { + emit descriptionChanged(); + } + if (rule->hasFlag(RuleItem::AffectsWarning)) { + emit showWarningChanged(); + } + + return true; +} + +RuleItem *RulesModel::addRule(RuleItem *rule) +{ + m_ruleList << rule; + m_rules.insert(rule->key(), rule); + + return rule; +} + +bool RulesModel::hasRule(const QString& key) const +{ + return m_rules.contains(key); +} + + +RuleItem *RulesModel::ruleItem(const QString& key) const +{ + return m_rules.value(key); +} + +QString RulesModel::description() const +{ + const QString desc = m_rules["description"]->value().toString(); + if (!desc.isEmpty()) { + return desc; + } + return defaultDescription(); +} + +QString RulesModel::defaultDescription() const +{ + const QString wmclass = m_rules["wmclass"]->value().toString(); + const QString title = m_rules["title"]->isEnabled() ? m_rules["title"]->value().toString() : QString(); + + if (!title.isEmpty()) { + return i18n("Window settings for %1", title); + } + if (!wmclass.isEmpty()) { + return i18n("Settings for %1", wmclass); + } + + return i18n("New window settings"); +} + +bool RulesModel::isWarningShown() const +{ + const bool no_wmclass = !m_rules["wmclass"]->isEnabled() + || m_rules["wmclass"]->policy() == Rules::UnimportantMatch; + const bool alltypes = !m_rules["types"]->isEnabled() + || (m_rules["types"]->value() == 0) + || (m_rules["types"]->value() == NET::AllTypesMask) + || ((m_rules["types"]->value().toInt() | (1 << NET::Override)) == 0x3FF); + + return (no_wmclass && alltypes); +} + + +void RulesModel::readFromSettings(RuleSettings *settings) +{ + beginResetModel(); + + for (RuleItem *rule : qAsConst(m_ruleList)) { + const KConfigSkeletonItem *configItem = settings->findItem(rule->key()); + const KConfigSkeletonItem *configPolicyItem = settings->findItem(rule->policyKey()); + + if (!configItem + || (configPolicyItem && configPolicyItem->property() == Rules::Unused) + || (configItem->property().toString().isEmpty())) { + rule->reset(); + continue; + } + + rule->setEnabled(true); + + const QVariant value = configItem->property(); + rule->setValue(value); + + if (rule->policyType() != RulePolicy::NoPolicy) { + const int policy = configPolicyItem->property().toInt(); + rule->setPolicy(policy); + } + } + + endResetModel(); + + emit descriptionChanged(); + emit showWarningChanged(); +} + +void RulesModel::writeToSettings(RuleSettings *settings) const +{ + const QString description = m_rules["description"]->value().toString(); + if (description.isEmpty()) { + m_rules["description"]->setValue(defaultDescription()); + } + + for (const RuleItem *rule : qAsConst(m_ruleList)) { + KConfigSkeletonItem *configItem = settings->findItem(rule->key()); + KConfigSkeletonItem *configPolicyItem = settings->findItem(rule->policyKey()); + + Q_ASSERT (configItem); + + if (rule->isEnabled()) { + configItem->setProperty(rule->value()); + if (configPolicyItem) { + configPolicyItem->setProperty(rule->policy()); + } + } else { + if (configPolicyItem) { + configPolicyItem->setProperty(Rules::Unused); + } else { + // Rules without policy gets deactivated by an empty string + configItem->setProperty(QString()); + } + } + } +} + +void RulesModel::importFromRules(Rules* rules) +{ + QTemporaryFile tempFile; + if (!tempFile.open()) { + return; + } + const auto cfg = KSharedConfig::openConfig(tempFile.fileName(), KConfig::SimpleConfig); + RuleSettings *settings = new RuleSettings(cfg, QStringLiteral("tempSettings")); + + settings->setDefaults(); + if (rules) { + rules->write(settings); + } + readFromSettings(settings); + + delete(settings); +} + +Rules *RulesModel::exportToRules() const +{ + QTemporaryFile tempFile; + if (!tempFile.open()) { + return nullptr; + } + const auto cfg = KSharedConfig::openConfig(tempFile.fileName(), KConfig::SimpleConfig); + + RuleSettings *settings = new RuleSettings(cfg, QStringLiteral("tempSettings")); + + writeToSettings(settings); + Rules *rules = new Rules(settings); + + delete(settings); + return rules; +} + + +void RulesModel::populateRuleList() +{ + qDeleteAll(m_ruleList); + m_ruleList.clear(); + + //Rule description + addRule(new RuleItem(QLatin1String("description"), + RulePolicy::NoPolicy, RuleItem::String, + i18n("Description"), i18n("Window matching"), + QStringLiteral("entry-edit"))); + m_rules["description"]->setFlags(RuleItem::AlwaysEnabled | RuleItem::AffectsDescription); + + // Window matching + addRule(new RuleItem(QLatin1String("wmclass"), + RulePolicy::StringMatch, RuleItem::String, + i18n("Window class (application)"), i18n("Window matching"), + QStringLiteral("window"))); + m_rules["wmclass"]->setFlags(RuleItem::AlwaysEnabled | RuleItem::AffectsWarning | RuleItem::AffectsDescription); + + addRule(new RuleItem(QLatin1String("wmclasscomplete"), + RulePolicy::NoPolicy, RuleItem::Boolean, + i18n("Match whole window class"), i18n("Window matching"), + QStringLiteral("window"))); + m_rules["wmclasscomplete"]->setFlags(RuleItem::AlwaysEnabled); + + addRule(new RuleItem(QLatin1String("types"), + RulePolicy::NoPolicy, RuleItem::FlagsOption, + i18n("Window types"), i18n("Window matching"), + QStringLiteral("window-duplicate"), + windowTypesModelData())); + m_rules["types"]->setFlags(RuleItem::AlwaysEnabled | RuleItem::AffectsWarning ); + + addRule(new RuleItem(QLatin1String("windowrole"), + RulePolicy::NoPolicy, RuleItem::String, + i18n("Window role"), i18n("Window matching"), + QStringLiteral("dialog-object-properties"))); + + addRule(new RuleItem(QLatin1String("title"), + RulePolicy::StringMatch, RuleItem::String, + i18n("Window title"), i18n("Window matching"), + QStringLiteral("edit-comment"))); + m_rules["title"]->setFlags(RuleItem::AffectsDescription); + + addRule(new RuleItem(QLatin1String("clientmachine"), + RulePolicy::StringMatch, RuleItem::String, + i18n("Machine (hostname)"), i18n("Window matching"), + QStringLiteral("computer"))); + + // Size & Position + addRule(new RuleItem(QLatin1String("position"), + RulePolicy::SetRule, RuleItem::Coordinate, + i18n("Position"), i18n("Size & Position"), + QStringLiteral("transform-move"))); + + addRule(new RuleItem(QLatin1String("size"), + RulePolicy::SetRule, RuleItem::Coordinate, + i18n("Size"), i18n("Size & Position"), + QStringLiteral("image-resize-symbolic"))); + + addRule(new RuleItem(QLatin1String("maximizehoriz"), + RulePolicy::SetRule, RuleItem::Boolean, + i18n("Maximized horizontally"), i18n("Size & Position"), + QStringLiteral("resizecol"))); + + addRule(new RuleItem(QLatin1String("maximizevert"), + RulePolicy::SetRule, RuleItem::Boolean, + i18n("Maximized vertically"), i18n("Size & Position"), + QStringLiteral("resizerow"))); + + addRule(new RuleItem(QLatin1String("desktop"), + RulePolicy::SetRule, RuleItem::Option, + i18n("Virtual Desktop"), i18n("Size & Position"), + QStringLiteral("virtual-desktops"), + virtualDesktopsModelData())); + +#ifdef KWIN_BUILD_ACTIVITIES + m_activities = new KActivities::Consumer(this); + + addRule(new RuleItem(QLatin1String("activity"), + RulePolicy::SetRule, RuleItem::Option, + i18n("Activity"), i18n("Size & Position"), + QStringLiteral("activities"), + activitiesModelData())); + + // Activites consumer may update the available activities later + connect(m_activities, &KActivities::Consumer::activitiesChanged, + this, [this] { m_rules["activity"]->setOptionsData(activitiesModelData()); }); + connect(m_activities, &KActivities::Consumer::serviceStatusChanged, + this, [this] { m_rules["activity"]->setOptionsData(activitiesModelData()); }); + +#endif + + addRule(new RuleItem(QLatin1String("screen"), + RulePolicy::SetRule, RuleItem::Integer, + i18n("Screen"), i18n("Size & Position"), + QStringLiteral("osd-shutd-screen"))); + + addRule(new RuleItem(QLatin1String("fullscreen"), + RulePolicy::SetRule, RuleItem::Boolean, + i18n("Fullscreen"), i18n("Size & Position"), + QStringLiteral("view-fullscreen"))); + + addRule(new RuleItem(QLatin1String("minimize"), + RulePolicy::SetRule, RuleItem::Boolean, + i18n("Minimized"), i18n("Size & Position"), + QStringLiteral("window-minimize"))); + + addRule(new RuleItem(QLatin1String("shade"), + RulePolicy::SetRule, RuleItem::Boolean, + i18n("Shaded"), i18n("Size & Position"), + QStringLiteral("window-shade"))); + + addRule(new RuleItem(QLatin1String("placement"), + RulePolicy::ForceRule, RuleItem::Option, + i18n("Initial placement"), i18n("Size & Position"), + QStringLiteral("region"), + placementModelData())); + + addRule(new RuleItem(QLatin1String("ignoregeometry"), + RulePolicy::SetRule, RuleItem::Boolean, + i18n("Ignore requested geometry"), i18n("Size & Position"), + QStringLiteral("view-time-schedule-baselined-remove"))); + m_rules["ignoregeometry"]->setDescription(i18n("Windows can ask to appear in a certain position.\n" + "By default this overrides the placement strategy\n" + "what might be nasty if the client abuses the feature\n" + "to unconditionally popup in the middle of your screen.")); + + addRule(new RuleItem(QLatin1String("minsize"), + RulePolicy::ForceRule, RuleItem::Coordinate, + i18n("Minimum Size"), i18n("Size & Position"), + QStringLiteral("image-resize-symbolic"))); + + addRule(new RuleItem(QLatin1String("maxsize"), + RulePolicy::ForceRule, RuleItem::Coordinate, + i18n("Maximum Size"), i18n("Size & Position"), + QStringLiteral("image-resize-symbolic"))); + + addRule(new RuleItem(QLatin1String("strictgeometry"), + RulePolicy::ForceRule, RuleItem::Boolean, + i18n("Obey geometry restrictions"), i18n("Size & Position"), + QStringLiteral("transform-crop-and-resize"))); + m_rules["strictgeometry"]->setDescription(i18n("Eg. terminals or video players can ask to keep a certain aspect ratio\n" + "or only grow by values larger than one\n" + "(eg. by the dimensions of one character).\n" + "This may be pointless and the restriction prevents arbitrary dimensions\n" + "like your complete screen area.")); + + // Arrangement & Access + addRule(new RuleItem(QLatin1String("above"), + RulePolicy::SetRule, RuleItem::Boolean, + i18n("Keep above"), i18n("Arrangement & Access"), + QStringLiteral("window-keep-above"))); + + addRule(new RuleItem(QLatin1String("below"), + RulePolicy::SetRule, RuleItem::Boolean, + i18n("Keep below"), i18n("Arrangement & Access"), + QStringLiteral("window-keep-below"))); + + addRule(new RuleItem(QLatin1String("skiptaskbar"), + RulePolicy::SetRule, RuleItem::Boolean, + i18n("Skip taskbar"), i18n("Arrangement & Access"), + QStringLiteral("kt-show-statusbar"))); + m_rules["skiptaskbar"]->setDescription(i18n("Window shall (not) appear in the taskbar.")); + + addRule(new RuleItem(QLatin1String("skippager"), + RulePolicy::SetRule, RuleItem::Boolean, + i18n("Skip pager"), i18n("Arrangement & Access"), + QStringLiteral("org.kde.plasma.pager"))); + m_rules["skippager"]->setDescription(i18n("Window shall (not) appear in the manager for virtual desktops")); + + addRule(new RuleItem(QLatin1String("skipswitcher"), + RulePolicy::SetRule, RuleItem::Boolean, + i18n("Skip switcher"), i18n("Arrangement & Access"), + QStringLiteral("preferences-system-windows-effect-flipswitch"))); + m_rules["skipswitcher"]->setDescription(i18n("Window shall (not) appear in the Alt+Tab list")); + + addRule(new RuleItem(QLatin1String("shortcut"), + RulePolicy::SetRule, RuleItem::Shortcut, + i18n("Shortcut"), i18n("Arrangement & Access"), + QStringLiteral("configure-shortcuts"))); + + // Appearance & Fixes + addRule(new RuleItem(QLatin1String("noborder"), + RulePolicy::SetRule, RuleItem::Boolean, + i18n("No titlebar and frame"), i18n("Appearance & Fixes"), + QStringLiteral("dialog-cancel"))); + + addRule(new RuleItem(QLatin1String("decocolor"), + RulePolicy::ForceRule, RuleItem::Option, + i18n("Titlebar color scheme"), i18n("Appearance & Fixes"), + QStringLiteral("preferences-desktop-theme"), + colorSchemesModelData())); + + addRule(new RuleItem(QLatin1String("opacityactive"), + RulePolicy::ForceRule, RuleItem::Percentage, + i18n("Active opacity"), i18n("Appearance & Fixes"), + QStringLiteral("edit-opacity"))); + + addRule(new RuleItem(QLatin1String("opacityinactive"), + RulePolicy::ForceRule, RuleItem::Percentage, + i18n("Inactive opacity"), i18n("Appearance & Fixes"), + QStringLiteral("edit-opacity"))); + + addRule(new RuleItem(QLatin1String("fsplevel"), + RulePolicy::ForceRule, RuleItem::Option, + i18n("Focus stealing prevention"), i18n("Appearance & Fixes"), + QStringLiteral("preferences-system-windows-effect-glide"), + focusModelData())); + m_rules["fsplevel"]->setDescription(i18n("KWin tries to prevent windows from taking the focus\n" + "(\"activate\") while you're working in another window,\n" + "but this may sometimes fail or superact.\n" + "\"None\" will unconditionally allow this window to get the focus while\n" + "\"Extreme\" will completely prevent it from taking the focus.")); + + addRule(new RuleItem(QLatin1String("fpplevel"), + RulePolicy::ForceRule, RuleItem::Option, + i18n("Focus protection"), i18n("Appearance & Fixes"), + QStringLiteral("preferences-system-windows-effect-minimize"), + focusModelData())); + m_rules["fpplevel"]->setDescription(i18n("This controls the focus protection of the currently active window.\n" + "None will always give the focus away,\n" + "Extreme will keep it.\n" + "Otherwise it's interleaved with the stealing prevention\n" + "assigned to the window that wants the focus.")); + + addRule(new RuleItem(QLatin1String("acceptfocus"), + RulePolicy::ForceRule, RuleItem::Boolean, + i18n("Accept focus"), i18n("Appearance & Fixes"), + QStringLiteral("preferences-desktop-cursors"))); + m_rules["acceptfocus"]->setDescription(i18n("Windows may prevent to get the focus (activate) when being clicked.\n" + "On the other hand you might wish to prevent a window\n" + "from getting focused on a mouse click.")); + + addRule(new RuleItem(QLatin1String("disableglobalshortcuts"), + RulePolicy::ForceRule, RuleItem::Boolean, + i18n("Ignore global shortcuts"), i18n("Appearance & Fixes"), + QStringLiteral("input-keyboard-virtual-off"))); + m_rules["disableglobalshortcuts"]->setDescription(i18n("When used, a window will receive\n" + "all keyboard inputs while it is active, including Alt+Tab etc.\n" + "This is especially interesting for emulators or virtual machines.\n" + "\n" + "Be warned:\n" + "you won't be able to Alt+Tab out of the window\n" + "nor use any other global shortcut (such as Alt+F2 to show KRunner)\n" + "while it's active!")); + + addRule(new RuleItem(QLatin1String("closeable"), + RulePolicy::ForceRule, RuleItem::Boolean, + i18n("Closeable"), i18n("Appearance & Fixes"), + QStringLiteral("dialog-close"))); + + addRule(new RuleItem(QLatin1String("type"), + RulePolicy::ForceRule, RuleItem::Option, + i18n("Set window type"), i18n("Appearance & Fixes"), + QStringLiteral("window-duplicate"), + windowTypesModelData())); + + addRule(new RuleItem(QLatin1String("desktopfile"), + RulePolicy::SetRule, RuleItem::String, + i18n("Desktop file name"), i18n("Appearance & Fixes"), + QStringLiteral("application-x-desktop"))); + + addRule(new RuleItem(QLatin1String("blockcompositing"), + RulePolicy::ForceRule, RuleItem::Boolean, + i18n("Block compositing"), i18n("Appearance & Fixes"), + QStringLiteral("composite-track-on"))); +} + + +const QHash RulesModel::x11PropertyHash() +{ + static const auto propertyToRule = QHash { + /* The original detection dialog allows to choose depending on "Match complete window class": + * if Match Complete == false: wmclass = "resourceClass" + * if Match Complete == true: wmclass = "resourceName" + " " + "resourceClass" + */ + { "resourceName", "wmclass" }, + { "caption", "title" }, + { "role", "windowrole" }, + { "clientMachine", "clientmachine" }, + { "x11DesktopNumber", "desktop" }, + { "maximizeHorizontal", "maximizehoriz" }, + { "maximizeVertical", "maximizevert" }, + { "minimized", "minimize" }, + { "shaded", "shade" }, + { "fullscreen", "fullscreen" }, + { "keepAbove", "above" }, + { "keepBelow", "below" }, + { "noBorder", "noborder" }, + { "skipTaskbar", "skiptaskbar" }, + { "skipPager", "skippager" }, + { "skipSwitcher", "skipswitcher" }, + { "type", "type" }, + { "desktopFile", "desktopfile" } + }; + return propertyToRule; +}; + +void RulesModel::prefillProperties(const QVariantMap &info) +{ + beginResetModel(); + + // Properties that cannot be directly applied via x11PropertyHash + const QString position = QStringLiteral("%1,%2").arg(info.value("x").toInt()) + .arg(info.value("y").toInt()); + const QString size = QStringLiteral("%1,%2").arg(info.value("width").toInt()) + .arg(info.value("height").toInt()); + + if (!m_rules["position"]->isEnabled()) { + m_rules["position"]->setValue(position); + } + if (!m_rules["size"]->isEnabled()) { + m_rules["size"]->setValue(size); + } + if (!m_rules["minsize"]->isEnabled()) { + m_rules["minsize"]->setValue(size); + } + if (!m_rules["maxsize"]->isEnabled()) { + m_rules["maxsize"]->setValue(size); + } + + NET::WindowType window_type = static_cast(info.value("type", 0).toInt()); + if (!m_rules["types"]->isEnabled() || m_rules["types"]->value() == 0) { + if (window_type == NET::Unknown) { + window_type = NET::Normal; + } + m_rules["types"]->setValue(1 << window_type); + } + + const auto ruleForProperty = x11PropertyHash(); + for (QString &property : info.keys()) { + if (!ruleForProperty.contains(property)) { + continue; + } + const QString ruleKey = ruleForProperty.value(property, QString()); + Q_ASSERT(hasRule(ruleKey)); + + // Only prefill disabled or empty properties + if (!m_rules[ruleKey]->isEnabled() || m_rules[ruleKey]->value().toString().isEmpty()) { + m_rules[ruleKey]->setValue(info.value(property)); + } + } + + endResetModel(); + + emit descriptionChanged(); + emit showWarningChanged(); +} + + +QList RulesModel::windowTypesModelData() const +{ + static const auto modelData = QList { + //TODO: Find/create better icons + { NET::Normal, i18n("Normal Window") , QIcon::fromTheme("window") }, + { NET::Dialog, i18n("Dialog Window") , QIcon::fromTheme("window-duplicate") }, + { NET::Utility, i18n("Utility Window") , QIcon::fromTheme("dialog-object-properties") }, + { NET::Dock, i18n("Dock (panel)") , QIcon::fromTheme("list-remove") }, + { NET::Toolbar, i18n("Toolbar") , QIcon::fromTheme("tools") }, + { NET::Menu, i18n("Torn-Off Menu") , QIcon::fromTheme("overflow-menu-left") }, + { NET::Splash, i18n("Splash Screen") , QIcon::fromTheme("embosstool") }, + { NET::Desktop, i18n("Desktop") , QIcon::fromTheme("desktop") }, + // { NET::Override, i18n("Unmanaged Window") }, deprecated + { NET::TopMenu, i18n("Standalone Menubar"), QIcon::fromTheme("open-menu-symbolic") } + }; + return modelData; +} + +QList RulesModel::virtualDesktopsModelData() const +{ + QList modelData; + for (int desktopId = 1; desktopId <= KWindowSystem::numberOfDesktops(); ++desktopId) { + modelData << OptionsModel::Data{ + desktopId, + QString::number(desktopId).rightJustified(2) + QStringLiteral(": ") + KWindowSystem::desktopName(desktopId), + QIcon::fromTheme("virtual-desktops") + }; + } + modelData << OptionsModel::Data{ NET::OnAllDesktops, i18n("All Desktops"), QIcon::fromTheme("window-pin") }; + return modelData; +} + + +QList RulesModel::activitiesModelData() const +{ +#ifdef KWIN_BUILD_ACTIVITIES + QList modelData; + + // NULL_ID from kactivities/src/lib/core/consumer.cpp + modelData << OptionsModel::Data{ + QString::fromLatin1("00000000-0000-0000-0000-000000000000"), + i18n("All Activities"), + QIcon::fromTheme("activities") + }; + + const auto activities = m_activities->activities(KActivities::Info::Running); + if (m_activities->serviceStatus() == KActivities::Consumer::Running) { + for (const QString &activityId : activities) { + const KActivities::Info info(activityId); + modelData << OptionsModel::Data{ activityId, info.name(), QIcon::fromTheme(info.icon()) }; + } + } + + return modelData; +#else + return {}; +#endif +} + +QList RulesModel::placementModelData() const +{ + // From "placement.h" : Placement rule is stored as a string, not the enum value + static const auto modelData = QList { + { Placement::policyToString(Placement::Default), i18n("Default") }, + { Placement::policyToString(Placement::NoPlacement), i18n("No Placement") }, + { Placement::policyToString(Placement::Smart), i18n("Minimal Overlapping") }, + { Placement::policyToString(Placement::Maximizing), i18n("Maximized") }, + { Placement::policyToString(Placement::Cascade), i18n("Cascaded") }, + { Placement::policyToString(Placement::Centered), i18n("Centered") }, + { Placement::policyToString(Placement::Random), i18n("Random") }, + { Placement::policyToString(Placement::ZeroCornered), i18n("In Top-Left Corner") }, + { Placement::policyToString(Placement::UnderMouse), i18n("Under Mouse") }, + { Placement::policyToString(Placement::OnMainWindow), i18n("On Main Window") } + }; + return modelData; +} + +QList RulesModel::focusModelData() const +{ + static const auto modelData = QList { + { 0, i18n("None") }, + { 1, i18n("Low") }, + { 2, i18n("Normal") }, + { 3, i18n("High") }, + { 4, i18n("Extreme") } + }; + return modelData; +} + +QList RulesModel::colorSchemesModelData() const +{ + QList modelData; + + KColorSchemeManager schemes; + QAbstractItemModel *schemesModel = schemes.model(); + + // Skip row 0, which is Default scheme + for (int r = 1; r < schemesModel->rowCount(); r++) { + const QModelIndex index = schemesModel->index(r, 0); + modelData << OptionsModel::Data{ + QFileInfo(index.data(Qt::UserRole).toString()).baseName(), + index.data(Qt::DisplayRole).toString(), + index.data(Qt::DecorationRole).value() + }; + } + + return modelData; +} + + +bool RulesFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +{ + if (m_isSearching) { + return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); + } + if (m_showAll) { + return true; + } + + return sourceModel()->index(source_row, 0).data(RulesModel::EnabledRole).toBool(); +} + +void RulesFilterModel::setSearchText(const QString &text) +{ + const QString searchText = text.trimmed(); + m_isSearching = !searchText.isEmpty(); + setFilterFixedString(searchText); +} + +bool RulesFilterModel::showAll() const +{ + return m_showAll; +} + +void RulesFilterModel::setShowAll(bool showAll) +{ + if (m_showAll == showAll) { + return; + } + + m_showAll = showAll; + invalidateFilter(); + emit showAllChanged(); +} + + +void RulesModel::detectWindowProperties(int secs) +{ + QTimer::singleShot(secs*1000, this, &RulesModel::selectX11Window); +} + +void RulesModel::selectX11Window() +{ + QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KWin"), + QStringLiteral("/KWin"), + QStringLiteral("org.kde.KWin"), + QStringLiteral("queryWindowInfo")); + + QDBusPendingReply async = QDBusConnection::sessionBus().asyncCall(message); + + QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(async, this); + connect(callWatcher, &QDBusPendingCallWatcher::finished, this, + [this](QDBusPendingCallWatcher *self) { + QDBusPendingReply reply = *self; + self->deleteLater(); + if (!reply.isValid()) { + return; + } + const QVariantMap windowInfo = reply.value(); + //TODO: Improve UI to suggest/select the detected properties. + // For now, just prefill unused rules + prefillProperties(windowInfo); + } + ); +} + +} //namespace diff --git a/kcmkwin/kwinrules/ruleswidget.h b/kcmkwin/kwinrules/ruleswidget.h deleted file mode 100644 --- a/kcmkwin/kwinrules/ruleswidget.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2004 Lubos Lunak - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - - -#ifndef __RULESWIDGET_H__ -#define __RULESWIDGET_H__ - -#include - -#include -#include - -#include "ui_ruleswidgetbase.h" -#include "ui_editshortcut.h" - -#ifdef KWIN_BUILD_ACTIVITIES -namespace KActivities { - class Consumer; -} // namespace KActivities -#endif - -namespace KWin -{ - -class Rules; -class DetectDialog; - -class RulesWidget - : public QWidget, public Ui::RulesWidgetBase -{ - Q_OBJECT -public: - explicit RulesWidget(QWidget* parent = nullptr); - void setRules(Rules* r); - Rules* rules() const; - bool finalCheck(); - void prepareWindowSpecific(const QVariantMap &info); -Q_SIGNALS: - void changed(bool state); -protected Q_SLOTS: - void detectClicked(); - void wmclassMatchChanged(); - void roleMatchChanged(); - void titleMatchChanged(); - void machineMatchChanged(); - void shortcutEditClicked(); -private Q_SLOTS: - // geometry tab - void updateEnableposition(); - void updateEnablesize(); - void updateEnabledesktop(); - void updateEnablescreen(); -#ifdef KWIN_BUILD_ACTIVITIES - void updateEnableactivity(); -#endif - void updateEnablemaximizehoriz(); - void updateEnablemaximizevert(); - void updateEnableminimize(); - void updateEnableshade(); - void updateEnablefullscreen(); - void updateEnableplacement(); - // preferences tab - void updateEnableabove(); - void updateEnablebelow(); - void updateEnablenoborder(); - void updateEnabledecocolor(); - void updateEnableskiptaskbar(); - void updateEnableskippager(); - void updateEnableskipswitcher(); - void updateEnableacceptfocus(); - void updateEnablecloseable(); - void updateEnableautogroup(); - void updateEnableautogroupfg(); - void updateEnableautogroupid(); - void updateEnableopacityactive(); - void updateEnableopacityinactive(); - // workarounds tab - void updateEnablefsplevel(); - void updateEnablefpplevel(); - void updateEnabletype(); - void updateEnableignoregeometry(); - void updateEnableminsize(); - void updateEnablemaxsize(); - void updateEnablestrictgeometry(); - void updateEnableshortcut(); - void updateEnabledisableglobalshortcuts(); - void updateEnableblockcompositing(); - void updateEnabledesktopfile(); - // internal - void detected(bool); -private: - int desktopToCombo(int d) const; - int comboToDesktop(int val) const; -#ifdef KWIN_BUILD_ACTIVITIES - int activityToCombo(const QString &d) const; - QString comboToActivity(int val) const; - void updateActivitiesList(); - KActivities::Consumer *m_activities; - QString m_selectedActivityId; // we need this for async activity loading -#endif - int comboToTiling(int val) const; - int inc(int i) const { return i+1; } - int dec(int i) const { return i-1; } - void prefillUnusedValues(const QVariantMap& info); - DetectDialog* detect_dlg; - bool detect_dlg_ok; -}; - -class RulesDialog - : public QDialog -{ - Q_OBJECT -public: - explicit RulesDialog(QWidget* parent = nullptr, const char* name = nullptr); - Rules* edit(Rules* r, const QVariantMap& info, bool show_hints); -protected: - void accept() override; -private Q_SLOTS: - void displayHints(); -private: - RulesWidget* widget; - Rules* rules; -}; - -class EditShortcut - : public QWidget, public Ui_EditShortcut -{ - Q_OBJECT -public: - explicit EditShortcut(QWidget* parent = nullptr); -protected Q_SLOTS: - void editShortcut(); - void clearShortcut(); -}; - -class EditShortcutDialog - : public QDialog -{ - Q_OBJECT -public: - explicit EditShortcutDialog(QWidget* parent = nullptr, const char* name = nullptr); - void setShortcut(const QString& cut); - QString shortcut() const; -private: - EditShortcut* widget; -}; - -// slightly duped from utils.cpp -class ShortcutDialog - : public QDialog -{ - Q_OBJECT -public: - explicit ShortcutDialog(const QKeySequence& cut, QWidget* parent = nullptr); - void accept() override; - QKeySequence shortcut() const; -private: - KKeySequenceWidget* widget; -}; - -} // namespace - -#endif diff --git a/kcmkwin/kwinrules/ruleswidget.cpp b/kcmkwin/kwinrules/ruleswidget.cpp deleted file mode 100644 --- a/kcmkwin/kwinrules/ruleswidget.cpp +++ /dev/null @@ -1,970 +0,0 @@ -/* - * Copyright (c) 2004 Lubos Lunak - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "ruleswidget.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef KWIN_BUILD_ACTIVITIES -#include -#endif - -#include -#include -#include - -#include "../../rules.h" - -#include "detectwidget.h" - -Q_DECLARE_METATYPE(NET::WindowType) - -namespace KWin -{ - -#define SETUP( var, type ) \ - connect( enable_##var, SIGNAL(toggled(bool)), rule_##var, SLOT(setEnabled(bool))); \ - connect( enable_##var, SIGNAL(toggled(bool)), this, SLOT(updateEnable##var())); \ - connect( rule_##var, SIGNAL(activated(int)), this, SLOT(updateEnable##var())); \ - enable_##var->setWhatsThis( enableDesc ); \ - rule_##var->setWhatsThis( type##RuleDesc ); - -RulesWidget::RulesWidget(QWidget* parent) - : detect_dlg(nullptr) -{ - Q_UNUSED(parent); - setupUi(this); - QRegularExpressionValidator* validator = new QRegularExpressionValidator(QRegularExpression("[0-9\\-+,xX:]*"), this); - maxsize->setValidator(validator); - minsize->setValidator(validator); - position->setValidator(validator); - Ui::RulesWidgetBase::size->setValidator(validator); - - QString enableDesc = - i18n("Enable this checkbox to alter this window property for the specified window(s)."); - QString setRuleDesc = - i18n("Specify how the window property should be affected:
    " - "
  • Do Not Affect: The window property will not be affected and therefore" - " the default handling for it will be used. Specifying this will block more generic" - " window settings from taking effect.
  • " - "
  • Apply Initially: The window property will be only set to the given value" - " after the window is created. No further changes will be affected.
  • " - "
  • Remember: The value of the window property will be remembered and every" - " time the window is created, the last remembered value will be applied.
  • " - "
  • Force: The window property will be always forced to the given value.
  • " - "
  • Apply Now: The window property will be set to the given value immediately" - " and will not be affected later (this action will be deleted afterwards).
  • " - "
  • Force temporarily: The window property will be forced to the given value" - " until it is hidden (this action will be deleted after the window is hidden).
  • " - "
"); - QString forceRuleDesc = - i18n("Specify how the window property should be affected:
    " - "
  • Do Not Affect: The window property will not be affected and therefore" - " the default handling for it will be used. Specifying this will block more generic" - " window settings from taking effect.
  • " - "
  • Force: The window property will be always forced to the given value.
  • " - "
  • Force temporarily: The window property will be forced to the given value" - " until it is hidden (this action will be deleted after the window is hidden).
  • " - "
"); - // window tabs have enable signals done in designer - // geometry tab - SETUP(position, set); - SETUP(size, set); - SETUP(desktop, set); - SETUP(screen, set); -#ifdef KWIN_BUILD_ACTIVITIES - SETUP(activity, set); -#endif - SETUP(maximizehoriz, set); - SETUP(maximizevert, set); - SETUP(minimize, set); - SETUP(shade, set); - SETUP(fullscreen, set); - SETUP(placement, force); - // preferences tab - SETUP(above, set); - SETUP(below, set); - SETUP(noborder, set); - SETUP(decocolor, force); - SETUP(skiptaskbar, set); - SETUP(skippager, set); - SETUP(skipswitcher, set); - SETUP(acceptfocus, force); - SETUP(closeable, force); - SETUP(autogroup, force); - SETUP(autogroupfg, force); - SETUP(autogroupid, force); - SETUP(opacityactive, force); - SETUP(opacityinactive, force); - SETUP(shortcut, force); - // workarounds tab - SETUP(fsplevel, force); - SETUP(fpplevel, force); - SETUP(type, force); - SETUP(desktopfile, set); - SETUP(ignoregeometry, set); - SETUP(minsize, force); - SETUP(maxsize, force); - SETUP(strictgeometry, force); - SETUP(disableglobalshortcuts, force); - SETUP(blockcompositing, force); - - connect (shortcut_edit, SIGNAL(clicked()), SLOT(shortcutEditClicked())); - - edit_reg_wmclass->hide(); - edit_reg_role->hide(); - edit_reg_title->hide(); - edit_reg_machine->hide(); - -#ifndef KWIN_BUILD_ACTIVITIES - rule_activity->hide(); - enable_activity->hide(); - activity->hide(); -#endif - int i; - for (i = 1; - i <= KWindowSystem::numberOfDesktops(); - ++i) - desktop->addItem(QString::number(i).rightJustified(2) + ':' + KWindowSystem::desktopName(i)); - desktop->addItem(i18n("All Desktops")); - -#ifdef KWIN_BUILD_ACTIVITIES - m_activities = new KActivities::Consumer(this); - connect(m_activities, &KActivities::Consumer::activitiesChanged, - this, [this] { updateActivitiesList(); }); - connect(m_activities, &KActivities::Consumer::serviceStatusChanged, - this, [this] { updateActivitiesList(); }); - updateActivitiesList(); -#endif - - KColorSchemeManager *schemes = new KColorSchemeManager(this); - decocolor->setModel(schemes->model()); - - // hide autogrouping as it's currently not supported - // BUG 370301 - line_11->hide(); - enable_autogroup->hide(); - autogroup->hide(); - rule_autogroup->hide(); - enable_autogroupid->hide(); - autogroupid->hide(); - rule_autogroupid->hide(); - enable_autogroupfg->hide(); - autogroupfg->hide(); - rule_autogroupfg->hide(); -} - -#undef SETUP - -#define UPDATE_ENABLE_SLOT(var) \ - void RulesWidget::updateEnable##var() \ - { \ - /* leave the label readable label_##var->setEnabled( enable_##var->isChecked() && rule_##var->currentIndex() != 0 );*/ \ - Ui::RulesWidgetBase::var->setEnabled( enable_##var->isChecked() && rule_##var->currentIndex() != 0 ); \ - } - -// geometry tab -UPDATE_ENABLE_SLOT(position) -UPDATE_ENABLE_SLOT(size) -UPDATE_ENABLE_SLOT(desktop) -UPDATE_ENABLE_SLOT(screen) -#ifdef KWIN_BUILD_ACTIVITIES -UPDATE_ENABLE_SLOT(activity) -#endif -UPDATE_ENABLE_SLOT(maximizehoriz) -UPDATE_ENABLE_SLOT(maximizevert) -UPDATE_ENABLE_SLOT(minimize) -UPDATE_ENABLE_SLOT(shade) -UPDATE_ENABLE_SLOT(fullscreen) -UPDATE_ENABLE_SLOT(placement) -// preferences tab -UPDATE_ENABLE_SLOT(above) -UPDATE_ENABLE_SLOT(below) -UPDATE_ENABLE_SLOT(noborder) -UPDATE_ENABLE_SLOT(decocolor) -UPDATE_ENABLE_SLOT(skiptaskbar) -UPDATE_ENABLE_SLOT(skippager) -UPDATE_ENABLE_SLOT(skipswitcher) -UPDATE_ENABLE_SLOT(acceptfocus) -UPDATE_ENABLE_SLOT(closeable) -UPDATE_ENABLE_SLOT(autogroup) -UPDATE_ENABLE_SLOT(autogroupfg) -UPDATE_ENABLE_SLOT(autogroupid) -UPDATE_ENABLE_SLOT(opacityactive) -UPDATE_ENABLE_SLOT(opacityinactive) -void RulesWidget::updateEnableshortcut() -{ - shortcut->setEnabled(enable_shortcut->isChecked() && rule_shortcut->currentIndex() != 0); - shortcut_edit->setEnabled(enable_shortcut->isChecked() && rule_shortcut->currentIndex() != 0); -} -// workarounds tab -UPDATE_ENABLE_SLOT(fsplevel) -UPDATE_ENABLE_SLOT(fpplevel) -UPDATE_ENABLE_SLOT(type) -UPDATE_ENABLE_SLOT(ignoregeometry) -UPDATE_ENABLE_SLOT(minsize) -UPDATE_ENABLE_SLOT(maxsize) -UPDATE_ENABLE_SLOT(strictgeometry) -UPDATE_ENABLE_SLOT(disableglobalshortcuts) -UPDATE_ENABLE_SLOT(blockcompositing) -UPDATE_ENABLE_SLOT(desktopfile) - -#undef UPDATE_ENABLE_SLOT - -static const int set_rule_to_combo[] = { - 0, // Unused - 0, // Don't Affect - 3, // Force - 1, // Apply - 2, // Remember - 4, // ApplyNow - 5 // ForceTemporarily -}; - -static const Rules::SetRule combo_to_set_rule[] = { - (Rules::SetRule)Rules::DontAffect, - (Rules::SetRule)Rules::Apply, - (Rules::SetRule)Rules::Remember, - (Rules::SetRule)Rules::Force, - (Rules::SetRule)Rules::ApplyNow, - (Rules::SetRule)Rules::ForceTemporarily -}; - -static const int force_rule_to_combo[] = { - 0, // Unused - 0, // Don't Affect - 1, // Force - 0, // Apply - 0, // Remember - 0, // ApplyNow - 2 // ForceTemporarily -}; - -static const Rules::ForceRule combo_to_force_rule[] = { - (Rules::ForceRule)Rules::DontAffect, - (Rules::ForceRule)Rules::Force, - (Rules::ForceRule)Rules::ForceTemporarily -}; - -static QString positionToStr(const QPoint& p) -{ - if (p == invalidPoint) - return QString(); - return QString::number(p.x()) + ',' + QString::number(p.y()); -} - -static QPoint strToPosition(const QString& str) -{ - // two numbers, with + or -, separated by any of , x X : - QRegExp reg("\\s*([+-]?[0-9]*)\\s*[,xX:]\\s*([+-]?[0-9]*)\\s*"); - if (!reg.exactMatch(str)) - return invalidPoint; - return QPoint(reg.cap(1).toInt(), reg.cap(2).toInt()); -} - -static QString sizeToStr(const QSize& s) -{ - if (!s.isValid()) - return QString(); - return QString::number(s.width()) + ',' + QString::number(s.height()); -} - -static QSize strToSize(const QString& str) -{ - // two numbers, with + or -, separated by any of , x X : - QRegExp reg("\\s*([+-]?[0-9]*)\\s*[,xX:]\\s*([+-]?[0-9]*)\\s*"); - if (!reg.exactMatch(str)) - return QSize(); - return QSize(reg.cap(1).toInt(), reg.cap(2).toInt()); -} - -int RulesWidget::desktopToCombo(int d) const -{ - if (d >= 1 && d < desktop->count()) - return d - 1; - return desktop->count() - 1; // on all desktops -} - -int RulesWidget::comboToDesktop(int val) const -{ - if (val == desktop->count() - 1) - return NET::OnAllDesktops; - return val + 1; -} - -#ifdef KWIN_BUILD_ACTIVITIES -int RulesWidget::activityToCombo(const QString &d) const -{ - // TODO: ivan - do a multiselection list - for (int i = 0; i < activity->count(); i++) { - if (activity->itemData(i).toString() == d) { - return i; - } - } - - return activity->count() - 1; // on all activities -} - -QString RulesWidget::comboToActivity(int val) const -{ - // TODO: ivan - do a multiselection list - if (val < 0 || val >= activity->count()) - return QString(); - - return activity->itemData(val).toString(); -} - -void RulesWidget::updateActivitiesList() -{ - activity->clear(); - - // cloned from kactivities/src/lib/core/consumer.cpp - #define NULL_UUID "00000000-0000-0000-0000-000000000000" - activity->addItem(i18n("All Activities"), QString::fromLatin1(NULL_UUID)); - #undef NULL_UUID - - if (m_activities->serviceStatus() == KActivities::Consumer::Running) { - foreach (const QString & activityId, m_activities->activities(KActivities::Info::Running)) { - const KActivities::Info info(activityId); - activity->addItem(info.name(), activityId); - } - } - - auto rules = this->rules(); - if (rules->activityrule == Rules::UnusedSetRule) { - enable_activity->setChecked(false); - Ui::RulesWidgetBase::activity->setCurrentIndex(0); - } else { - enable_activity->setChecked(true); - Ui::RulesWidgetBase::activity->setCurrentIndex(activityToCombo(m_selectedActivityId)); - } - updateEnableactivity(); -} -#endif - -static int placementToCombo(Placement::Policy placement) -{ - static const int conv[] = { - 1, // NoPlacement - 0, // Default - 0, // Unknown - 6, // Random - 2, // Smart - 4, // Cascade - 5, // Centered - 7, // ZeroCornered - 8, // UnderMouse - 9, // OnMainWindow - 3 // Maximizing - }; - return conv[ placement ]; -} - -static Placement::Policy comboToPlacement(int val) -{ - static const Placement::Policy conv[] = { - Placement::Default, - Placement::NoPlacement, - Placement::Smart, - Placement::Maximizing, - Placement::Cascade, - Placement::Centered, - Placement::Random, - Placement::ZeroCornered, - Placement::UnderMouse, - Placement::OnMainWindow - // no Placement::Unknown - }; - return conv[ val ]; -} - -static int typeToCombo(NET::WindowType type) -{ - if (type < NET::Normal || type > NET::Splash || - type == NET::Override) // The user must NOT set a window to be unmanaged. - // This case is not handled in KWin and will lead to segfaults. - // Even iff it was supported, it would mean to allow the user to shoot himself - // since an unmanaged window has to manage itself, what is probably not the case when the hint is not set. - // Rule opportunity might be a relict from the Motif Hint window times of KDE1 - return 0; // Normal - static const int conv[] = { - 0, // Normal - 7, // Desktop - 3, // Dock - 4, // Toolbar - 5, // Menu - 1, // Dialog - 8, // Override - ignored. - 9, // TopMenu - 2, // Utility - 6 // Splash - }; - return conv[ type ]; -} - -static NET::WindowType comboToType(int val) -{ - static const NET::WindowType conv[] = { - NET::Normal, - NET::Dialog, - NET::Utility, - NET::Dock, - NET::Toolbar, - NET::Menu, - NET::Splash, - NET::Desktop, - NET::TopMenu - }; - return conv[ val ]; -} - -#define GENERIC_RULE( var, func, Type, type, uimethod, uimethod0 ) \ - if ( rules->var##rule == Rules::Unused##Type##Rule ) \ - { \ - enable_##var->setChecked( false ); \ - rule_##var->setCurrentIndex( 0 ); \ - Ui::RulesWidgetBase::var->uimethod0; \ - updateEnable##var(); \ - } \ - else \ - { \ - enable_##var->setChecked( true ); \ - rule_##var->setCurrentIndex( type##_rule_to_combo[ rules->var##rule ] ); \ - Ui::RulesWidgetBase::var->uimethod( func( rules->var )); \ - updateEnable##var(); \ - } - -#define CHECKBOX_SET_RULE( var, func ) GENERIC_RULE( var, func, Set, set, setChecked, setChecked( false )) -#define LINEEDIT_SET_RULE( var, func ) GENERIC_RULE( var, func, Set, set, setText, setText( QString() )) -#define COMBOBOX_SET_RULE( var, func ) GENERIC_RULE( var, func, Set, set, setCurrentIndex, setCurrentIndex( 0 )) -#define SPINBOX_SET_RULE( var, func ) GENERIC_RULE( var, func, Set, set, setValue, setValue(0)) -#define CHECKBOX_FORCE_RULE( var, func ) GENERIC_RULE( var, func, Force, force, setChecked, setChecked( false )) -#define LINEEDIT_FORCE_RULE( var, func ) GENERIC_RULE( var, func, Force, force, setText, setText( QString() )) -#define COMBOBOX_FORCE_RULE( var, func ) GENERIC_RULE( var, func, Force, force, setCurrentIndex, setCurrentIndex( 0 )) -#define SPINBOX_FORCE_RULE( var, func ) GENERIC_RULE( var, func, Force, force, setValue, setValue(0)) - -void RulesWidget::setRules(Rules* rules) -{ - Rules tmp; - if (rules == nullptr) - rules = &tmp; // empty - description->setText(rules->description); - wmclass->setText(rules->wmclass); - whole_wmclass->setChecked(rules->wmclasscomplete); - wmclass_match->setCurrentIndex(rules->wmclassmatch); - wmclassMatchChanged(); - role->setText(rules->windowrole); - role_match->setCurrentIndex(rules->windowrolematch); - roleMatchChanged(); - types->item(0)->setSelected(rules->types & NET::NormalMask); - types->item(1)->setSelected(rules->types & NET::DialogMask); - types->item(2)->setSelected(rules->types & NET::UtilityMask); - types->item(3)->setSelected(rules->types & NET::DockMask); - types->item(4)->setSelected(rules->types & NET::ToolbarMask); - types->item(5)->setSelected(rules->types & NET::MenuMask); - types->item(6)->setSelected(rules->types & NET::SplashMask); - types->item(7)->setSelected(rules->types & NET::DesktopMask); - types->item(8)->setSelected(rules->types & NET::OverrideMask); - types->item(9)->setSelected(rules->types & NET::TopMenuMask); - title->setText(rules->title); - title_match->setCurrentIndex(rules->titlematch); - titleMatchChanged(); - machine->setText(rules->clientmachine); - machine_match->setCurrentIndex(rules->clientmachinematch); - machineMatchChanged(); - LINEEDIT_SET_RULE(position, positionToStr); - LINEEDIT_SET_RULE(size, sizeToStr); - COMBOBOX_SET_RULE(desktop, desktopToCombo); - SPINBOX_SET_RULE(screen, inc); -#ifdef KWIN_BUILD_ACTIVITIES - m_selectedActivityId = rules->activity; - COMBOBOX_SET_RULE(activity, activityToCombo); -#endif - CHECKBOX_SET_RULE(maximizehoriz,); - CHECKBOX_SET_RULE(maximizevert,); - CHECKBOX_SET_RULE(minimize,); - CHECKBOX_SET_RULE(shade,); - CHECKBOX_SET_RULE(fullscreen,); - COMBOBOX_FORCE_RULE(placement, placementToCombo); - CHECKBOX_SET_RULE(above,); - CHECKBOX_SET_RULE(below,); - CHECKBOX_SET_RULE(noborder,); - auto decoColorToCombo = [this](const QString &value) { - for (int i = 0; i < decocolor->count(); ++i) { - if (decocolor->itemData(i).toString() == value) { - return i; - } - } - // search for Breeze - for (int i = 0; i < decocolor->count(); ++i) { - if (QFileInfo(decocolor->itemData(i).toString()).baseName() == QStringLiteral("Breeze")) { - return i; - } - } - return 0; - }; - COMBOBOX_FORCE_RULE(decocolor, decoColorToCombo); - CHECKBOX_SET_RULE(skiptaskbar,); - CHECKBOX_SET_RULE(skippager,); - CHECKBOX_SET_RULE(skipswitcher,); - CHECKBOX_FORCE_RULE(acceptfocus,); - CHECKBOX_FORCE_RULE(closeable,); - CHECKBOX_FORCE_RULE(autogroup,); - CHECKBOX_FORCE_RULE(autogroupfg,); - LINEEDIT_FORCE_RULE(autogroupid,); - SPINBOX_FORCE_RULE(opacityactive,); - SPINBOX_FORCE_RULE(opacityinactive,); - LINEEDIT_SET_RULE(shortcut,); - COMBOBOX_FORCE_RULE(fsplevel,); - COMBOBOX_FORCE_RULE(fpplevel,); - COMBOBOX_FORCE_RULE(type, typeToCombo); - CHECKBOX_SET_RULE(ignoregeometry,); - LINEEDIT_FORCE_RULE(minsize, sizeToStr); - LINEEDIT_FORCE_RULE(maxsize, sizeToStr); - CHECKBOX_FORCE_RULE(strictgeometry,); - CHECKBOX_FORCE_RULE(disableglobalshortcuts,); - CHECKBOX_FORCE_RULE(blockcompositing,); - LINEEDIT_SET_RULE(desktopfile,) -} - -#undef GENERIC_RULE -#undef CHECKBOX_SET_RULE -#undef LINEEDIT_SET_RULE -#undef COMBOBOX_SET_RULE -#undef SPINBOX_SET_RULE -#undef CHECKBOX_FORCE_RULE -#undef LINEEDIT_FORCE_RULE -#undef COMBOBOX_FORCE_RULE -#undef SPINBOX_FORCE_RULE - -#define GENERIC_RULE( var, func, Type, type, uimethod ) \ - if ( enable_##var->isChecked() && rule_##var->currentIndex() >= 0) \ - { \ - rules->var##rule = combo_to_##type##_rule[ rule_##var->currentIndex() ]; \ - rules->var = func( Ui::RulesWidgetBase::var->uimethod()); \ - } \ - else \ - rules->var##rule = Rules::Unused##Type##Rule; - -#define CHECKBOX_SET_RULE( var, func ) GENERIC_RULE( var, func, Set, set, isChecked ) -#define LINEEDIT_SET_RULE( var, func ) GENERIC_RULE( var, func, Set, set, text ) -#define COMBOBOX_SET_RULE( var, func ) GENERIC_RULE( var, func, Set, set, currentIndex ) -#define SPINBOX_SET_RULE( var, func ) GENERIC_RULE( var, func, Set, set, value) -#define CHECKBOX_FORCE_RULE( var, func ) GENERIC_RULE( var, func, Force, force, isChecked ) -#define LINEEDIT_FORCE_RULE( var, func ) GENERIC_RULE( var, func, Force, force, text ) -#define COMBOBOX_FORCE_RULE( var, func ) GENERIC_RULE( var, func, Force, force, currentIndex ) -#define SPINBOX_FORCE_RULE( var, func ) GENERIC_RULE( var, func, Force, force, value) - -Rules* RulesWidget::rules() const -{ - Rules* rules = new Rules(); - rules->description = description->text(); - rules->wmclass = wmclass->text().toUtf8(); - rules->wmclasscomplete = whole_wmclass->isChecked(); - rules->wmclassmatch = static_cast< Rules::StringMatch >(wmclass_match->currentIndex()); - rules->windowrole = role->text().toUtf8(); - rules->windowrolematch = static_cast< Rules::StringMatch >(role_match->currentIndex()); - rules->types = {}; - bool all_types = true; - for (int i = 0; - i < types->count(); - ++i) - if (!types->item(i)->isSelected()) - all_types = false; - if (all_types) // if all types are selected, use AllTypesMask (for future expansion) - rules->types = NET::AllTypesMask; - else { - rules->types |= types->item(0)->isSelected() ? NET::NormalMask : NET::WindowTypeMask(0); - rules->types |= types->item(1)->isSelected() ? NET::DialogMask : NET::WindowTypeMask(0); - rules->types |= types->item(2)->isSelected() ? NET::UtilityMask : NET::WindowTypeMask(0); - rules->types |= types->item(3)->isSelected() ? NET::DockMask : NET::WindowTypeMask(0); - rules->types |= types->item(4)->isSelected() ? NET::ToolbarMask : NET::WindowTypeMask(0); - rules->types |= types->item(5)->isSelected() ? NET::MenuMask : NET::WindowTypeMask(0); - rules->types |= types->item(6)->isSelected() ? NET::SplashMask : NET::WindowTypeMask(0); - rules->types |= types->item(7)->isSelected() ? NET::DesktopMask : NET::WindowTypeMask(0); - rules->types |= types->item(8)->isSelected() ? NET::OverrideMask : NET::WindowTypeMask(0); - rules->types |= types->item(9)->isSelected() ? NET::TopMenuMask : NET::WindowTypeMask(0); - } - rules->title = title->text(); - rules->titlematch = static_cast< Rules::StringMatch >(title_match->currentIndex()); - rules->clientmachine = machine->text().toUtf8(); - rules->clientmachinematch = static_cast< Rules::StringMatch >(machine_match->currentIndex()); - LINEEDIT_SET_RULE(position, strToPosition); - LINEEDIT_SET_RULE(size, strToSize); - COMBOBOX_SET_RULE(desktop, comboToDesktop); - SPINBOX_SET_RULE(screen, dec); -#ifdef KWIN_BUILD_ACTIVITIES - COMBOBOX_SET_RULE(activity, comboToActivity); -#endif - CHECKBOX_SET_RULE(maximizehoriz,); - CHECKBOX_SET_RULE(maximizevert,); - CHECKBOX_SET_RULE(minimize,); - CHECKBOX_SET_RULE(shade,); - CHECKBOX_SET_RULE(fullscreen,); - COMBOBOX_FORCE_RULE(placement, comboToPlacement); - CHECKBOX_SET_RULE(above,); - CHECKBOX_SET_RULE(below,); - CHECKBOX_SET_RULE(noborder,); - auto comboToDecocolor = [this](int index) -> QString { - return decocolor->itemData(index).toString(); - }; - COMBOBOX_FORCE_RULE(decocolor, comboToDecocolor); - CHECKBOX_SET_RULE(skiptaskbar,); - CHECKBOX_SET_RULE(skippager,); - CHECKBOX_SET_RULE(skipswitcher,); - CHECKBOX_FORCE_RULE(acceptfocus,); - CHECKBOX_FORCE_RULE(closeable,); - CHECKBOX_FORCE_RULE(autogroup,); - CHECKBOX_FORCE_RULE(autogroupfg,); - LINEEDIT_FORCE_RULE(autogroupid,); - SPINBOX_FORCE_RULE(opacityactive,); - SPINBOX_FORCE_RULE(opacityinactive,); - LINEEDIT_SET_RULE(shortcut,); - COMBOBOX_FORCE_RULE(fsplevel,); - COMBOBOX_FORCE_RULE(fpplevel,); - COMBOBOX_FORCE_RULE(type, comboToType); - CHECKBOX_SET_RULE(ignoregeometry,); - LINEEDIT_FORCE_RULE(minsize, strToSize); - LINEEDIT_FORCE_RULE(maxsize, strToSize); - CHECKBOX_FORCE_RULE(strictgeometry,); - CHECKBOX_FORCE_RULE(disableglobalshortcuts,); - CHECKBOX_FORCE_RULE(blockcompositing,); - LINEEDIT_SET_RULE(desktopfile,); - return rules; -} - -#undef GENERIC_RULE -#undef CHECKBOX_SET_RULE -#undef LINEEDIT_SET_RULE -#undef COMBOBOX_SET_RULE -#undef SPINBOX_SET_RULE -#undef CHECKBOX_FORCE_RULE -#undef LINEEDIT_FORCE_RULE -#undef COMBOBOX_FORCE_RULE -#undef SPINBOX_FORCE_RULE - -#define STRING_MATCH_COMBO( type ) \ - void RulesWidget::type##MatchChanged() \ - { \ - edit_reg_##type->setEnabled( type##_match->currentIndex() == Rules::RegExpMatch ); \ - type->setEnabled( type##_match->currentIndex() != Rules::UnimportantMatch ); \ - } - -STRING_MATCH_COMBO(wmclass) -STRING_MATCH_COMBO(role) -STRING_MATCH_COMBO(title) -STRING_MATCH_COMBO(machine) - -#undef STRING_MATCH_COMBO - -void RulesWidget::detectClicked() -{ - Q_ASSERT(detect_dlg == nullptr); - detect_dlg = new DetectDialog; - connect(detect_dlg, SIGNAL(detectionDone(bool)), this, SLOT(detected(bool))); - detect_dlg->detect(Ui::RulesWidgetBase::detection_delay->value()); - Ui::RulesWidgetBase::detect->setEnabled(false); -} - -void RulesWidget::detected(bool ok) -{ - if (ok) { - wmclass->setText(detect_dlg->selectedClass()); - wmclass_match->setCurrentIndex(Rules::ExactMatch); - wmclassMatchChanged(); // grrr - whole_wmclass->setChecked(detect_dlg->selectedWholeClass()); - role->setText(detect_dlg->selectedRole()); - role_match->setCurrentIndex(detect_dlg->selectedRole().isEmpty() - ? Rules::UnimportantMatch : Rules::ExactMatch); - roleMatchChanged(); - if (detect_dlg->selectedWholeApp()) { - for (int i = 0; - i < types->count(); - ++i) - types->item(i)->setSelected(true); - } else { - NET::WindowType type = detect_dlg->selectedType(); - for (int i = 0; - i < types->count(); - ++i) - types->item(i)->setSelected(false); - types->item(typeToCombo(type))->setSelected(true); - } - title->setText(detect_dlg->selectedTitle()); - title_match->setCurrentIndex(detect_dlg->titleMatch()); - titleMatchChanged(); - machine->setText(detect_dlg->selectedMachine()); - machine_match->setCurrentIndex(Rules::UnimportantMatch); - machineMatchChanged(); - // prefill values from to window to settings which already set - prefillUnusedValues(detect_dlg->windowInfo()); - } - delete detect_dlg; - detect_dlg = nullptr; - detect_dlg_ok = ok; - Ui::RulesWidgetBase::detect->setEnabled(true); -} - -#define GENERIC_PREFILL( var, func, info, uimethod ) \ - if ( !enable_##var->isChecked()) \ - { \ - Ui::RulesWidgetBase::var->uimethod( func( info )); \ - } - -#define CHECKBOX_PREFILL( var, func, info ) GENERIC_PREFILL( var, func, info, setChecked ) -#define LINEEDIT_PREFILL( var, func, info ) GENERIC_PREFILL( var, func, info, setText ) -#define COMBOBOX_PREFILL( var, func, info ) GENERIC_PREFILL( var, func, info, setCurrentIndex ) -#define SPINBOX_PREFILL( var, func, info ) GENERIC_PREFILL( var, func, info, setValue ) - -void RulesWidget::prefillUnusedValues(const QVariantMap& info) -{ - const QSize windowSize{info.value("width").toInt(), info.value("height").toInt()}; - LINEEDIT_PREFILL(position, positionToStr, QPoint(info.value("x").toInt(), info.value("y").toInt())); - LINEEDIT_PREFILL(size, sizeToStr, windowSize); - COMBOBOX_PREFILL(desktop, desktopToCombo, info.value("x11DesktopNumber").toInt()); - // COMBOBOX_PREFILL(activity, activityToCombo, info.activity()); // TODO: ivan - CHECKBOX_PREFILL(maximizehoriz, , info.value("maximizeHorizontal").toBool()); - CHECKBOX_PREFILL(maximizevert, , info.value("maximizeVertical").toBool()); - CHECKBOX_PREFILL(minimize, , info.value("minimized").toBool()); - CHECKBOX_PREFILL(shade, , info.value("shaded").toBool()); - CHECKBOX_PREFILL(fullscreen, , info.value("fullscreen").toBool()); - //COMBOBOX_PREFILL( placement, placementToCombo ); - CHECKBOX_PREFILL(above, , info.value("keepAbove").toBool()); - CHECKBOX_PREFILL(below, , info.value("keepBelow").toBool()); - CHECKBOX_PREFILL(noborder, , info.value("noBorder").toBool()); - CHECKBOX_PREFILL(skiptaskbar, , info.value("skipTaskbar").toBool()); - CHECKBOX_PREFILL(skippager, , info.value("skipPager").toBool()); - CHECKBOX_PREFILL(skipswitcher, , info.value("skipSwitcher").toBool()); - //CHECKBOX_PREFILL( acceptfocus, ); - //CHECKBOX_PREFILL( closeable, ); - //CHECKBOX_PREFILL( autogroup, ); - //CHECKBOX_PREFILL( autogroupfg, ); - //LINEEDIT_PREFILL( autogroupid, ); - SPINBOX_PREFILL(opacityactive, , 100 /*get the actual opacity somehow*/); - SPINBOX_PREFILL(opacityinactive, , 100 /*get the actual opacity somehow*/); - //LINEEDIT_PREFILL( shortcut, ); - //COMBOBOX_PREFILL( fsplevel, ); - //COMBOBOX_PREFILL( fpplevel, ); - COMBOBOX_PREFILL(type, typeToCombo, info.value("type").value()); - //CHECKBOX_PREFILL( ignoregeometry, ); - LINEEDIT_PREFILL(minsize, sizeToStr, windowSize); - LINEEDIT_PREFILL(maxsize, sizeToStr, windowSize); - //CHECKBOX_PREFILL( strictgeometry, ); - //CHECKBOX_PREFILL( disableglobalshortcuts, ); - //CHECKBOX_PREFILL( blockcompositing, ); - LINEEDIT_PREFILL(desktopfile, , info.value("desktopFile").toString()); -} - -#undef GENERIC_PREFILL -#undef CHECKBOX_PREFILL -#undef LINEEDIT_PREFILL -#undef COMBOBOX_PREFILL -#undef SPINBOX_PREFILL - -bool RulesWidget::finalCheck() -{ - if (description->text().isEmpty()) { - if (!wmclass->text().isEmpty()) - description->setText(i18n("Settings for %1", wmclass->text())); - else - description->setText(i18n("Unnamed entry")); - } - bool all_types = true; - for (int i = 0; - i < types->count(); - ++i) - if (!types->item(i)->isSelected()) - all_types = false; - if (wmclass_match->currentIndex() == Rules::UnimportantMatch && all_types) { - if (KMessageBox::warningContinueCancel(window(), - i18n("You have specified the window class as unimportant.\n" - "This means the settings will possibly apply to windows from all applications. " - "If you really want to create a generic setting, it is recommended you at least " - "limit the window types to avoid special window types.")) != KMessageBox::Continue) - return false; - } - return true; -} - -void RulesWidget::prepareWindowSpecific(const QVariantMap &info) -{ - tabs->setCurrentIndex(1); // geometry tab, skip tab for window identification - prefillUnusedValues(info); -} - -void RulesWidget::shortcutEditClicked() -{ - QPointer dlg = new EditShortcutDialog(window()); - dlg->setShortcut(shortcut->text()); - if (dlg->exec() == QDialog::Accepted) - shortcut->setText(dlg->shortcut()); - delete dlg; -} - -RulesDialog::RulesDialog(QWidget* parent, const char* name) - : QDialog(parent) -{ - setObjectName(name); - setModal(true); - setWindowTitle(i18n("Edit Window-Specific Settings")); - setWindowIcon(QIcon::fromTheme("preferences-system-windows-actions")); - - setLayout(new QVBoxLayout); - widget = new RulesWidget(this); - layout()->addWidget(widget); - - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - connect(buttons, SIGNAL(accepted()), SLOT(accept())); - connect(buttons, SIGNAL(rejected()), SLOT(reject())); - layout()->addWidget(buttons); -} - -// window is set only for Alt+F3/Window-specific settings, because the dialog -// is then related to one specific window -Rules* RulesDialog::edit(Rules* r, const QVariantMap& info, bool show_hints) -{ - rules = r; - widget->setRules(rules); - if (!info.isEmpty()) - { - widget->prepareWindowSpecific(info); - } - if (show_hints) - QTimer::singleShot(0, this, SLOT(displayHints())); - exec(); - return rules; -} - -void RulesDialog::displayHints() -{ - QString str = "

"; - str += i18n("This configuration dialog allows altering settings only for the selected window" - " or application. Find the setting you want to affect, enable the setting using the checkbox," - " select in what way the setting should be affected and to which value."); -#if 0 // maybe later - str += "

" + i18n("Consult the documentation for more details."); -#endif - str += "

"; - KMessageBox::information(this, str, QString(), "displayhints"); -} - -void RulesDialog::accept() -{ - if (!widget->finalCheck()) - return; - rules = widget->rules(); - QDialog::accept(); -} - -EditShortcut::EditShortcut(QWidget* parent) - : QWidget(parent) -{ - setupUi(this); -} - -void EditShortcut::editShortcut() -{ - QPointer< ShortcutDialog > dlg = new ShortcutDialog(QKeySequence(shortcut->text()), window()); - if (dlg->exec() == QDialog::Accepted) - shortcut->setText(dlg->shortcut().toString()); - delete dlg; -} - -void EditShortcut::clearShortcut() -{ - shortcut->clear(); -} - -EditShortcutDialog::EditShortcutDialog(QWidget* parent, const char* name) - : QDialog(parent) - , widget(new EditShortcut(this)) -{ - setObjectName(name); - setModal(true); - setWindowTitle(i18n("Edit Shortcut")); - - setLayout(new QVBoxLayout); - - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - connect(buttons, SIGNAL(accepted()), SLOT(accept())); - connect(buttons, SIGNAL(rejected()), SLOT(reject())); - - layout()->addWidget(widget); - layout()->addWidget(buttons); -} - -void EditShortcutDialog::setShortcut(const QString& cut) -{ - widget->shortcut->setText(cut); -} - -QString EditShortcutDialog::shortcut() const -{ - return widget->shortcut->text(); -} - -ShortcutDialog::ShortcutDialog(const QKeySequence& cut, QWidget* parent) - : QDialog(parent) - , widget(new KKeySequenceWidget(this)) -{ - widget->setKeySequence(cut); - // It's a global shortcut so don't allow multikey shortcuts - widget->setMultiKeyShortcutsAllowed(false); - - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - connect(buttons, SIGNAL(accepted()), SLOT(accept())); - connect(buttons, SIGNAL(rejected()), SLOT(reject())); - - setLayout(new QVBoxLayout); - layout()->addWidget(widget); - layout()->addWidget(buttons); -} - -void ShortcutDialog::accept() -{ - QKeySequence seq = shortcut(); - if (!seq.isEmpty()) { - if (seq[0] == Qt::Key_Escape) { - reject(); - return; - } - if (seq[0] == Qt::Key_Space - || (seq[0] & Qt::KeyboardModifierMask) == 0) { - // clear - widget->clearKeySequence(); - QDialog::accept(); - return; - } - } - QDialog::accept(); -} - -QKeySequence ShortcutDialog::shortcut() const -{ - return widget->keySequence(); -} - -} // namespace - diff --git a/kcmkwin/kwinrules/ruleswidgetbase.ui b/kcmkwin/kwinrules/ruleswidgetbase.ui deleted file mode 100644 --- a/kcmkwin/kwinrules/ruleswidgetbase.ui +++ /dev/null @@ -1,2834 +0,0 @@ - - - KWin::RulesWidgetBase - - - - 0 - 0 - 592 - 588 - - - - - - - 0 - - - - &Window matching - - - - - - &Description: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - false - - - description - - - - - - - - - - Window &class (application): - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - false - - - wmclass - - - - - - - - Unimportant - - - - - Exact Match - - - - - Substring Match - - - - - Regular Expression - - - - - - - - - - - false - - - Edit - - - - - - - - - - Match w&hole window class - - - - - - - Window ro&le: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - false - - - role - - - - - - - - Unimportant - - - - - Exact Match - - - - - Substring Match - - - - - Regular Expression - - - - - - - - - - - false - - - Edit - - - - - - - Window &types: - - - Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing - - - false - - - types - - - - - - - Window t&itle: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - false - - - title - - - - - - - - Unimportant - - - - - Exact Match - - - - - Substring Match - - - - - Regular Expression - - - - - - - - false - - - Edit - - - - - - - - - - &Machine (hostname): - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - false - - - machine - - - - - - - - Unimportant - - - - - Exact Match - - - - - Substring Match - - - - - Regular Expression - - - - - - - - false - - - Edit - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - &Detect Window Properties - - - - - - - s delay - - - 30 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 0 - 0 - - - - false - - - Qt::ScrollBarAsNeeded - - - Qt::ScrollBarAsNeeded - - - true - - - false - - - QAbstractItemView::NoDragDrop - - - false - - - QAbstractItemView::ExtendedSelection - - - QListView::Static - - - QListView::TopToBottom - - - true - - - QListView::Adjust - - - 0 - - - QListView::ListMode - - - true - - - - Normal Window - - - - - Dialog Window - - - - - Utility Window - - - - - Dock (panel) - - - - - Toolbar - - - - - Torn-Off Menu - - - - - Splash Screen - - - - - Desktop - - - - - Unmanaged Window - - - - - Standalone Menubar - - - - - - - - Qt::Horizontal - - - - - - - - &Size && Position - - - - - - &Position - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - x,y - - - 0123456789-+,xX: - - - - - - - &Size - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - width,height - - - 0123456789-+,xX: - - - - - - - Qt::Horizontal - - - - - - - Maximized &horizontally - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - - - - - Maximized &vertically - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - - - - - Qt::Horizontal - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - &Desktop - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Activit&y - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - - - - - false - - - 1 - - - - - - - Qt::Horizontal - - - - - - - &Fullscreen - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - - - - - M&inimized - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - - - - - Sh&aded - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - - - - - Qt::Horizontal - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - - Default - - - - - No Placement - - - - - Minimal Overlapping - - - - - Maximized - - - - - Cascaded - - - - - Centered - - - - - Random - - - - - In Top-Left Corner - - - - - Under Mouse - - - - - On Main Window - - - - - - - - - - - Initial p&lacement - - - - - - - Windows can ask to appear in a certain position. -By default this overrides the placement strategy -what might be nasty if the client abuses the feature -to unconditionally popup in the middle of your screen. - - - Ignore requested &geometry - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - - - - - Qt::Horizontal - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - M&inimum size - - - - - - - false - - - width,height - - - 0123456789-+,xX: - - - - - - - M&aximum size - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - width,height - - - 0123456789-+,xX: - - - - - - - Eg. terminals or video players can ask to keep a certain aspect ratio -or only grow by values larger than one -(eg. by the dimensions of one character). -This may be pointless and the restriction prevents arbitrary dimensions -like your complete screen area. - - - Qt::LeftToRight - - - Obey geometry restrictions - - - - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 16 - - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - Screen - - - - - - - - &Arrangement && Access - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - Window shall (not) appear in the manager for virtual desktops - - - Skip pa&ger - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - - - - - false - - - - - - - Window shall (not) appear in the taskbar. - - - Skip &taskbar - - - - - - - false - - - - - - - Window shall (not) appear in the Alt+Tab list - - - Skip &switcher - - - - - - - false - - - Edit... - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - Qt::Horizontal - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 8 - - - - - - - - false - - - - - - - false - - - - - - - Shortcut - - - - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - - - - - false - - - - - - - Keep &above - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Autog&roup in foreground - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - - - - - Qt::Horizontal - - - - - - - Keep &below - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - - 0 - 0 - - - - Qt::Horizontal - - - - - - - Autogroup by I&D - - - - - - - Autogroup with &identical - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - - - - - - Appearance && &Fixes - - - - - - &No titlebar and frame - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - - - - - Titlebar color &scheme - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - - - - - Qt::Horizontal - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - A&ctive opacity - - - - - - - false - - - % - - - 100 - - - 100 - - - - - - - I&nactive opacity - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - % - - - 100 - - - 100 - - - - - - - Qt::Horizontal - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 8 - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 8 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - KWin tries to prevent windows from taking the focus -("activate") while you're working in another window, -but this may sometimes fail or superact. -"None" will unconditionally allow this window to get the focus while -"Extreme" will completely prevent it from taking the focus. - - - &Focus stealing prevention - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - - None - - - - - Low - - - - - Normal - - - - - High - - - - - Extreme - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - This controls the focus protection of the currently active window. -None will always give the focus away, -Extreme will keep it. -Otherwise it's interleaved with the stealing prevention -assigned to the window that wants the focus. - - - Focus protection - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - - None - - - - - Low - - - - - Normal - - - - - High - - - - - Extreme - - - - - - - - Windows may prevent to get the focus (activate) when being clicked. -On the other hand you might wish to prevent a window -from getting focused on a mouse click. - - - Accept &focus - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - - - - - When used, a window will receive -all keyboard inputs while it is active, including Alt+Tab etc. -This is especially interesting for emulators or virtual machines. - -Be warned: -you won't be able to Alt+Tab out of the window -nor use any other global shortcut (such as Alt+F2 to show KRunner) -while it's active! - - - Ignore global shortcuts - - - - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - - - - - Qt::Horizontal - - - - - - - &Closeable - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - - - - - Window &type - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - - Normal Window - - - - - Dialog Window - - - - - Utility Window - - - - - Dock (panel) - - - - - Toolbar - - - - - Torn-Off Menu - - - - - Splash Screen - - - - - Desktop - - - - - Standalone Menubar - - - - - - - - Desktop file name - - - - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - org.kde.kwin - - - - - - - Qt::Horizontal - - - - - - - Block compositing - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - KLineEdit - QLineEdit -
klineedit.h
-
- - KComboBox - QComboBox -
kcombobox.h
-
- - YesNoBox - QWidget -
yesnobox.h
- 1 -
-
- - description - detect - detection_delay - wmclass_match - wmclass - edit_reg_wmclass - whole_wmclass - role_match - role - edit_reg_role - types - title_match - title - edit_reg_title - machine_match - machine - edit_reg_machine - enable_position - rule_position - position - enable_size - rule_size - size - enable_maximizehoriz - rule_maximizehoriz - enable_maximizevert - rule_maximizevert - enable_desktop - rule_desktop - desktop - enable_activity - rule_activity - activity - enable_screen - rule_screen - screen - enable_fullscreen - rule_fullscreen - enable_minimize - rule_minimize - enable_shade - rule_shade - enable_placement - rule_placement - placement - enable_ignoregeometry - rule_ignoregeometry - enable_minsize - rule_minsize - minsize - enable_maxsize - rule_maxsize - maxsize - enable_strictgeometry - rule_strictgeometry - enable_above - rule_above - enable_below - rule_below - enable_autogroup - rule_autogroup - enable_autogroupfg - rule_autogroupfg - enable_autogroupid - rule_autogroupid - autogroupid - enable_skiptaskbar - rule_skiptaskbar - enable_skippager - rule_skippager - enable_skipswitcher - rule_skipswitcher - enable_shortcut - rule_shortcut - shortcut - shortcut_edit - enable_noborder - rule_noborder - enable_decocolor - rule_decocolor - decocolor - enable_opacityactive - rule_opacityactive - opacityactive - enable_opacityinactive - rule_opacityinactive - opacityinactive - enable_fsplevel - rule_fsplevel - fsplevel - enable_fpplevel - rule_fpplevel - fpplevel - enable_acceptfocus - rule_acceptfocus - enable_disableglobalshortcuts - rule_disableglobalshortcuts - enable_closeable - rule_closeable - enable_type - rule_type - type - enable_desktopfile - rule_desktopfile - desktopfile - enable_blockcompositing - rule_blockcompositing - tabs - - - - - detect - clicked() - KWin::RulesWidgetBase - detectClicked() - - - 285 - 124 - - - 20 - 20 - - - - - wmclass_match - activated(int) - KWin::RulesWidgetBase - wmclassMatchChanged() - - - 297 - 196 - - - 20 - 20 - - - - - role_match - activated(int) - KWin::RulesWidgetBase - roleMatchChanged() - - - 297 - 254 - - - 20 - 20 - - - - - title_match - activated(int) - KWin::RulesWidgetBase - titleMatchChanged() - - - 231 - 482 - - - 242 - 293 - - - - - machine_match - activated(int) - KWin::RulesWidgetBase - machineMatchChanged() - - - 194 - 509 - - - 242 - 293 - - - - -
diff --git a/kcmkwin/kwinrules/yesnobox.h b/kcmkwin/kwinrules/yesnobox.h deleted file mode 100644 --- a/kcmkwin/kwinrules/yesnobox.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2011 Thomas Lübking - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - - -#ifndef YESNOBOX_H -#define YESNOBOX_H - -#include -#include - -#include - -class YesNoBox : public QWidget { - Q_OBJECT -public: - explicit YesNoBox( QWidget *parent ) : QWidget(parent) - { - QHBoxLayout *l = new QHBoxLayout(this); - l->setContentsMargins(0, 0, 0, 0); - l->addWidget(yes = new QRadioButton(i18n("Yes"), this)); - l->addWidget(no = new QRadioButton(i18n("No"), this)); - l->addStretch(100); - no->setChecked(true); - connect(yes, SIGNAL(clicked(bool)), this, SIGNAL(clicked(bool))); - connect(yes, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); - connect(no, SIGNAL(clicked(bool)), this, SLOT(noClicked(bool))); - } - bool isChecked() { return yes->isChecked(); } -public Q_SLOTS: - void setChecked(bool b) { yes->setChecked(b); } - void toggle() { yes->toggle(); } - -Q_SIGNALS: - void clicked(bool checked = false); - void toggled(bool checked); -private Q_SLOTS: - void noClicked(bool checked) { emit clicked(!checked); } -private: - QRadioButton *yes, *no; -}; - -#endif // YESNOBOX_H