Changeset View
Changeset View
Standalone View
Standalone View
effects/trackmouse/trackmouse.cpp
1 | /******************************************************************** | 1 | /******************************************************************** | ||
---|---|---|---|---|---|
2 | KWin - the KDE window manager | 2 | KWin - the KDE window manager | ||
3 | This file is part of the KDE project. | 3 | This file is part of the KDE project. | ||
4 | 4 | | |||
5 | Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org> | 5 | Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org> | ||
6 | Copyright (C) 2010 Jorge Mata <matamax123@gmail.com> | 6 | Copyright (C) 2010 Jorge Mata <matamax123@gmail.com> | ||
7 | Copyright (C) 2018 Vlad Zagorodniy <vladzzag@gmail.com> | ||||
7 | 8 | | |||
8 | This program is free software; you can redistribute it and/or modify | 9 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | 10 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | 11 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | 12 | (at your option) any later version. | ||
12 | 13 | | |||
13 | This program is distributed in the hope that it will be useful, | 14 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
Show All 22 Lines | |||||
37 | #include <KLocalizedString> | 38 | #include <KLocalizedString> | ||
38 | 39 | | |||
39 | #include <math.h> | 40 | #include <math.h> | ||
40 | 41 | | |||
41 | namespace KWin | 42 | namespace KWin | ||
42 | { | 43 | { | ||
43 | 44 | | |||
44 | TrackMouseEffect::TrackMouseEffect() | 45 | TrackMouseEffect::TrackMouseEffect() | ||
45 | : m_active(false) | 46 | : m_angle(0) | ||
46 | , m_angle(0) | | |||
47 | { | 47 | { | ||
48 | initConfig<TrackMouseConfig>(); | 48 | initConfig<TrackMouseConfig>(); | ||
49 | m_texture[0] = m_texture[1] = 0; | 49 | m_texture[0] = m_texture[1] = 0; | ||
50 | #ifdef KWIN_HAVE_XRENDER_COMPOSITING | 50 | #ifdef KWIN_HAVE_XRENDER_COMPOSITING | ||
51 | m_picture[0] = m_picture[1] = 0; | 51 | m_picture[0] = m_picture[1] = 0; | ||
52 | if ( effects->compositingType() == XRenderCompositing) | 52 | if ( effects->compositingType() == XRenderCompositing) | ||
53 | m_angleBase = 1.57079632679489661923; // Pi/2 | 53 | m_angleBase = 1.57079632679489661923; // Pi/2 | ||
54 | #endif | 54 | #endif | ||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Line(s) | 86 | { | |||
102 | } else if (m_mousePolling) { | 102 | } else if (m_mousePolling) { | ||
103 | effects->stopMousePolling(); | 103 | effects->stopMousePolling(); | ||
104 | m_mousePolling = false; | 104 | m_mousePolling = false; | ||
105 | } | 105 | } | ||
106 | } | 106 | } | ||
107 | 107 | | |||
108 | void TrackMouseEffect::prePaintScreen(ScreenPrePaintData& data, int time) | 108 | void TrackMouseEffect::prePaintScreen(ScreenPrePaintData& data, int time) | ||
109 | { | 109 | { | ||
110 | if (m_active) { | | |||
111 | QTime t = QTime::currentTime(); | 110 | QTime t = QTime::currentTime(); | ||
112 | m_angle = ((t.second() % 4) * m_angleBase) + (t.msec() / 1000.0 * m_angleBase); | 111 | m_angle = ((t.second() % 4) * m_angleBase) + (t.msec() / 1000.0 * m_angleBase); | ||
113 | m_lastRect[0].moveCenter(cursorPos()); | 112 | m_lastRect[0].moveCenter(cursorPos()); | ||
114 | m_lastRect[1].moveCenter(cursorPos()); | 113 | m_lastRect[1].moveCenter(cursorPos()); | ||
115 | data.paint |= m_lastRect[0].adjusted(-1,-1,1,1); | 114 | data.paint |= m_lastRect[0].adjusted(-1,-1,1,1); | ||
116 | } | 115 | | ||
117 | effects->prePaintScreen(data, time); | 116 | effects->prePaintScreen(data, time); | ||
118 | } | 117 | } | ||
119 | 118 | | |||
120 | void TrackMouseEffect::paintScreen(int mask, QRegion region, ScreenPaintData& data) | 119 | void TrackMouseEffect::paintScreen(int mask, QRegion region, ScreenPaintData& data) | ||
121 | { | 120 | { | ||
122 | effects->paintScreen(mask, region, data); // paint normal screen | 121 | effects->paintScreen(mask, region, data); // paint normal screen | ||
123 | if (!m_active) | | |||
124 | return; | | |||
125 | 122 | | |||
126 | if ( effects->isOpenGLCompositing() && m_texture[0] && m_texture[1]) { | 123 | if ( effects->isOpenGLCompositing() && m_texture[0] && m_texture[1]) { | ||
127 | ShaderBinder binder(ShaderTrait::MapTexture); | 124 | ShaderBinder binder(ShaderTrait::MapTexture); | ||
128 | GLShader *shader(binder.shader()); | 125 | GLShader *shader(binder.shader()); | ||
129 | if (!shader) { | 126 | if (!shader) { | ||
130 | return; | 127 | return; | ||
131 | } | 128 | } | ||
132 | glEnable(GL_BLEND); | 129 | glEnable(GL_BLEND); | ||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Line(s) | 178 | for (int i = 0; i < 2; ++i) { | |||
186 | painter->drawImage(m_lastRect[i], m_image[i]); | 183 | painter->drawImage(m_lastRect[i], m_image[i]); | ||
187 | painter->restore(); | 184 | painter->restore(); | ||
188 | } | 185 | } | ||
189 | } | 186 | } | ||
190 | } | 187 | } | ||
191 | 188 | | |||
192 | void TrackMouseEffect::postPaintScreen() | 189 | void TrackMouseEffect::postPaintScreen() | ||
193 | { | 190 | { | ||
194 | if (m_active) { | | |||
195 | effects->addRepaint(m_lastRect[0].adjusted(-1,-1,1,1)); | 191 | effects->addRepaint(m_lastRect[0].adjusted(-1,-1,1,1)); | ||
196 | } | | |||
197 | effects->postPaintScreen(); | 192 | effects->postPaintScreen(); | ||
198 | } | 193 | } | ||
199 | 194 | | |||
200 | bool TrackMouseEffect::init() | 195 | bool TrackMouseEffect::init() | ||
201 | { | 196 | { | ||
202 | effects->makeOpenGLContextCurrent(); | 197 | effects->makeOpenGLContextCurrent(); | ||
203 | #ifdef KWIN_HAVE_XRENDER_COMPOSITING | 198 | #ifdef KWIN_HAVE_XRENDER_COMPOSITING | ||
204 | if (!(m_texture[0] || m_picture[0] || !m_image[0].isNull())) { | 199 | if (!(m_texture[0] || m_picture[0] || !m_image[0].isNull())) { | ||
205 | loadTexture(); | 200 | loadTexture(); | ||
206 | if (!(m_texture[0] || m_picture[0] || !m_image[0].isNull())) | 201 | if (!(m_texture[0] || m_picture[0] || !m_image[0].isNull())) | ||
207 | return false; | 202 | return false; | ||
208 | } | 203 | } | ||
209 | #else | 204 | #else | ||
210 | if (!m_texture[0] || m_image[0].isNull()) { | 205 | if (!m_texture[0] || m_image[0].isNull()) { | ||
211 | loadTexture(); | 206 | loadTexture(); | ||
212 | if (!m_texture[0] || m_image[0].isNull()) | 207 | if (!m_texture[0] || m_image[0].isNull()) | ||
213 | return false; | 208 | return false; | ||
214 | } | 209 | } | ||
215 | #endif | 210 | #endif | ||
216 | m_lastRect[0].moveCenter(cursorPos()); | 211 | m_lastRect[0].moveCenter(cursorPos()); | ||
217 | m_lastRect[1].moveCenter(cursorPos()); | 212 | m_lastRect[1].moveCenter(cursorPos()); | ||
218 | m_active = true; | | |||
219 | m_angle = 0; | 213 | m_angle = 0; | ||
220 | return true; | 214 | return true; | ||
221 | } | 215 | } | ||
222 | 216 | | |||
223 | void TrackMouseEffect::toggle() | 217 | void TrackMouseEffect::toggle() | ||
224 | { | 218 | { | ||
225 | if (m_mousePolling) | 219 | switch (m_state) { | ||
226 | return; | 220 | case State::ActivatedByModifiers: | ||
davidedmundson: One comment I forgot to save.
There's an inbalance here:
If you activate by shortcut, then… | |||||
That's totally intentional.
mouseChanged is emitted when, for example, mouse has been moved. If you press a modifier key, mouseChanged is not emitted. So, that's fine. Also, this leads to a bug in some sense, e.g. if you stop moving mouse and then release modifiers, the effect will be still active even though modifiers are not pressed anymore. zzag: > If you activate by shortcut, then pressing a modifier on and off won't disable it. But if you… | |||||
OK, that's bs. On Wayland, I suppose things are a little bit different. zzag: OK, that's bs. On Wayland, I suppose things are a little bit different. | |||||
221 | m_state = State::ActivatedByShortcut; | ||||
222 | break; | ||||
223 | | ||||
224 | case State::ActivatedByShortcut: | ||||
225 | m_state = State::Inactive; | ||||
226 | break; | ||||
227 | 227 | | |||
228 | if (m_active) { | 228 | case State::Inactive: | ||
229 | m_active = false; | 229 | if (!init()) { | ||
230 | } else if (!init()) { | | |||
231 | return; | 230 | return; | ||
232 | } | 231 | } | ||
232 | m_state = State::ActivatedByShortcut; | ||||
233 | break; | ||||
234 | | ||||
235 | default: | ||||
236 | Q_UNREACHABLE(); | ||||
237 | break; | ||||
238 | } | ||||
239 | | ||||
233 | effects->addRepaint(m_lastRect[0].adjusted(-1,-1,1,1)); | 240 | effects->addRepaint(m_lastRect[0].adjusted(-1, -1, 1, 1)); | ||
234 | } | 241 | } | ||
235 | 242 | | |||
236 | void TrackMouseEffect::slotMouseChanged(const QPoint&, const QPoint&, | 243 | void TrackMouseEffect::slotMouseChanged(const QPoint&, const QPoint&, | ||
237 | Qt::MouseButtons, Qt::MouseButtons, | 244 | Qt::MouseButtons, Qt::MouseButtons, | ||
238 | Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers) | 245 | Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers) | ||
239 | { | 246 | { | ||
240 | if (!m_mousePolling) // we didn't ask for it but maybe someone else did... | 247 | if (!m_mousePolling) { // we didn't ask for it but maybe someone else did... | ||
241 | return; | 248 | return; | ||
242 | if (m_modifiers && modifiers == m_modifiers) { | 249 | } | ||
243 | if (!m_active && !init()) { | 250 | | ||
251 | switch (m_state) { | ||||
252 | case State::ActivatedByModifiers: | ||||
253 | if (modifiers == m_modifiers) { | ||||
244 | return; | 254 | return; | ||
245 | } | 255 | } | ||
246 | effects->addRepaint(m_lastRect[0].adjusted(-1,-1,1,1)); | 256 | m_state = State::Inactive; | ||
247 | } else if (m_active) { | 257 | break; | ||
248 | m_active = false; | 258 | | ||
249 | effects->addRepaint(m_lastRect[0].adjusted(-1,-1,1,1)); | 259 | case State::ActivatedByShortcut: | ||
260 | return; | ||||
261 | | ||||
262 | case State::Inactive: | ||||
263 | if (modifiers != m_modifiers) { | ||||
264 | return; | ||||
250 | } | 265 | } | ||
266 | if (!init()) { | ||||
267 | return; | ||||
268 | } | ||||
269 | m_state = State::ActivatedByModifiers; | ||||
270 | break; | ||||
271 | | ||||
272 | default: | ||||
273 | Q_UNREACHABLE(); | ||||
274 | break; | ||||
275 | } | ||||
276 | | ||||
277 | effects->addRepaint(m_lastRect[0].adjusted(-1, -1, 1, 1)); | ||||
251 | } | 278 | } | ||
252 | 279 | | |||
253 | void TrackMouseEffect::loadTexture() | 280 | void TrackMouseEffect::loadTexture() | ||
254 | { | 281 | { | ||
255 | QString f[2] = {QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("tm_outer.png")), | 282 | QString f[2] = {QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("tm_outer.png")), | ||
256 | QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("tm_inner.png"))}; | 283 | QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("tm_inner.png"))}; | ||
257 | if (f[0].isEmpty() || f[1].isEmpty()) | 284 | if (f[0].isEmpty() || f[1].isEmpty()) | ||
258 | return; | 285 | return; | ||
Show All 16 Lines | 301 | if (effects->compositingType() == QPainterCompositing) { | |||
275 | m_image[i] = QImage(f[i]); | 302 | m_image[i] = QImage(f[i]); | ||
276 | m_lastRect[i].setSize(m_image[i].size()); | 303 | m_lastRect[i].setSize(m_image[i].size()); | ||
277 | } | 304 | } | ||
278 | } | 305 | } | ||
279 | } | 306 | } | ||
280 | 307 | | |||
281 | bool TrackMouseEffect::isActive() const | 308 | bool TrackMouseEffect::isActive() const | ||
282 | { | 309 | { | ||
283 | return m_active; | 310 | return m_state != State::Inactive; | ||
284 | } | 311 | } | ||
285 | 312 | | |||
286 | } // namespace | 313 | } // namespace |
One comment I forgot to save.
There's an inbalance here:
If you activate by shortcut, then pressing a modifier on and off won't disable it
But if you activate by modifier then toggling the shortcut will disable it
This might become an issue if a user has it bound to both meta modifier and shortcut meta+a and pressed whilst moving the mouse.
They would hit meta, activate it by modifier, press the shortcut which then turns it off, release the keys and then it would stay off even though they hit the shortcut once.
/maybe/ we actually want
case State::ActivatedByModifiers:
but it's an extreme edge case