File indexing completed on 2024-12-08 13:18:52
0001 /* 0002 SPDX-FileCopyrightText: 1999-2001 Lubos Lunak <l.lunak@kde.org> 0003 SPDX-FileCopyrightText: 2008 Michael Jansen <kde@michael-jansen.biz> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "action_data/action_data.h" 0009 #include "triggers/triggers.h" 0010 #include "windows_handler.h" 0011 #include "windows_helper/window_selection_list.h" 0012 0013 #include <KConfig> 0014 #include <KConfigGroup> 0015 #include <QDebug> 0016 0017 #include <X11/X.h> 0018 0019 namespace KHotKeys 0020 { 0021 WindowTriggerVisitor::~WindowTriggerVisitor() 0022 { 0023 } 0024 0025 WindowTrigger::WindowTrigger(ActionData *data_P, Windowdef_list *windows_P, WindowEvents window_actions_P) 0026 : Trigger(data_P) 0027 , _windows(windows_P) 0028 , window_actions(window_actions_P) 0029 , existing_windows() 0030 , last_active_window(None) 0031 , active(true) 0032 { 0033 if (!_windows) { 0034 _windows = new Windowdef_list("Windowdef_list comment"); 0035 } 0036 0037 Q_ASSERT(_windows->isEmpty()); 0038 init(); 0039 } 0040 0041 WindowTrigger::~WindowTrigger() 0042 { 0043 // qDebug() << "~WindowTrigger :" << this; 0044 disconnect(windows_handler, nullptr, this, nullptr); 0045 delete _windows; 0046 } 0047 0048 void WindowTrigger::accept(TriggerVisitor &visitor) 0049 { 0050 if (WindowTriggerVisitor *v = dynamic_cast<WindowTriggerVisitor *>(&visitor)) { 0051 v->visit(*this); 0052 } else { 0053 qDebug() << "Visitor error"; 0054 } 0055 } 0056 0057 void WindowTrigger::init() 0058 { 0059 qDebug() << "WindowTrigger::init()"; 0060 disconnect(windows_handler, nullptr, this, nullptr); 0061 connect(windows_handler, SIGNAL(window_added(WId)), this, SLOT(window_added(WId))); 0062 connect(windows_handler, SIGNAL(window_removed(WId)), this, SLOT(window_removed(WId))); 0063 if (window_actions & (WINDOW_ACTIVATES | WINDOW_DEACTIVATES /*| WINDOW_DISAPPEARS*/)) 0064 connect(windows_handler, SIGNAL(active_window_changed(WId)), this, SLOT(active_window_changed(WId))); 0065 // clang-format off 0066 connect(windows_handler, SIGNAL(window_changed(WId,uint)), this, SLOT(window_changed(WId,uint))); 0067 // clang-format on 0068 } 0069 0070 void WindowTrigger::activate(bool activate_P) 0071 { 0072 active = activate_P; 0073 } 0074 0075 void WindowTrigger::active_window_changed(WId window_P) 0076 { 0077 if (!existing_windows.contains(window_P)) { 0078 existing_windows[window_P] = windows()->match(Window_data(window_P)); 0079 } 0080 0081 if (!active || !khotkeys_active()) { 0082 // We still keep track of the last active window so we have valid data 0083 // if khotkeys is switched on again. 0084 last_active_window = window_P; 0085 return; 0086 } 0087 0088 // Check if the last active window was a match for us 0089 bool was_match = existing_windows.contains(last_active_window) ? existing_windows[last_active_window] : false; 0090 0091 if (was_match && (window_actions & WINDOW_DEACTIVATES)) { 0092 windows_handler->set_action_window(window_P); 0093 data->execute(); 0094 } 0095 0096 if (existing_windows[window_P] && (window_actions & WINDOW_ACTIVATES)) { 0097 qDebug() << "Executing data"; 0098 windows_handler->set_action_window(window_P); 0099 data->execute(); 0100 } 0101 0102 last_active_window = window_P; 0103 } 0104 0105 void WindowTrigger::cfg_write(KConfigGroup &cfg_P) const 0106 { 0107 base::cfg_write(cfg_P); 0108 KConfigGroup windowsConfig(cfg_P.config(), cfg_P.name() + "Windows"); 0109 if (windows()) { 0110 windows()->cfg_write(windowsConfig); 0111 } 0112 cfg_P.writeEntry("WindowActions", static_cast<int>(window_actions)); 0113 cfg_P.writeEntry("Type", "WINDOW"); // overwrites value set in base::cfg_write() 0114 } 0115 0116 const QString WindowTrigger::description() const 0117 { 0118 return i18n("Window trigger: ") + windows()->comment(); 0119 } 0120 0121 void WindowTrigger::setOnWindowEvents(WindowEvents events) 0122 { 0123 window_actions = events; 0124 init(); 0125 } 0126 0127 void WindowTrigger::set_window_rules(Windowdef_list *list) 0128 { 0129 delete _windows; 0130 _windows = list; 0131 } 0132 0133 bool WindowTrigger::triggers_on(window_action_t w_action_P) const 0134 { 0135 return window_actions & w_action_P; 0136 } 0137 0138 void WindowTrigger::window_added(WId window_P) 0139 { 0140 // Always keep track of windows, 0141 existing_windows[window_P] = windows()->match(Window_data(window_P)); 0142 0143 if (!active || !khotkeys_active()) { 0144 return; 0145 } 0146 0147 if (existing_windows[window_P] && (window_actions & WINDOW_APPEARS)) { 0148 windows_handler->set_action_window(window_P); 0149 data->execute(); 0150 } 0151 } 0152 0153 void WindowTrigger::window_removed(WId window_P) 0154 { 0155 // Always keep track of windows, 0156 bool matches = false; 0157 if (existing_windows.contains(window_P)) { 0158 matches = existing_windows[window_P]; 0159 existing_windows.remove(window_P); 0160 } 0161 0162 if (!active || !khotkeys_active()) { 0163 return; 0164 } 0165 0166 if (matches && (window_actions & WINDOW_DISAPPEARS)) { 0167 windows_handler->set_action_window(window_P); 0168 data->execute(); 0169 } 0170 } 0171 0172 void WindowTrigger::window_changed(WId window_P, unsigned int dirty_P) 0173 { 0174 if (!(dirty_P & (NET::WMName | NET::WMWindowType))) 0175 return; 0176 0177 // Check if the old state was a match 0178 bool was_match = false; 0179 if (existing_windows.contains(window_P)) 0180 was_match = existing_windows[window_P]; 0181 0182 // Check if the new state is a match 0183 bool matches = windows()->match(Window_data(window_P)); 0184 existing_windows[window_P] = matches; 0185 0186 if (!active || !khotkeys_active()) { 0187 return; 0188 } 0189 0190 if (matches && !was_match) { 0191 if (window_actions & WINDOW_APPEARS) { 0192 windows_handler->set_action_window(window_P); 0193 data->execute(); 0194 } else if (window_actions & WINDOW_ACTIVATES && window_P == windows_handler->active_window()) { 0195 windows_handler->set_action_window(window_P); 0196 data->execute(); 0197 } 0198 } 0199 } 0200 0201 const Windowdef_list *WindowTrigger::windows() const 0202 { 0203 return _windows; 0204 } 0205 0206 Windowdef_list *WindowTrigger::windows() 0207 { 0208 return _windows; 0209 } 0210 0211 WindowTrigger *WindowTrigger::copy(ActionData *data_P) const 0212 { 0213 WindowTrigger *ret = new WindowTrigger(data_P ? data_P : data, windows()->copy(), window_actions); 0214 ret->existing_windows = existing_windows; // CHECKME je tohle vazne treba ? 0215 return ret; 0216 } 0217 0218 } // namespace KHotKeys