File indexing completed on 2024-11-10 04:56:49
0001 /* 0002 windows.cpp 0003 0004 SPDX-FileCopyrightText: 1997 Patrick Dowler <dowler@morgul.fsh.uvic.ca> 0005 SPDX-FileCopyrightText: 2001 Waldo Bastian <bastian@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include <QApplication> 0011 #include <QCheckBox> 0012 #include <QFormLayout> 0013 #include <QGroupBox> 0014 #include <QHBoxLayout> 0015 #include <QLabel> 0016 #include <QRadioButton> 0017 #include <QScreen> 0018 #include <QtDBus> 0019 0020 #include <KConfig> 0021 #include <KConfigGroup> 0022 #include <KLocalizedString> 0023 #include <KWindowSystem> 0024 0025 #include "kwinoptions_settings.h" 0026 #include "windows.h" 0027 #include <kwin_effects_interface.h> 0028 0029 #include "kwinoptions_kdeglobals_settings.h" 0030 #include "kwinoptions_settings.h" 0031 0032 #define CLICK_TO_FOCUS 0 0033 #define CLICK_TO_FOCUS_MOUSE_PRECEDENT 1 0034 #define FOCUS_FOLLOWS_MOUSE 2 0035 #define FOCUS_FOLLOWS_MOUSE_PRECEDENT 3 0036 #define FOCUS_UNDER_MOUSE 4 0037 #define FOCUS_STRICTLY_UNDER_MOUSE 5 0038 0039 namespace 0040 { 0041 constexpr int defaultFocusPolicyIndex = CLICK_TO_FOCUS; 0042 } 0043 0044 KWinFocusConfigForm::KWinFocusConfigForm(QWidget *parent) 0045 : QWidget(parent) 0046 { 0047 setupUi(parent); 0048 } 0049 0050 KFocusConfig::KFocusConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent) 0051 : KCModule(parent, KPluginMetaData()) 0052 , standAlone(_standAlone) 0053 , m_ui(new KWinFocusConfigForm(widget())) 0054 { 0055 if (settings) { 0056 initialize(settings); 0057 } 0058 } 0059 0060 void KFocusConfig::initialize(KWinOptionsSettings *settings) 0061 { 0062 m_settings = settings; 0063 addConfig(m_settings, widget()); 0064 0065 connect(m_ui->windowFocusPolicy, qOverload<int>(&QComboBox::currentIndexChanged), this, &KFocusConfig::focusPolicyChanged); 0066 connect(m_ui->windowFocusPolicy, qOverload<int>(&QComboBox::currentIndexChanged), this, &KFocusConfig::updateDefaultIndicator); 0067 connect(this, SIGNAL(defaultsIndicatorsVisibleChanged(bool)), this, SLOT(updateDefaultIndicator())); 0068 0069 connect(qApp, &QGuiApplication::screenAdded, this, &KFocusConfig::updateMultiScreen); 0070 connect(qApp, &QGuiApplication::screenRemoved, this, &KFocusConfig::updateMultiScreen); 0071 updateMultiScreen(); 0072 } 0073 0074 void KFocusConfig::updateMultiScreen() 0075 { 0076 m_ui->multiscreenBehaviorLabel->setVisible(QApplication::screens().count() > 1); 0077 m_ui->kcfg_SeparateScreenFocus->setVisible(QApplication::screens().count() > 1); 0078 } 0079 0080 void KFocusConfig::updateDefaultIndicator() 0081 { 0082 const bool isDefault = m_ui->windowFocusPolicy->currentIndex() == defaultFocusPolicyIndex; 0083 m_ui->windowFocusPolicy->setProperty("_kde_highlight_neutral", defaultsIndicatorsVisible() && !isDefault); 0084 m_ui->windowFocusPolicy->update(); 0085 } 0086 0087 void KFocusConfig::updateFocusPolicyExplanatoryText() 0088 { 0089 const int focusPolicy = m_ui->windowFocusPolicy->currentIndex(); 0090 switch (focusPolicy) { 0091 case CLICK_TO_FOCUS: 0092 m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("<em>Click to focus:</em> A window becomes active when you click into it. This behavior is common on other operating systems and likely what you want.")); 0093 break; 0094 case CLICK_TO_FOCUS_MOUSE_PRECEDENT: 0095 m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("<em>Click to focus (mouse precedence):</em> Mostly the same as <em>Click to focus</em>. If an active window has to be chosen by the system (eg. because the currently active one was closed) the window under the mouse is the preferred candidate. Unusual, but possible variant of <em>Click to focus</em>.")); 0096 break; 0097 case FOCUS_FOLLOWS_MOUSE: 0098 m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("<em>Focus follows mouse:</em> Moving the mouse onto a window will activate it. Eg. windows randomly appearing under the mouse will not gain the focus. <em>Focus stealing prevention</em> takes place as usual. Think as <em>Click to focus</em> just without having to actually click.")); 0099 break; 0100 case FOCUS_FOLLOWS_MOUSE_PRECEDENT: 0101 m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("This is mostly the same as <em>Focus follows mouse</em>. If an active window has to be chosen by the system (eg. because the currently active one was closed) the window under the mouse is the preferred candidate. Choose this, if you want a hover controlled focus.")); 0102 break; 0103 case FOCUS_UNDER_MOUSE: 0104 m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("<em>Focus under mouse:</em> The focus always remains on the window under the mouse.<br/><strong>Warning:</strong> <em>Focus stealing prevention</em> and the <em>tabbox ('Alt+Tab')</em> contradict the activation policy and will not work. You very likely want to use <em>Focus follows mouse (mouse precedence)</em> instead!")); 0105 break; 0106 case FOCUS_STRICTLY_UNDER_MOUSE: 0107 m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("<em>Focus strictly under mouse:</em> The focus is always on the window under the mouse (in doubt nowhere) very much like the focus behavior in an unmanaged legacy X11 environment.<br/><strong>Warning:</strong> <em>Focus stealing prevention</em> and the <em>tabbox ('Alt+Tab')</em> contradict the activation policy and will not work. You very likely want to use <em>Focus follows mouse (mouse precedence)</em> instead!")); 0108 break; 0109 } 0110 } 0111 0112 void KFocusConfig::focusPolicyChanged() 0113 { 0114 int selectedFocusPolicy = 0; 0115 bool selectedNextFocusPrefersMouseItem = false; 0116 const bool loadedNextFocusPrefersMouseItem = m_settings->nextFocusPrefersMouse(); 0117 0118 updateFocusPolicyExplanatoryText(); 0119 0120 int focusPolicy = m_ui->windowFocusPolicy->currentIndex(); 0121 switch (focusPolicy) { 0122 case CLICK_TO_FOCUS: 0123 selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::ClickToFocus; 0124 break; 0125 case CLICK_TO_FOCUS_MOUSE_PRECEDENT: 0126 selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::ClickToFocus; 0127 selectedNextFocusPrefersMouseItem = true; 0128 break; 0129 case FOCUS_FOLLOWS_MOUSE: 0130 selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::FocusFollowsMouse; 0131 break; 0132 case FOCUS_FOLLOWS_MOUSE_PRECEDENT: 0133 selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::FocusFollowsMouse; 0134 selectedNextFocusPrefersMouseItem = true; 0135 break; 0136 case FOCUS_UNDER_MOUSE: 0137 selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::FocusUnderMouse; 0138 break; 0139 case FOCUS_STRICTLY_UNDER_MOUSE: 0140 selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::FocusStrictlyUnderMouse; 0141 break; 0142 } 0143 0144 unmanagedWidgetChangeState(m_settings->focusPolicy() != selectedFocusPolicy || loadedNextFocusPrefersMouseItem != selectedNextFocusPrefersMouseItem); 0145 0146 unmanagedWidgetDefaultState(focusPolicy == defaultFocusPolicyIndex); 0147 0148 // the auto raise related widgets are: autoRaise 0149 m_ui->kcfg_AutoRaise->setEnabled(focusPolicy != CLICK_TO_FOCUS && focusPolicy != CLICK_TO_FOCUS_MOUSE_PRECEDENT); 0150 0151 m_ui->kcfg_FocusStealingPreventionLevel->setDisabled(focusPolicy == FOCUS_UNDER_MOUSE || focusPolicy == FOCUS_STRICTLY_UNDER_MOUSE); 0152 0153 // the delayed focus related widgets are: delayFocus 0154 m_ui->delayFocusOnLabel->setEnabled(focusPolicy != CLICK_TO_FOCUS); 0155 m_ui->kcfg_DelayFocusInterval->setEnabled(focusPolicy != CLICK_TO_FOCUS); 0156 } 0157 0158 void KFocusConfig::load(void) 0159 { 0160 KCModule::load(); 0161 0162 const bool loadedNextFocusPrefersMouseItem = m_settings->nextFocusPrefersMouse(); 0163 0164 int focusPolicy = m_settings->focusPolicy(); 0165 0166 switch (focusPolicy) { 0167 // the ClickToFocus and FocusFollowsMouse have special values when 0168 // NextFocusPrefersMouse is true 0169 case KWinOptionsSettings::EnumFocusPolicy::ClickToFocus: 0170 m_ui->windowFocusPolicy->setCurrentIndex(CLICK_TO_FOCUS + loadedNextFocusPrefersMouseItem); 0171 break; 0172 case KWinOptionsSettings::EnumFocusPolicy::FocusFollowsMouse: 0173 m_ui->windowFocusPolicy->setCurrentIndex(FOCUS_FOLLOWS_MOUSE + loadedNextFocusPrefersMouseItem); 0174 break; 0175 default: 0176 // +2 to ignore the two special values 0177 m_ui->windowFocusPolicy->setCurrentIndex(focusPolicy + 2); 0178 break; 0179 } 0180 updateFocusPolicyExplanatoryText(); 0181 } 0182 0183 void KFocusConfig::save(void) 0184 { 0185 KCModule::save(); 0186 0187 int idxFocusPolicy = m_ui->windowFocusPolicy->currentIndex(); 0188 switch (idxFocusPolicy) { 0189 case CLICK_TO_FOCUS: 0190 case CLICK_TO_FOCUS_MOUSE_PRECEDENT: 0191 m_settings->setFocusPolicy(KWinOptionsSettings::EnumFocusPolicy::ClickToFocus); 0192 break; 0193 case FOCUS_FOLLOWS_MOUSE: 0194 case FOCUS_FOLLOWS_MOUSE_PRECEDENT: 0195 // the ClickToFocus and FocusFollowsMouse have special values when 0196 // NextFocusPrefersMouse is true 0197 m_settings->setFocusPolicy(KWinOptionsSettings::EnumFocusPolicy::FocusFollowsMouse); 0198 break; 0199 case FOCUS_UNDER_MOUSE: 0200 m_settings->setFocusPolicy(KWinOptionsSettings::EnumFocusPolicy::FocusUnderMouse); 0201 break; 0202 case FOCUS_STRICTLY_UNDER_MOUSE: 0203 m_settings->setFocusPolicy(KWinOptionsSettings::EnumFocusPolicy::FocusStrictlyUnderMouse); 0204 break; 0205 } 0206 m_settings->setNextFocusPrefersMouse(idxFocusPolicy == CLICK_TO_FOCUS_MOUSE_PRECEDENT || idxFocusPolicy == FOCUS_FOLLOWS_MOUSE_PRECEDENT); 0207 0208 m_settings->save(); 0209 0210 if (standAlone) { 0211 // Send signal to all kwin instances 0212 QDBusMessage message = 0213 QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); 0214 QDBusConnection::sessionBus().send(message); 0215 } 0216 } 0217 0218 void KFocusConfig::defaults() 0219 { 0220 KCModule::defaults(); 0221 m_ui->windowFocusPolicy->setCurrentIndex(defaultFocusPolicyIndex); 0222 } 0223 0224 KWinAdvancedConfigForm::KWinAdvancedConfigForm(QWidget *parent) 0225 : QWidget(parent) 0226 { 0227 setupUi(parent); 0228 } 0229 0230 KAdvancedConfig::KAdvancedConfig(bool _standAlone, KWinOptionsSettings *settings, KWinOptionsKDEGlobalsSettings *globalSettings, QWidget *parent) 0231 : KCModule(parent, KPluginMetaData()) 0232 , standAlone(_standAlone) 0233 , m_ui(new KWinAdvancedConfigForm(widget())) 0234 { 0235 if (settings && globalSettings) { 0236 initialize(settings, globalSettings); 0237 } 0238 } 0239 0240 void KAdvancedConfig::initialize(KWinOptionsSettings *settings, KWinOptionsKDEGlobalsSettings *globalSettings) 0241 { 0242 m_settings = settings; 0243 addConfig(m_settings, widget()); 0244 addConfig(globalSettings, widget()); 0245 0246 m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::Smart, "Smart"); 0247 m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::Maximizing, "Maximizing"); 0248 m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::Random, "Random"); 0249 m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::Centered, "Centered"); 0250 m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::ZeroCornered, "ZeroCornered"); 0251 m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::UnderMouse, "UnderMouse"); 0252 0253 // Don't show the option to prevent apps from remembering their window 0254 // positions on Wayland because it doesn't work on Wayland and the feature 0255 // will eventually be implemented in a different way there. 0256 // This option lives in the kdeglobals file because it is consumed by 0257 // kxmlgui. 0258 m_ui->kcfg_AllowKDEAppsToRememberWindowPositions->setVisible(KWindowSystem::isPlatformX11()); 0259 0260 m_ui->kcfg_ActivationDesktopPolicy->setItemData(KWinOptionsSettings::ActivationDesktopPolicyChoices::SwitchToOtherDesktop, "SwitchToOtherDesktop"); 0261 m_ui->kcfg_ActivationDesktopPolicy->setItemData(KWinOptionsSettings::ActivationDesktopPolicyChoices::BringToCurrentDesktop, "BringToCurrentDesktop"); 0262 } 0263 0264 void KAdvancedConfig::save(void) 0265 { 0266 KCModule::save(); 0267 0268 if (standAlone) { 0269 // Send signal to all kwin instances 0270 QDBusMessage message = 0271 QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); 0272 QDBusConnection::sessionBus().send(message); 0273 } 0274 } 0275 0276 KWinMovingConfigForm::KWinMovingConfigForm(QWidget *parent) 0277 : QWidget(parent) 0278 { 0279 setupUi(parent); 0280 } 0281 0282 KMovingConfig::KMovingConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent) 0283 : KCModule(parent, KPluginMetaData()) 0284 , standAlone(_standAlone) 0285 , m_ui(new KWinMovingConfigForm(widget())) 0286 { 0287 if (settings) { 0288 initialize(settings); 0289 } 0290 } 0291 0292 void KMovingConfig::initialize(KWinOptionsSettings *settings) 0293 { 0294 m_settings = settings; 0295 addConfig(m_settings, widget()); 0296 } 0297 0298 void KMovingConfig::save(void) 0299 { 0300 KCModule::save(); 0301 0302 if (standAlone) { 0303 // Send signal to all kwin instances 0304 QDBusMessage message = 0305 QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); 0306 QDBusConnection::sessionBus().send(message); 0307 } 0308 } 0309 0310 #include "moc_windows.cpp"