10#if KWIN_BUILD_ACTIVITIES
14#include <QDBusConnection>
15#include <QDBusMessage>
16#include <QDBusMetaType>
17#include <QDBusPendingCallWatcher>
18#include <QDBusPendingReply>
24#include <KColorSchemeManager>
26#include <KLocalizedString>
27#include <KWindowSystem>
33 : QAbstractListModel(parent)
35 qmlRegisterUncreatableType<RuleItem>(
"org.kde.kcms.kwinrules", 1, 0,
"RuleItem",
36 QStringLiteral(
"Do not create objects of type RuleItem"));
37 qmlRegisterUncreatableType<RulesModel>(
"org.kde.kcms.kwinrules", 1, 0,
"RulesModel",
38 QStringLiteral(
"Do not create objects of type RulesModel"));
39 qmlRegisterUncreatableType<OptionsModel>(
"org.kde.kcms.kwinrules", 1, 0,
"OptionsModel",
40 QStringLiteral(
"Do not create objects of type OptionsModel"));
42 qDBusRegisterMetaType<KWin::DBusDesktopDataStruct>();
43 qDBusRegisterMetaType<KWin::DBusDesktopDataVector>();
55 {
KeyRole, QByteArrayLiteral(
"key")},
56 {
NameRole, QByteArrayLiteral(
"name")},
57 {
IconRole, QByteArrayLiteral(
"icon")},
64 {
TypeRole, QByteArrayLiteral(
"type")},
74 if (parent.isValid()) {
77 return m_ruleList.size();
82 if (!checkIndex(index, CheckIndexOption::IndexIsValid | CheckIndexOption::ParentIsInvalid)) {
86 const RuleItem *rule = m_ruleList.at(index.row());
106 return rule->
value();
123 if (!checkIndex(index, CheckIndexOption::IndexIsValid | CheckIndexOption::ParentIsInvalid)) {
127 RuleItem *rule = m_ruleList.at(index.row());
131 if (value.toBool() == rule->
isEnabled()) {
138 processSuggestion(rule->
key(), value);
140 if (value == rule->
value()) {
146 if (value.toInt() == rule->
policy()) {
161 writeToSettings(rule);
163 Q_EMIT dataChanged(index, index, QList<int>{role});
177 if (indexes.isEmpty()) {
178 return QModelIndex();
180 return indexes.at(0);
186 m_rules.insert(rule->
key(), rule);
193 return m_rules.contains(key);
198 return m_rules.value(key);
203 const QString desc = m_rules[
"description"]->value().toString();
204 if (!desc.isEmpty()) {
207 return defaultDescription();
215QString RulesModel::defaultDescription()
const
217 const QString wmclass = m_rules[
"wmclass"]->value().toString();
218 const QString title = m_rules[
"title"]->isEnabled() ? m_rules[
"title"]->value().toString() : QString();
220 if (!title.isEmpty()) {
221 return i18n(
"Window settings for %1", title);
223 if (!wmclass.isEmpty()) {
224 return i18n(
"Settings for %1", wmclass);
227 return i18n(
"New window settings");
230void RulesModel::processSuggestion(
const QString &key,
const QVariant &value)
232 if (key == QLatin1String(
"wmclasshelper")) {
240 QStringList messages;
242 if (wmclassWarning()) {
243 messages << i18n(
"You have specified the window class as unimportant.\n"
244 "This means the settings will possibly apply to windows from all applications."
245 " If you really want to create a generic setting, it is recommended"
246 " you at least limit the window types to avoid special window types.");
249 if (geometryWarning()) {
250 messages << i18n(
"Some applications set their own geometry after starting,"
251 " overriding your initial settings for size and position. "
252 "To enforce these settings, also force the property \"%1\" to \"Yes\".",
253 m_rules[
"ignoregeometry"]->name());
256 if (opacityWarning()) {
257 messages << i18n(
"Readability may be impaired with extremely low opacity values. At 0%, the window becomes invisible.");
263bool RulesModel::wmclassWarning()
const
265 const bool no_wmclass = !m_rules[
"wmclass"]->isEnabled()
267 const bool alltypes = !m_rules[
"types"]->isEnabled()
268 || (m_rules[
"types"]->value() == 0)
269 || (m_rules[
"types"]->value() == NET::AllTypesMask)
270 || ((m_rules[
"types"]->value().toInt() | (1 << NET::Override)) == 0x3FF);
272 return (no_wmclass && alltypes);
275bool RulesModel::geometryWarning()
const
277 if (!KWindowSystem::isPlatformX11()) {
281 const bool ignoregeometry = m_rules[
"ignoregeometry"]->isEnabled()
283 && m_rules[
"ignoregeometry"]->value() ==
true;
285 const bool initialPos = m_rules[
"position"]->isEnabled()
289 const bool initialSize = m_rules[
"size"]->isEnabled()
293 const bool initialPlacement = m_rules[
"placement"]->isEnabled()
296 return (!ignoregeometry && (initialPos || initialSize || initialPlacement));
299bool RulesModel::opacityWarning()
const
301 auto opacityActive = m_rules[
"opacityactive"];
302 const bool lowOpacityActive = opacityActive->isEnabled()
304 && opacityActive->value().toInt() < 25;
306 auto opacityInactive = m_rules[
"opacityinactive"];
307 const bool lowOpacityInactive = opacityInactive->isEnabled()
309 && opacityInactive->value().toInt() < 25;
311 return lowOpacityActive || lowOpacityInactive;
329 for (
RuleItem *rule : std::as_const(m_ruleList)) {
330 const KConfigSkeletonItem *configItem = m_settings->findItem(rule->
key());
331 const KConfigSkeletonItem *configPolicyItem = m_settings->findItem(rule->
policyKey());
339 const bool isEnabled = configPolicyItem ? configPolicyItem->property() !=
Rules::Unused
340 : !configItem->property().toString().isEmpty();
343 const QVariant value = configItem->property();
346 if (configPolicyItem) {
347 const int policy = configPolicyItem->property().toInt();
358void RulesModel::writeToSettings(
RuleItem *rule)
360 KConfigSkeletonItem *configItem = m_settings->findItem(rule->
key());
361 KConfigSkeletonItem *configPolicyItem = m_settings->findItem(rule->
policyKey());
368 configItem->setProperty(rule->
value());
369 if (configPolicyItem) {
370 configPolicyItem->setProperty(rule->
policy());
373 configItem->setDefault();
374 if (configPolicyItem) {
375 configPolicyItem->setDefault();
380void RulesModel::populateRuleList()
382 qDeleteAll(m_ruleList);
386 auto description = addRule(
new RuleItem(QLatin1String(
"description"),
388 i18n(
"Description"), i18n(
"Window matching"),
389 QIcon::fromTheme(
"entry-edit")));
394 auto wmclass = addRule(
new RuleItem(QLatin1String(
"wmclass"),
396 i18n(
"Window class (application)"), i18n(
"Window matching"),
397 QIcon::fromTheme(
"window")));
402 auto wmclasscomplete = addRule(
new RuleItem(QLatin1String(
"wmclasscomplete"),
404 i18n(
"Match whole window class"), i18n(
"Window matching"),
405 QIcon::fromTheme(
"window")));
409 auto wmclasshelper = addRule(
new RuleItem(QLatin1String(
"wmclasshelper"),
411 i18n(
"Whole window class"), i18n(
"Window matching"),
412 QIcon::fromTheme(
"window")));
415 auto types = addRule(
new RuleItem(QLatin1String(
"types"),
417 i18n(
"Window types"), i18n(
"Window matching"),
418 QIcon::fromTheme(
"window-duplicate")));
419 types->setOptionsData(windowTypesModelData());
423 addRule(
new RuleItem(QLatin1String(
"windowrole"),
425 i18n(
"Window role"), i18n(
"Window matching"),
426 QIcon::fromTheme(
"dialog-object-properties")));
428 auto title = addRule(
new RuleItem(QLatin1String(
"title"),
430 i18n(
"Window title"), i18n(
"Window matching"),
431 QIcon::fromTheme(
"edit-comment")));
434 addRule(
new RuleItem(QLatin1String(
"clientmachine"),
436 i18n(
"Machine (hostname)"), i18n(
"Window matching"),
437 QIcon::fromTheme(
"computer")));
440 auto position = addRule(
new RuleItem(QLatin1String(
"position"),
442 i18n(
"Position"), i18n(
"Size & Position"),
443 QIcon::fromTheme(
"transform-move")));
446 auto size = addRule(
new RuleItem(QLatin1String(
"size"),
448 i18n(
"Size"), i18n(
"Size & Position"),
449 QIcon::fromTheme(
"transform-scale")));
452 addRule(
new RuleItem(QLatin1String(
"maximizehoriz"),
454 i18n(
"Maximized horizontally"), i18n(
"Size & Position"),
455 QIcon::fromTheme(
"resizecol")));
457 addRule(
new RuleItem(QLatin1String(
"maximizevert"),
459 i18n(
"Maximized vertically"), i18n(
"Size & Position"),
460 QIcon::fromTheme(
"resizerow")));
463 if (KWindowSystem::isPlatformX11()) {
465 desktops =
new RuleItem(QLatin1String(
"desktops"),
467 i18n(
"Virtual Desktop"), i18n(
"Size & Position"),
468 QIcon::fromTheme(
"virtual-desktops"));
471 desktops =
new RuleItem(QLatin1String(
"desktops"),
473 i18n(
"Virtual Desktops"), i18n(
"Size & Position"),
474 QIcon::fromTheme(
"virtual-desktops"));
477 desktops->setOptionsData(virtualDesktopsModelData());
480 m_rules[
"desktops"]->setOptionsData(virtualDesktopsModelData());
481 const QModelIndex index =
indexOf(
"desktops");
485 updateVirtualDesktops();
487#if KWIN_BUILD_ACTIVITIES
488 m_activities =
new KActivities::Consumer(
this);
490 auto activity = addRule(
new RuleItem(QLatin1String(
"activity"),
492 i18n(
"Activities"), i18n(
"Size & Position"),
493 QIcon::fromTheme(
"activities")));
494 activity->setOptionsData(activitiesModelData());
497 auto updateActivities = [
this]() {
498 m_rules[
"activity"]->setOptionsData(activitiesModelData());
499 const QModelIndex index =
indexOf(
"activity");
502 connect(m_activities, &KActivities::Consumer::activitiesChanged,
this, updateActivities);
503 connect(m_activities, &KActivities::Consumer::serviceStatusChanged,
this, updateActivities);
506 addRule(
new RuleItem(QLatin1String(
"screen"),
508 i18n(
"Screen"), i18n(
"Size & Position"),
509 QIcon::fromTheme(
"osd-shutd-screen")));
511 addRule(
new RuleItem(QLatin1String(
"fullscreen"),
513 i18n(
"Fullscreen"), i18n(
"Size & Position"),
514 QIcon::fromTheme(
"view-fullscreen")));
516 addRule(
new RuleItem(QLatin1String(
"minimize"),
518 i18n(
"Minimized"), i18n(
"Size & Position"),
519 QIcon::fromTheme(
"window-minimize")));
521 addRule(
new RuleItem(QLatin1String(
"shade"),
523 i18n(
"Shaded"), i18n(
"Size & Position"),
524 QIcon::fromTheme(
"window-shade")));
526 auto placement = addRule(
new RuleItem(QLatin1String(
"placement"),
528 i18n(
"Initial placement"), i18n(
"Size & Position"),
529 QIcon::fromTheme(
"region")));
530 placement->setOptionsData(placementModelData());
533 if (KWindowSystem::isPlatformX11()) {
535 auto ignoregeometry = addRule(
new RuleItem(QLatin1String(
"ignoregeometry"),
537 i18n(
"Ignore requested geometry"), i18n(
"Size & Position"),
538 QIcon::fromTheme(
"view-time-schedule-baselined-remove"),
539 xi18nc(
"@info:tooltip",
540 "Some applications can set their own geometry, overriding the window manager preferences. "
541 "Setting this property overrides their placement requests."
543 "This affects <interface>Size</interface> and <interface>Position</interface> "
544 "but not <interface>Maximized</interface> or <interface>Fullscreen</interface> states."
546 "Note that the position can also be used to map to a different <interface>Screen</interface>")));
550 addRule(
new RuleItem(QLatin1String(
"minsize"),
552 i18n(
"Minimum Size"), i18n(
"Size & Position"),
553 QIcon::fromTheme(
"transform-scale")));
555 addRule(
new RuleItem(QLatin1String(
"maxsize"),
557 i18n(
"Maximum Size"), i18n(
"Size & Position"),
558 QIcon::fromTheme(
"transform-scale")));
560 addRule(
new RuleItem(QLatin1String(
"strictgeometry"),
562 i18n(
"Obey geometry restrictions"), i18n(
"Size & Position"),
563 QIcon::fromTheme(
"transform-crop-and-resize"),
564 xi18nc(
"@info:tooltip",
"Some apps like video players or terminals can ask KWin to constrain them to "
565 "certain aspect ratios or only grow by values larger than the dimensions of one "
566 "character. Use this property to ignore such restrictions and allow those windows "
567 "to be resized to arbitrary sizes."
569 "This can be helpful for windows that can't quite fit the full screen area when "
573 addRule(
new RuleItem(QLatin1String(
"above"),
575 i18n(
"Keep above other windows"), i18n(
"Arrangement & Access"),
576 QIcon::fromTheme(
"window-keep-above")));
578 addRule(
new RuleItem(QLatin1String(
"below"),
580 i18n(
"Keep below other windows"), i18n(
"Arrangement & Access"),
581 QIcon::fromTheme(
"window-keep-below")));
583 addRule(
new RuleItem(QLatin1String(
"skiptaskbar"),
585 i18n(
"Skip taskbar"), i18n(
"Arrangement & Access"),
586 QIcon::fromTheme(
"kt-show-statusbar"),
587 i18nc(
"@info:tooltip",
"Controls whether or not the window appears in the Task Manager.")));
589 addRule(
new RuleItem(QLatin1String(
"skippager"),
591 i18n(
"Skip pager"), i18n(
"Arrangement & Access"),
592 QIcon::fromTheme(
"org.kde.plasma.pager"),
593 i18nc(
"@info:tooltip",
"Controls whether or not the window appears in the Virtual Desktop manager.")));
595 addRule(
new RuleItem(QLatin1String(
"skipswitcher"),
597 i18n(
"Skip switcher"), i18n(
"Arrangement & Access"),
598 QIcon::fromTheme(
"preferences-system-windows-effect-flipswitch"),
599 xi18nc(
"@info:tooltip",
"Controls whether or not the window appears in the <shortcut>Alt+Tab</shortcut> window list.")));
601 addRule(
new RuleItem(QLatin1String(
"shortcut"),
603 i18n(
"Shortcut"), i18n(
"Arrangement & Access"),
604 QIcon::fromTheme(
"configure-shortcuts")));
607 addRule(
new RuleItem(QLatin1String(
"noborder"),
609 i18n(
"No titlebar and frame"), i18n(
"Appearance & Fixes"),
610 QIcon::fromTheme(
"dialog-cancel")));
612 auto decocolor = addRule(
new RuleItem(QLatin1String(
"decocolor"),
614 i18n(
"Titlebar color scheme"), i18n(
"Appearance & Fixes"),
615 QIcon::fromTheme(
"preferences-desktop-theme")));
616 decocolor->setOptionsData(colorSchemesModelData());
618 auto opacityactive = addRule(
new RuleItem(QLatin1String(
"opacityactive"),
620 i18n(
"Active opacity"), i18n(
"Appearance & Fixes"),
621 QIcon::fromTheme(
"edit-opacity")));
623 auto opacityinactive = addRule(
new RuleItem(QLatin1String(
"opacityinactive"),
625 i18n(
"Inactive opacity"), i18n(
"Appearance & Fixes"),
626 QIcon::fromTheme(
"edit-opacity")));
629 auto fsplevel = addRule(
new RuleItem(QLatin1String(
"fsplevel"),
631 i18n(
"Focus stealing prevention"), i18n(
"Appearance & Fixes"),
632 QIcon::fromTheme(
"preferences-system-windows-effect-glide"),
633 xi18nc(
"@info:tooltip",
"KWin tries to prevent windows that were opened without direct user action from raising "
634 "themselves and taking focus while you're currently interacting with another window. This "
635 "property can be used to change the level of focus stealing prevention applied to "
636 "individual windows and apps."
638 "Here's what will happen to a window opened without your direct action at each level of "
639 "focus stealing prevention:"
642 "<item><emphasis strong='true'>None:</emphasis> The window will be raised and focused.</item>"
643 "<item><emphasis strong='true'>Low:</emphasis> Focus stealing prevention will be applied, "
644 "but in the case of a situation KWin considers ambiguous, the window will be raised and "
646 "<item><emphasis strong='true'>Normal:</emphasis> Focus stealing prevention will be "
647 "applied, but in the case of a situation KWin considers ambiguous, the window will "
648 "<emphasis>not</emphasis> be raised and focused.</item>"
649 "<item><emphasis strong='true'>High:</emphasis> The window will only be raised and focused "
650 "if it belongs to the same app as the currently-focused window.</item>"
651 "<item><emphasis strong='true'>Extreme:</emphasis> The window will never be raised and "
654 fsplevel->setOptionsData(focusModelData());
656 auto fpplevel = addRule(
new RuleItem(QLatin1String(
"fpplevel"),
658 i18n(
"Focus protection"), i18n(
"Appearance & Fixes"),
659 QIcon::fromTheme(
"preferences-system-windows-effect-minimize"),
660 xi18nc(
"@info:tooltip",
"This property controls the focus protection level of the currently active "
661 "window. It is used to override the focus stealing prevention applied to new windows that "
662 "are opened without your direct action."
664 "Here's what happens to new windows that are opened without your direct action at each "
665 "level of focus protection while the window with this property applied to it has focus:"
668 "<item><emphasis strong='true'>None</emphasis>: Newly-opened windows always raise "
669 "themselves and take focus.</item>"
670 "<item><emphasis strong='true'>Low:</emphasis> Focus stealing prevention will be applied "
671 "to the newly-opened window, but in the case of a situation KWin considers ambiguous, the "
672 "window will be raised and focused.</item>"
673 "<item><emphasis strong='true'>Normal:</emphasis> Focus stealing prevention will be applied "
674 "to the newly-opened window, but in the case of a situation KWin considers ambiguous, the "
675 "window will <emphasis>not</emphasis> be raised and focused.</item>"
676 "<item><emphasis strong='true'>High:</emphasis> Newly-opened windows will only raise "
677 "themselves and take focus if they belongs to the same app as the currently-focused "
679 "<item><emphasis strong='true'>Extreme:</emphasis> Newly-opened windows never raise "
680 "themselves and take focus.</item>"
682 fpplevel->setOptionsData(focusModelData());
684 addRule(
new RuleItem(QLatin1String(
"acceptfocus"),
686 i18n(
"Accept focus"), i18n(
"Appearance & Fixes"),
687 QIcon::fromTheme(
"preferences-desktop-cursors"),
688 i18n(
"Controls whether or not the window becomes focused when clicked.")));
690 addRule(
new RuleItem(QLatin1String(
"disableglobalshortcuts"),
692 i18n(
"Ignore global shortcuts"), i18n(
"Appearance & Fixes"),
693 QIcon::fromTheme(
"input-keyboard-virtual-off"),
694 xi18nc(
"@info:tooltip",
"Use this property to prevent global keyboard shortcuts from working while "
695 "the window is focused. This can be useful for apps like emulators or virtual "
696 "machines that handle some of the same shortcuts themselves."
698 "Note that you won't be able to <shortcut>Alt+Tab</shortcut> out of the window "
699 "or use any other global shortcuts such as <shortcut>Alt+Space</shortcut> to "
700 "activate KRunner.")));
702 addRule(
new RuleItem(QLatin1String(
"closeable"),
704 i18n(
"Closeable"), i18n(
"Appearance & Fixes"),
705 QIcon::fromTheme(
"dialog-close")));
707 addRule(
new RuleItem(QLatin1String(
"desktopfile"),
709 i18n(
"Desktop file name"), i18n(
"Appearance & Fixes"),
710 QIcon::fromTheme(
"application-x-desktop")));
712 addRule(
new RuleItem(QLatin1String(
"blockcompositing"),
714 i18n(
"Block compositing"), i18n(
"Appearance & Fixes"),
715 QIcon::fromTheme(
"composite-track-on")));
717 auto layer = addRule(
new RuleItem(QLatin1String(
"layer"),
719 i18n(
"Layer"), i18n(
"Appearance & Fixes"),
720 QIcon::fromTheme(
"view-sort")));
721 layer->setOptionsData(layerModelData());
723 addRule(
new RuleItem(QLatin1String(
"adaptivesync"),
725 i18n(
"Adaptive Sync"), i18n(
"Appearance & Fixes"),
726 QIcon::fromTheme(
"monitor-symbolic")));
729const QHash<QString, QString> RulesModel::x11PropertyHash()
731 static const auto propertyToRule = QHash<QString, QString>{
732 {
"caption",
"title"},
733 {
"role",
"windowrole"},
734 {
"clientMachine",
"clientmachine"},
735 {
"maximizeHorizontal",
"maximizehoriz"},
736 {
"maximizeVertical",
"maximizevert"},
737 {
"minimized",
"minimize"},
739 {
"fullscreen",
"fullscreen"},
740 {
"keepAbove",
"above"},
741 {
"keepBelow",
"below"},
742 {
"noBorder",
"noborder"},
743 {
"skipTaskbar",
"skiptaskbar"},
744 {
"skipPager",
"skippager"},
745 {
"skipSwitcher",
"skipswitcher"},
746 {
"desktopFile",
"desktopfile"},
747 {
"desktops",
"desktops"},
750 return propertyToRule;
756 const QPoint position = QPoint(info.value(
"x").toInt(), info.value(
"y").toInt());
757 const QSize size = QSize(info.value(
"width").toInt(), info.value(
"height").toInt());
759 m_rules[
"position"]->setSuggestedValue(position);
760 m_rules[
"size"]->setSuggestedValue(size);
761 m_rules[
"minsize"]->setSuggestedValue(size);
762 m_rules[
"maxsize"]->setSuggestedValue(size);
764 NET::WindowType window_type =
static_cast<NET::WindowType
>(info.value(
"type", 0).toInt());
765 if (window_type == NET::Unknown) {
766 window_type = NET::Normal;
768 m_rules[
"types"]->setSuggestedValue(1 << window_type);
770 const QString wmsimpleclass = info.value(
"resourceClass").toString();
771 const QString wmcompleteclass = QStringLiteral(
"%1 %2").arg(info.value(
"resourceName").toString(),
772 info.value(
"resourceClass").toString());
776 if (wmsimpleclass.isEmpty()) {
778 xi18nc(
"@info",
"This application is not providing a class for the window, "
779 "so KWin cannot use it to match and apply any rules. "
780 "If you still want to apply some rules to it, "
781 "try to match other properties like the window title instead.<nl/><nl/>"
782 "Please consider reporting this bug to the application's developers."));
785 m_rules[
"wmclass"]->setSuggestedValue(wmsimpleclass);
786 m_rules[
"wmclasshelper"]->setSuggestedValue(wmcompleteclass);
788#if KWIN_BUILD_ACTIVITIES
789 const QStringList activities = info.value(
"activities").toStringList();
790 m_rules[
"activity"]->setSuggestedValue(activities.isEmpty() ? QStringList{Activities::nullUuid()}
794 const auto ruleForProperty = x11PropertyHash();
795 for (QString &property : info.keys()) {
796 if (!ruleForProperty.contains(property)) {
799 const QString ruleKey = ruleForProperty.value(property, QString());
802 m_rules[ruleKey]->setSuggestedValue(info.value(property));
808QList<OptionsModel::Data> RulesModel::windowTypesModelData()
const
810 static const auto modelData = QList<OptionsModel::Data>{
813 {1 << NET::Normal, i18n(
"Normal Window"), QIcon::fromTheme(
"window")},
814 {1 << NET::Dialog, i18n(
"Dialog Window"), QIcon::fromTheme(
"window-duplicate")},
815 {1 << NET::Utility, i18n(
"Utility Window"), QIcon::fromTheme(
"dialog-object-properties")},
816 {1 << NET::Dock, i18n(
"Dock (panel)"), QIcon::fromTheme(
"list-remove")},
817 {1 << NET::Toolbar, i18n(
"Toolbar"), QIcon::fromTheme(
"tools")},
818 {1 << NET::Menu, i18n(
"Torn-Off Menu"), QIcon::fromTheme(
"overflow-menu-left")},
819 {1 << NET::Splash, i18n(
"Splash Screen"), QIcon::fromTheme(
"embosstool")},
820 {1 << NET::Desktop, i18n(
"Desktop"), QIcon::fromTheme(
"desktop")},
822 {1 << NET::TopMenu, i18n(
"Standalone Menubar"), QIcon::fromTheme(
"application-menu")},
823 {1 << NET::OnScreenDisplay, i18n(
"On Screen Display"), QIcon::fromTheme(
"osd-duplicate")}};
828QList<OptionsModel::Data> RulesModel::virtualDesktopsModelData()
const
830 QList<OptionsModel::Data> modelData;
831 modelData << OptionsModel::Data{
833 i18n(
"All Desktops"),
834 QIcon::fromTheme(
"window-pin"),
835 i18nc(
"@info:tooltip in the virtual desktop list",
"Make the window available on all desktops"),
838 for (
const DBusDesktopDataStruct &desktop : m_virtualDesktops) {
839 modelData << OptionsModel::Data{
841 QString::number(desktop.position + 1).rightJustified(2) + QStringLiteral(
": ") + desktop.name,
842 QIcon::fromTheme(
"virtual-desktops")};
847QList<OptionsModel::Data> RulesModel::activitiesModelData()
const
849#if KWIN_BUILD_ACTIVITIES
850 QList<OptionsModel::Data> modelData;
852 modelData << OptionsModel::Data{
854 i18n(
"All Activities"),
855 QIcon::fromTheme(
"activities"),
856 i18nc(
"@info:tooltip in the activity list",
"Make the window available on all activities"),
860 const auto activities = m_activities->activities(KActivities::Info::Running);
861 if (m_activities->serviceStatus() == KActivities::Consumer::Running) {
862 for (
const QString &activityId : activities) {
863 const KActivities::Info info(activityId);
864 modelData << OptionsModel::Data{activityId, info.name(), QIcon::fromTheme(info.icon())};
874QList<OptionsModel::Data> RulesModel::placementModelData()
const
876 static const auto modelData = QList<OptionsModel::Data>{
889QList<OptionsModel::Data> RulesModel::focusModelData()
const
891 static const auto modelData = QList<OptionsModel::Data>{
896 {4, i18n(
"Extreme")}};
900QList<OptionsModel::Data> RulesModel::colorSchemesModelData()
const
902 QList<OptionsModel::Data> modelData;
904 KColorSchemeManager schemes;
905 QAbstractItemModel *schemesModel = schemes.model();
908 for (
int r = 1; r < schemesModel->rowCount(); r++) {
909 const QModelIndex index = schemesModel->index(r, 0);
910 modelData << OptionsModel::Data{
911 QFileInfo(index.data(Qt::UserRole).toString()).baseName(),
912 index.data(Qt::DisplayRole).toString(),
913 index.data(Qt::DecorationRole).value<QIcon>()};
919QList<OptionsModel::Data> RulesModel::layerModelData()
const
921 static const auto modelData = QList<OptionsModel::Data>{
938 QTimer::singleShot(miliseconds,
this, &RulesModel::selectX11Window);
941void RulesModel::selectX11Window()
943 QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral(
"org.kde.KWin"),
944 QStringLiteral(
"/KWin"),
945 QStringLiteral(
"org.kde.KWin"),
946 QStringLiteral(
"queryWindowInfo"));
948 QDBusPendingReply<QVariantMap> async = QDBusConnection::sessionBus().asyncCall(message);
950 QDBusPendingCallWatcher *callWatcher =
new QDBusPendingCallWatcher(async,
this);
951 connect(callWatcher, &QDBusPendingCallWatcher::finished,
this, [
this](QDBusPendingCallWatcher *self) {
952 QDBusPendingReply<QVariantMap> reply = *self;
954 if (!reply.isValid()) {
955 if (reply.error().name() == QLatin1String(
"org.kde.KWin.Error.InvalidWindow")) {
956 Q_EMIT showErrorMessage(i18n(
"Unmanaged window"),
957 i18n(
"Could not detect window properties. The window is not managed by KWin."));
961 const QVariantMap windowInfo = reply.value();
967void RulesModel::updateVirtualDesktops()
969 QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral(
"org.kde.KWin"),
970 QStringLiteral(
"/VirtualDesktopManager"),
971 QStringLiteral(
"org.freedesktop.DBus.Properties"),
972 QStringLiteral(
"Get"));
973 message.setArguments(QVariantList{
974 QStringLiteral(
"org.kde.KWin.VirtualDesktopManager"),
975 QStringLiteral(
"desktops")});
977 QDBusPendingReply<QVariant> async = QDBusConnection::sessionBus().asyncCall(message);
979 QDBusPendingCallWatcher *callWatcher =
new QDBusPendingCallWatcher(async,
this);
980 connect(callWatcher, &QDBusPendingCallWatcher::finished,
this, [
this](QDBusPendingCallWatcher *self) {
981 QDBusPendingReply<QVariant> reply = *self;
983 if (!reply.isValid()) {
986 m_virtualDesktops = qdbus_cast<KWin::DBusDesktopDataVector>(reply.value());
987 Q_EMIT virtualDesktopsUpdated();
993#include "moc_rulesmodel.cpp"
static QString nullUuid()
QString description() const
QVariant suggestedValue() const
void setEnabled(bool enabled)
void setPolicy(int policy)
bool hasFlag(RuleItem::Flags flag) const
void setValue(QVariant value)
QVariant policyModel() const
QString policyKey() const
void setSuggestedValue(QVariant value)
void showErrorMessage(const QString &title, const QString &message)
RulesModel(QObject *parent=nullptr)
RuleSettings * settings() const
void setDescription(const QString &description)
void descriptionChanged()
QHash< int, QByteArray > 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
void virtualDesktopsUpdated()
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Q_INVOKABLE void detectWindowProperties(int miliseconds)
QStringList warningMessages
void setSuggestedProperties(const QVariantMap &info)
RuleItem * ruleItem(const QString &key) const
void warningMessagesChanged()
QModelIndex indexOf(const QString &key) const
void setSettings(RuleSettings *settings)
bool match(QList< GlobalShortcut > &shortcuts, Args... args)
@ CriticalNotificationLayer