Changeset View
Changeset View
Standalone View
Standalone View
pointer_input.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) 2013, 2016 Martin Gräßlin <mgraesslin@kde.org> | 5 | Copyright (C) 2013, 2016 Martin Gräßlin <mgraesslin@kde.org> | ||
6 | Copyright (C) 2018 Roman Gilg <subdiff@gmail.com> | ||||
6 | 7 | | |||
7 | This program is free software; you can redistribute it and/or modify | 8 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | 9 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | 10 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | 11 | (at your option) any later version. | ||
11 | 12 | | |||
12 | This program is distributed in the hope that it will be useful, | 13 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Line(s) | 127 | PointerInputRedirection::PointerInputRedirection(InputRedirection* parent) | |||
129 | , m_supportsWarping(Application::usesLibinput()) | 130 | , m_supportsWarping(Application::usesLibinput()) | ||
130 | { | 131 | { | ||
131 | } | 132 | } | ||
132 | 133 | | |||
133 | PointerInputRedirection::~PointerInputRedirection() = default; | 134 | PointerInputRedirection::~PointerInputRedirection() = default; | ||
134 | 135 | | |||
135 | void PointerInputRedirection::init() | 136 | void PointerInputRedirection::init() | ||
136 | { | 137 | { | ||
137 | Q_ASSERT(!m_inited); | 138 | Q_ASSERT(!inited()); | ||
138 | m_cursor = new CursorImage(this); | 139 | m_cursor = new CursorImage(this); | ||
139 | m_inited = true; | 140 | setInited(true); | ||
141 | InputDeviceHandler::init(); | ||||
142 | | ||||
140 | connect(m_cursor, &CursorImage::changed, kwinApp()->platform(), &Platform::cursorChanged); | 143 | connect(m_cursor, &CursorImage::changed, kwinApp()->platform(), &Platform::cursorChanged); | ||
141 | emit m_cursor->changed(); | 144 | emit m_cursor->changed(); | ||
142 | connect(workspace(), &Workspace::stackingOrderChanged, this, &PointerInputRedirection::update); | 145 | | ||
143 | connect(workspace(), &Workspace::clientMinimizedChanged, this, &PointerInputRedirection::update); | | |||
144 | connect(screens(), &Screens::changed, this, &PointerInputRedirection::updateAfterScreenChange); | 146 | connect(screens(), &Screens::changed, this, &PointerInputRedirection::updateAfterScreenChange); | ||
145 | if (waylandServer()->hasScreenLockerIntegration()) { | 147 | if (waylandServer()->hasScreenLockerIntegration()) { | ||
146 | connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, | 148 | connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, | ||
147 | [this] { | 149 | [this] { | ||
148 | waylandServer()->seat()->cancelPointerPinchGesture(); | 150 | waylandServer()->seat()->cancelPointerPinchGesture(); | ||
149 | waylandServer()->seat()->cancelPointerSwipeGesture(); | 151 | waylandServer()->seat()->cancelPointerSwipeGesture(); | ||
150 | update(); | 152 | update(); | ||
151 | } | 153 | } | ||
152 | ); | 154 | ); | ||
153 | } | 155 | } | ||
154 | connect(workspace(), &QObject::destroyed, this, [this] { m_inited = false; }); | 156 | connect(workspace(), &QObject::destroyed, this, [this] { setInited(false); }); | ||
155 | connect(waylandServer(), &QObject::destroyed, this, [this] { m_inited = false; }); | 157 | connect(waylandServer(), &QObject::destroyed, this, [this] { setInited(false); }); | ||
156 | connect(waylandServer()->seat(), &KWayland::Server::SeatInterface::dragEnded, this, | 158 | connect(waylandServer()->seat(), &KWayland::Server::SeatInterface::dragEnded, this, | ||
157 | [this] { | 159 | [this] { | ||
158 | // need to force a focused pointer change | 160 | // need to force a focused pointer change | ||
159 | waylandServer()->seat()->setFocusedPointerSurface(nullptr); | 161 | waylandServer()->seat()->setFocusedPointerSurface(nullptr); | ||
160 | setWindow(); | 162 | setFocus(nullptr); | ||
161 | update(); | 163 | update(); | ||
162 | } | 164 | } | ||
163 | ); | 165 | ); | ||
164 | connect(this, &PointerInputRedirection::internalWindowChanged, this, | | |||
165 | [this] { | | |||
166 | disconnect(m_internalWindowConnection); | | |||
167 | m_internalWindowConnection = QMetaObject::Connection(); | | |||
168 | if (internalWindow()) { | | |||
169 | m_internalWindowConnection = connect(internalWindow().data(), &QWindow::visibleChanged, this, | | |||
170 | [this] (bool visible) { | | |||
171 | if (!visible) { | | |||
172 | update(); | | |||
173 | } | | |||
174 | } | | |||
175 | ); | | |||
176 | } | | |||
177 | } | | |||
178 | ); | | |||
179 | connect(this, &PointerInputRedirection::decorationChanged, this, | | |||
180 | [this] { | | |||
181 | disconnect(m_decorationGeometryConnection); | | |||
182 | m_decorationGeometryConnection = QMetaObject::Connection(); | | |||
183 | if (decoration()) { | | |||
184 | m_decorationGeometryConnection = connect(decoration()->client(), &AbstractClient::geometryChanged, this, | | |||
185 | [this] { | | |||
186 | // ensure maximize button gets the leave event when maximizing/restore a window, see BUG 385140 | | |||
187 | const auto oldDeco = decoration(); | | |||
188 | update(); | | |||
189 | if (oldDeco && oldDeco == decoration() && !decoration()->client()->isMove() && !decoration()->client()->isResize() && !areButtonsPressed()) { | | |||
190 | // position of window did not change, we need to send HoverMotion manually | | |||
191 | const QPointF p = m_pos - decoration()->client()->pos(); | | |||
192 | QHoverEvent event(QEvent::HoverMove, p, p); | | |||
193 | QCoreApplication::instance()->sendEvent(decoration()->decoration(), &event); | | |||
194 | } | | |||
195 | }, Qt::QueuedConnection); | | |||
196 | } | | |||
197 | } | | |||
198 | ); | | |||
199 | // connect the move resize of all window | 166 | // connect the move resize of all window | ||
200 | auto setupMoveResizeConnection = [this] (AbstractClient *c) { | 167 | auto setupMoveResizeConnection = [this] (AbstractClient *c) { | ||
201 | connect(c, &AbstractClient::clientStartUserMovedResized, this, &PointerInputRedirection::updateOnStartMoveResize); | 168 | connect(c, &AbstractClient::clientStartUserMovedResized, this, &PointerInputRedirection::updateOnStartMoveResize); | ||
202 | connect(c, &AbstractClient::clientFinishUserMovedResized, this, &PointerInputRedirection::update); | 169 | connect(c, &AbstractClient::clientFinishUserMovedResized, this, &PointerInputRedirection::update); | ||
203 | }; | 170 | }; | ||
204 | const auto clients = workspace()->allClientList(); | 171 | const auto clients = workspace()->allClientList(); | ||
205 | std::for_each(clients.begin(), clients.end(), setupMoveResizeConnection); | 172 | std::for_each(clients.begin(), clients.end(), setupMoveResizeConnection); | ||
206 | connect(workspace(), &Workspace::clientAdded, this, setupMoveResizeConnection); | 173 | connect(workspace(), &Workspace::clientAdded, this, setupMoveResizeConnection); | ||
207 | connect(waylandServer(), &WaylandServer::shellClientAdded, this, setupMoveResizeConnection); | 174 | connect(waylandServer(), &WaylandServer::shellClientAdded, this, setupMoveResizeConnection); | ||
208 | 175 | | |||
209 | // warp the cursor to center of screen | 176 | // warp the cursor to center of screen | ||
210 | warp(screens()->geometry().center()); | 177 | warp(screens()->geometry().center()); | ||
211 | updateAfterScreenChange(); | 178 | updateAfterScreenChange(); | ||
212 | } | 179 | } | ||
213 | 180 | | |||
214 | void PointerInputRedirection::updateOnStartMoveResize() | 181 | void PointerInputRedirection::updateOnStartMoveResize() | ||
215 | { | 182 | { | ||
216 | breakPointerConstraints(window() ? window()->surface() : nullptr); | 183 | breakPointerConstraints(focus() ? focus()->surface() : nullptr); | ||
217 | disconnectPointerConstraintsConnection(); | 184 | disconnectPointerConstraintsConnection(); | ||
218 | setWindow(); | 185 | setFocus(nullptr); | ||
219 | waylandServer()->seat()->setFocusedPointerSurface(nullptr); | 186 | waylandServer()->seat()->setFocusedPointerSurface(nullptr); | ||
220 | } | 187 | } | ||
221 | 188 | | |||
222 | void PointerInputRedirection::updateToReset() | 189 | void PointerInputRedirection::updateToReset() | ||
223 | { | 190 | { | ||
224 | if (internalWindow()) { | 191 | if (internalWindow()) { | ||
225 | disconnect(m_internalWindowConnection); | 192 | disconnect(m_internalWindowConnection); | ||
226 | m_internalWindowConnection = QMetaObject::Connection(); | 193 | m_internalWindowConnection = QMetaObject::Connection(); | ||
227 | QEvent event(QEvent::Leave); | 194 | QEvent event(QEvent::Leave); | ||
228 | QCoreApplication::sendEvent(internalWindow().data(), &event); | 195 | QCoreApplication::sendEvent(internalWindow().data(), &event); | ||
229 | clearInternalWindow(); | 196 | setInternalWindow(nullptr); | ||
230 | } | 197 | } | ||
231 | if (decoration()) { | 198 | if (decoration()) { | ||
232 | QHoverEvent event(QEvent::HoverLeave, QPointF(), QPointF()); | 199 | QHoverEvent event(QEvent::HoverLeave, QPointF(), QPointF()); | ||
233 | QCoreApplication::instance()->sendEvent(decoration()->decoration(), &event); | 200 | QCoreApplication::instance()->sendEvent(decoration()->decoration(), &event); | ||
234 | clearDecoration(); | 201 | setDecoration(nullptr); | ||
235 | } | 202 | } | ||
236 | if (window()) { | 203 | if (focus()) { | ||
237 | if (AbstractClient *c = qobject_cast<AbstractClient*>(window().data())) { | 204 | if (AbstractClient *c = qobject_cast<AbstractClient*>(focus().data())) { | ||
238 | c->leaveEvent(); | 205 | c->leaveEvent(); | ||
239 | } | 206 | } | ||
240 | disconnect(m_windowGeometryConnection); | 207 | disconnect(m_focusGeometryConnection); | ||
241 | m_windowGeometryConnection = QMetaObject::Connection(); | 208 | m_focusGeometryConnection = QMetaObject::Connection(); | ||
242 | breakPointerConstraints(window()->surface()); | 209 | breakPointerConstraints(focus()->surface()); | ||
243 | disconnectPointerConstraintsConnection(); | 210 | disconnectPointerConstraintsConnection(); | ||
244 | setWindow(); | 211 | setFocus(nullptr); | ||
245 | } | 212 | } | ||
246 | waylandServer()->seat()->setFocusedPointerSurface(nullptr); | 213 | waylandServer()->seat()->setFocusedPointerSurface(nullptr); | ||
247 | } | 214 | } | ||
248 | 215 | | |||
249 | void PointerInputRedirection::processMotion(const QPointF &pos, uint32_t time, LibInput::Device *device) | 216 | void PointerInputRedirection::processMotion(const QPointF &pos, uint32_t time, LibInput::Device *device) | ||
250 | { | 217 | { | ||
251 | processMotion(pos, QSizeF(), QSizeF(), time, 0, device); | 218 | processMotion(pos, QSizeF(), QSizeF(), time, 0, device); | ||
252 | } | 219 | } | ||
Show All 38 Lines | 247 | private: | |||
291 | PointerInputRedirection *m_pointer; | 258 | PointerInputRedirection *m_pointer; | ||
292 | }; | 259 | }; | ||
293 | 260 | | |||
294 | int PositionUpdateBlocker::s_counter = 0; | 261 | int PositionUpdateBlocker::s_counter = 0; | ||
295 | QVector<PositionUpdateBlocker::ScheduledPosition> PositionUpdateBlocker::s_scheduledPositions; | 262 | QVector<PositionUpdateBlocker::ScheduledPosition> PositionUpdateBlocker::s_scheduledPositions; | ||
296 | 263 | | |||
297 | void PointerInputRedirection::processMotion(const QPointF &pos, const QSizeF &delta, const QSizeF &deltaNonAccelerated, uint32_t time, quint64 timeUsec, LibInput::Device *device) | 264 | void PointerInputRedirection::processMotion(const QPointF &pos, const QSizeF &delta, const QSizeF &deltaNonAccelerated, uint32_t time, quint64 timeUsec, LibInput::Device *device) | ||
298 | { | 265 | { | ||
299 | if (!m_inited) { | 266 | if (!inited()) { | ||
300 | return; | 267 | return; | ||
301 | } | 268 | } | ||
302 | if (PositionUpdateBlocker::isPositionBlocked()) { | 269 | if (PositionUpdateBlocker::isPositionBlocked()) { | ||
303 | PositionUpdateBlocker::schedulePosition(pos, delta, deltaNonAccelerated, time, timeUsec); | 270 | PositionUpdateBlocker::schedulePosition(pos, delta, deltaNonAccelerated, time, timeUsec); | ||
304 | return; | 271 | return; | ||
305 | } | 272 | } | ||
306 | 273 | | |||
307 | PositionUpdateBlocker blocker(this); | 274 | PositionUpdateBlocker blocker(this); | ||
308 | updatePosition(pos); | 275 | updatePosition(pos); | ||
309 | MouseEvent event(QEvent::MouseMove, m_pos, Qt::NoButton, m_qtButtons, | 276 | MouseEvent event(QEvent::MouseMove, m_pos, Qt::NoButton, m_qtButtons, | ||
310 | input()->keyboardModifiers(), time, | 277 | input()->keyboardModifiers(), time, | ||
311 | delta, deltaNonAccelerated, timeUsec, device); | 278 | delta, deltaNonAccelerated, timeUsec, device); | ||
312 | event.setModifiersRelevantForGlobalShortcuts(input()->modifiersRelevantForGlobalShortcuts()); | 279 | event.setModifiersRelevantForGlobalShortcuts(input()->modifiersRelevantForGlobalShortcuts()); | ||
313 | 280 | | |||
281 | update(); | ||||
314 | input()->processSpies(std::bind(&InputEventSpy::pointerEvent, std::placeholders::_1, &event)); | 282 | input()->processSpies(std::bind(&InputEventSpy::pointerEvent, std::placeholders::_1, &event)); | ||
315 | input()->processFilters(std::bind(&InputEventFilter::pointerEvent, std::placeholders::_1, &event, 0)); | 283 | input()->processFilters(std::bind(&InputEventFilter::pointerEvent, std::placeholders::_1, &event, 0)); | ||
316 | } | 284 | } | ||
317 | 285 | | |||
318 | void PointerInputRedirection::processButton(uint32_t button, InputRedirection::PointerButtonState state, uint32_t time, LibInput::Device *device) | 286 | void PointerInputRedirection::processButton(uint32_t button, InputRedirection::PointerButtonState state, uint32_t time, LibInput::Device *device) | ||
319 | { | 287 | { | ||
320 | updateButton(button, state); | | |||
321 | | ||||
322 | QEvent::Type type; | 288 | QEvent::Type type; | ||
323 | switch (state) { | 289 | switch (state) { | ||
324 | case InputRedirection::PointerButtonReleased: | 290 | case InputRedirection::PointerButtonReleased: | ||
325 | type = QEvent::MouseButtonRelease; | 291 | type = QEvent::MouseButtonRelease; | ||
326 | break; | 292 | break; | ||
327 | case InputRedirection::PointerButtonPressed: | 293 | case InputRedirection::PointerButtonPressed: | ||
328 | type = QEvent::MouseButtonPress; | 294 | type = QEvent::MouseButtonPress; | ||
295 | update(); | ||||
329 | break; | 296 | break; | ||
330 | default: | 297 | default: | ||
331 | Q_UNREACHABLE(); | 298 | Q_UNREACHABLE(); | ||
332 | return; | 299 | return; | ||
333 | } | 300 | } | ||
334 | 301 | | |||
302 | updateButton(button, state); | ||||
303 | | ||||
335 | MouseEvent event(type, m_pos, buttonToQtMouseButton(button), m_qtButtons, | 304 | MouseEvent event(type, m_pos, buttonToQtMouseButton(button), m_qtButtons, | ||
336 | input()->keyboardModifiers(), time, QSizeF(), QSizeF(), 0, device); | 305 | input()->keyboardModifiers(), time, QSizeF(), QSizeF(), 0, device); | ||
337 | event.setModifiersRelevantForGlobalShortcuts(input()->modifiersRelevantForGlobalShortcuts()); | 306 | event.setModifiersRelevantForGlobalShortcuts(input()->modifiersRelevantForGlobalShortcuts()); | ||
338 | event.setNativeButton(button); | 307 | event.setNativeButton(button); | ||
339 | 308 | | |||
340 | input()->processSpies(std::bind(&InputEventSpy::pointerEvent, std::placeholders::_1, &event)); | 309 | input()->processSpies(std::bind(&InputEventSpy::pointerEvent, std::placeholders::_1, &event)); | ||
341 | 310 | | |||
342 | if (!m_inited) { | 311 | if (!inited()) { | ||
343 | return; | 312 | return; | ||
344 | } | 313 | } | ||
345 | 314 | | |||
346 | input()->processFilters(std::bind(&InputEventFilter::pointerEvent, std::placeholders::_1, &event, button)); | 315 | input()->processFilters(std::bind(&InputEventFilter::pointerEvent, std::placeholders::_1, &event, button)); | ||
316 | | ||||
317 | if (state == InputRedirection::PointerButtonReleased) { | ||||
318 | update(); | ||||
319 | } | ||||
347 | } | 320 | } | ||
348 | 321 | | |||
349 | void PointerInputRedirection::processAxis(InputRedirection::PointerAxis axis, qreal delta, uint32_t time, LibInput::Device *device) | 322 | void PointerInputRedirection::processAxis(InputRedirection::PointerAxis axis, qreal delta, uint32_t time, LibInput::Device *device) | ||
350 | { | 323 | { | ||
351 | if (delta == 0) { | 324 | if (delta == 0) { | ||
352 | return; | 325 | return; | ||
353 | } | 326 | } | ||
327 | update(); | ||||
354 | 328 | | |||
355 | emit input()->pointerAxisChanged(axis, delta); | 329 | emit input()->pointerAxisChanged(axis, delta); | ||
356 | 330 | | |||
357 | WheelEvent wheelEvent(m_pos, delta, | 331 | WheelEvent wheelEvent(m_pos, delta, | ||
358 | (axis == InputRedirection::PointerAxisHorizontal) ? Qt::Horizontal : Qt::Vertical, | 332 | (axis == InputRedirection::PointerAxisHorizontal) ? Qt::Horizontal : Qt::Vertical, | ||
359 | m_qtButtons, input()->keyboardModifiers(), time, device); | 333 | m_qtButtons, input()->keyboardModifiers(), time, device); | ||
360 | wheelEvent.setModifiersRelevantForGlobalShortcuts(input()->modifiersRelevantForGlobalShortcuts()); | 334 | wheelEvent.setModifiersRelevantForGlobalShortcuts(input()->modifiersRelevantForGlobalShortcuts()); | ||
361 | 335 | | |||
362 | input()->processSpies(std::bind(&InputEventSpy::wheelEvent, std::placeholders::_1, &wheelEvent)); | 336 | input()->processSpies(std::bind(&InputEventSpy::wheelEvent, std::placeholders::_1, &wheelEvent)); | ||
363 | 337 | | |||
364 | if (!m_inited) { | 338 | if (!inited()) { | ||
365 | return; | 339 | return; | ||
366 | } | 340 | } | ||
367 | input()->processFilters(std::bind(&InputEventFilter::wheelEvent, std::placeholders::_1, &wheelEvent)); | 341 | input()->processFilters(std::bind(&InputEventFilter::wheelEvent, std::placeholders::_1, &wheelEvent)); | ||
368 | } | 342 | } | ||
369 | 343 | | |||
370 | void PointerInputRedirection::processSwipeGestureBegin(int fingerCount, quint32 time, KWin::LibInput::Device *device) | 344 | void PointerInputRedirection::processSwipeGestureBegin(int fingerCount, quint32 time, KWin::LibInput::Device *device) | ||
371 | { | 345 | { | ||
372 | Q_UNUSED(device) | 346 | Q_UNUSED(device) | ||
373 | if (!m_inited) { | 347 | if (!inited()) { | ||
374 | return; | 348 | return; | ||
375 | } | 349 | } | ||
376 | 350 | | |||
377 | input()->processSpies(std::bind(&InputEventSpy::swipeGestureBegin, std::placeholders::_1, fingerCount, time)); | 351 | input()->processSpies(std::bind(&InputEventSpy::swipeGestureBegin, std::placeholders::_1, fingerCount, time)); | ||
378 | input()->processFilters(std::bind(&InputEventFilter::swipeGestureBegin, std::placeholders::_1, fingerCount, time)); | 352 | input()->processFilters(std::bind(&InputEventFilter::swipeGestureBegin, std::placeholders::_1, fingerCount, time)); | ||
379 | } | 353 | } | ||
380 | 354 | | |||
381 | void PointerInputRedirection::processSwipeGestureUpdate(const QSizeF &delta, quint32 time, KWin::LibInput::Device *device) | 355 | void PointerInputRedirection::processSwipeGestureUpdate(const QSizeF &delta, quint32 time, KWin::LibInput::Device *device) | ||
382 | { | 356 | { | ||
383 | Q_UNUSED(device) | 357 | Q_UNUSED(device) | ||
384 | if (!m_inited) { | 358 | if (!inited()) { | ||
385 | return; | 359 | return; | ||
386 | } | 360 | } | ||
361 | update(); | ||||
387 | 362 | | |||
388 | input()->processSpies(std::bind(&InputEventSpy::swipeGestureUpdate, std::placeholders::_1, delta, time)); | 363 | input()->processSpies(std::bind(&InputEventSpy::swipeGestureUpdate, std::placeholders::_1, delta, time)); | ||
389 | input()->processFilters(std::bind(&InputEventFilter::swipeGestureUpdate, std::placeholders::_1, delta, time)); | 364 | input()->processFilters(std::bind(&InputEventFilter::swipeGestureUpdate, std::placeholders::_1, delta, time)); | ||
390 | } | 365 | } | ||
391 | 366 | | |||
392 | void PointerInputRedirection::processSwipeGestureEnd(quint32 time, KWin::LibInput::Device *device) | 367 | void PointerInputRedirection::processSwipeGestureEnd(quint32 time, KWin::LibInput::Device *device) | ||
393 | { | 368 | { | ||
394 | Q_UNUSED(device) | 369 | Q_UNUSED(device) | ||
395 | if (!m_inited) { | 370 | if (!inited()) { | ||
396 | return; | 371 | return; | ||
397 | } | 372 | } | ||
373 | update(); | ||||
398 | 374 | | |||
399 | input()->processSpies(std::bind(&InputEventSpy::swipeGestureEnd, std::placeholders::_1, time)); | 375 | input()->processSpies(std::bind(&InputEventSpy::swipeGestureEnd, std::placeholders::_1, time)); | ||
400 | input()->processFilters(std::bind(&InputEventFilter::swipeGestureEnd, std::placeholders::_1, time)); | 376 | input()->processFilters(std::bind(&InputEventFilter::swipeGestureEnd, std::placeholders::_1, time)); | ||
401 | } | 377 | } | ||
402 | 378 | | |||
403 | void PointerInputRedirection::processSwipeGestureCancelled(quint32 time, KWin::LibInput::Device *device) | 379 | void PointerInputRedirection::processSwipeGestureCancelled(quint32 time, KWin::LibInput::Device *device) | ||
404 | { | 380 | { | ||
405 | Q_UNUSED(device) | 381 | Q_UNUSED(device) | ||
406 | if (!m_inited) { | 382 | if (!inited()) { | ||
407 | return; | 383 | return; | ||
408 | } | 384 | } | ||
385 | update(); | ||||
409 | 386 | | |||
410 | input()->processSpies(std::bind(&InputEventSpy::swipeGestureCancelled, std::placeholders::_1, time)); | 387 | input()->processSpies(std::bind(&InputEventSpy::swipeGestureCancelled, std::placeholders::_1, time)); | ||
411 | input()->processFilters(std::bind(&InputEventFilter::swipeGestureCancelled, std::placeholders::_1, time)); | 388 | input()->processFilters(std::bind(&InputEventFilter::swipeGestureCancelled, std::placeholders::_1, time)); | ||
412 | } | 389 | } | ||
413 | 390 | | |||
414 | void PointerInputRedirection::processPinchGestureBegin(int fingerCount, quint32 time, KWin::LibInput::Device *device) | 391 | void PointerInputRedirection::processPinchGestureBegin(int fingerCount, quint32 time, KWin::LibInput::Device *device) | ||
415 | { | 392 | { | ||
416 | Q_UNUSED(device) | 393 | Q_UNUSED(device) | ||
417 | if (!m_inited) { | 394 | if (!inited()) { | ||
418 | return; | 395 | return; | ||
419 | } | 396 | } | ||
397 | update(); | ||||
420 | 398 | | |||
421 | input()->processSpies(std::bind(&InputEventSpy::pinchGestureBegin, std::placeholders::_1, fingerCount, time)); | 399 | input()->processSpies(std::bind(&InputEventSpy::pinchGestureBegin, std::placeholders::_1, fingerCount, time)); | ||
422 | input()->processFilters(std::bind(&InputEventFilter::pinchGestureBegin, std::placeholders::_1, fingerCount, time)); | 400 | input()->processFilters(std::bind(&InputEventFilter::pinchGestureBegin, std::placeholders::_1, fingerCount, time)); | ||
423 | } | 401 | } | ||
424 | 402 | | |||
425 | void PointerInputRedirection::processPinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time, KWin::LibInput::Device *device) | 403 | void PointerInputRedirection::processPinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time, KWin::LibInput::Device *device) | ||
426 | { | 404 | { | ||
427 | Q_UNUSED(device) | 405 | Q_UNUSED(device) | ||
428 | if (!m_inited) { | 406 | if (!inited()) { | ||
429 | return; | 407 | return; | ||
430 | } | 408 | } | ||
409 | update(); | ||||
431 | 410 | | |||
432 | input()->processSpies(std::bind(&InputEventSpy::pinchGestureUpdate, std::placeholders::_1, scale, angleDelta, delta, time)); | 411 | input()->processSpies(std::bind(&InputEventSpy::pinchGestureUpdate, std::placeholders::_1, scale, angleDelta, delta, time)); | ||
433 | input()->processFilters(std::bind(&InputEventFilter::pinchGestureUpdate, std::placeholders::_1, scale, angleDelta, delta, time)); | 412 | input()->processFilters(std::bind(&InputEventFilter::pinchGestureUpdate, std::placeholders::_1, scale, angleDelta, delta, time)); | ||
434 | } | 413 | } | ||
435 | 414 | | |||
436 | void PointerInputRedirection::processPinchGestureEnd(quint32 time, KWin::LibInput::Device *device) | 415 | void PointerInputRedirection::processPinchGestureEnd(quint32 time, KWin::LibInput::Device *device) | ||
437 | { | 416 | { | ||
438 | Q_UNUSED(device) | 417 | Q_UNUSED(device) | ||
439 | if (!m_inited) { | 418 | if (!inited()) { | ||
440 | return; | 419 | return; | ||
441 | } | 420 | } | ||
421 | update(); | ||||
442 | 422 | | |||
443 | input()->processSpies(std::bind(&InputEventSpy::pinchGestureEnd, std::placeholders::_1, time)); | 423 | input()->processSpies(std::bind(&InputEventSpy::pinchGestureEnd, std::placeholders::_1, time)); | ||
444 | input()->processFilters(std::bind(&InputEventFilter::pinchGestureEnd, std::placeholders::_1, time)); | 424 | input()->processFilters(std::bind(&InputEventFilter::pinchGestureEnd, std::placeholders::_1, time)); | ||
445 | } | 425 | } | ||
446 | 426 | | |||
447 | void PointerInputRedirection::processPinchGestureCancelled(quint32 time, KWin::LibInput::Device *device) | 427 | void PointerInputRedirection::processPinchGestureCancelled(quint32 time, KWin::LibInput::Device *device) | ||
448 | { | 428 | { | ||
449 | Q_UNUSED(device) | 429 | Q_UNUSED(device) | ||
450 | if (!m_inited) { | 430 | if (!inited()) { | ||
451 | return; | 431 | return; | ||
452 | } | 432 | } | ||
433 | update(); | ||||
453 | 434 | | |||
454 | input()->processSpies(std::bind(&InputEventSpy::pinchGestureCancelled, std::placeholders::_1, time)); | 435 | input()->processSpies(std::bind(&InputEventSpy::pinchGestureCancelled, std::placeholders::_1, time)); | ||
455 | input()->processFilters(std::bind(&InputEventFilter::pinchGestureCancelled, std::placeholders::_1, time)); | 436 | input()->processFilters(std::bind(&InputEventFilter::pinchGestureCancelled, std::placeholders::_1, time)); | ||
456 | } | 437 | } | ||
457 | 438 | | |||
458 | bool PointerInputRedirection::areButtonsPressed() const | 439 | bool PointerInputRedirection::areButtonsPressed() const | ||
459 | { | 440 | { | ||
460 | for (auto state : m_buttons) { | 441 | for (auto state : m_buttons) { | ||
461 | if (state == InputRedirection::PointerButtonPressed) { | 442 | if (state == InputRedirection::PointerButtonPressed) { | ||
462 | return true; | 443 | return true; | ||
463 | } | 444 | } | ||
464 | } | 445 | } | ||
465 | return false; | 446 | return false; | ||
466 | } | 447 | } | ||
467 | 448 | | |||
468 | static bool s_cursorUpdateBlocking = false; | 449 | bool PointerInputRedirection::focusUpdatesBlocked() | ||
469 | | ||||
470 | void PointerInputRedirection::update() | | |||
471 | { | 450 | { | ||
472 | if (!m_inited) { | 451 | if (!inited()) { | ||
473 | return; | 452 | return true; | ||
474 | } | 453 | } | ||
475 | if (waylandServer()->seat()->isDragPointer()) { | 454 | if (waylandServer()->seat()->isDragPointer()) { | ||
476 | // ignore during drag and drop | 455 | // ignore during drag and drop | ||
477 | return; | 456 | return true; | ||
457 | } | ||||
458 | if (waylandServer()->seat()->isTouchSequence()) { | ||||
459 | // ignore during touch operations | ||||
460 | return true; | ||||
478 | } | 461 | } | ||
479 | if (input()->isSelectingWindow()) { | 462 | if (input()->isSelectingWindow()) { | ||
480 | return; | 463 | return true; | ||
481 | } | 464 | } | ||
482 | if (areButtonsPressed()) { | 465 | if (areButtonsPressed()) { | ||
483 | return; | 466 | return true; | ||
484 | } | 467 | } | ||
485 | Toplevel *t = input()->findToplevel(m_pos.toPoint()); | 468 | return false; | ||
486 | const auto oldDeco = decoration(); | 469 | } | ||
487 | updateInternalWindow(m_pos); | 470 | | ||
488 | if (!internalWindow()) { | 471 | void PointerInputRedirection::cleanupInternalWindow(QWindow *old, QWindow *now) | ||
489 | updateDecoration(t, m_pos); | 472 | { | ||
490 | } else { | | |||
491 | updateDecoration(waylandServer()->findClient(internalWindow()), m_pos); | | |||
492 | if (decoration()) { | | |||
493 | disconnect(m_internalWindowConnection); | 473 | disconnect(m_internalWindowConnection); | ||
494 | m_internalWindowConnection = QMetaObject::Connection(); | 474 | m_internalWindowConnection = QMetaObject::Connection(); | ||
495 | QEvent event(QEvent::Leave); | 475 | | ||
496 | QCoreApplication::sendEvent(internalWindow().data(), &event); | 476 | if (old) { | ||
497 | clearInternalWindow(); | 477 | // leave internal window | ||
478 | // TODO: do this instead via Wayland protocol as below | ||||
479 | QEvent leaveEvent(QEvent::Leave); | ||||
480 | QCoreApplication::sendEvent(old, &leaveEvent); | ||||
498 | } | 481 | } | ||
482 | | ||||
483 | if (now) { | ||||
484 | m_internalWindowConnection = connect(internalWindow().data(), &QWindow::visibleChanged, this, | ||||
485 | [this] (bool visible) { | ||||
486 | if (!visible) { | ||||
487 | update(); | ||||
488 | } | ||||
489 | } | ||||
490 | ); | ||||
499 | } | 491 | } | ||
500 | if (decoration() || internalWindow()) { | | |||
501 | t = nullptr; | | |||
502 | } | 492 | } | ||
503 | if (decoration() != oldDeco) { | 493 | | ||
504 | emit decorationChanged(); | 494 | void PointerInputRedirection::cleanupDecoration(Decoration::DecoratedClientImpl *old, Decoration::DecoratedClientImpl *now) | ||
495 | { | ||||
496 | disconnect(m_decorationGeometryConnection); | ||||
497 | m_decorationGeometryConnection = QMetaObject::Connection(); | ||||
498 | workspace()->updateFocusMousePosition(position().toPoint()); | ||||
499 | | ||||
500 | if (old) { | ||||
501 | // send leave event to old decoration | ||||
502 | QHoverEvent event(QEvent::HoverLeave, QPointF(), QPointF()); | ||||
503 | QCoreApplication::instance()->sendEvent(old->decoration(), &event); | ||||
505 | } | 504 | } | ||
506 | auto oldWindow = window(); | 505 | if (!now) { | ||
507 | if (!oldWindow.isNull() && t == window().data()) { | 506 | // left decoration | ||
508 | return; | 507 | return; | ||
509 | } | 508 | } | ||
510 | auto seat = waylandServer()->seat(); | 509 | | ||
511 | // disconnect old surface | 510 | waylandServer()->seat()->setFocusedPointerSurface(nullptr); | ||
512 | if (oldWindow) { | 511 | | ||
513 | if (AbstractClient *c = qobject_cast<AbstractClient*>(oldWindow.data())) { | 512 | auto pos = m_pos - now->client()->pos(); | ||
514 | c->leaveEvent(); | 513 | QHoverEvent event(QEvent::HoverEnter, pos, pos); | ||
514 | QCoreApplication::instance()->sendEvent(now->decoration(), &event); | ||||
515 | now->client()->processDecorationMove(pos.toPoint(), m_pos.toPoint()); | ||||
516 | | ||||
517 | m_decorationGeometryConnection = connect(decoration()->client(), &AbstractClient::geometryChanged, this, | ||||
518 | [this] { | ||||
519 | // ensure maximize button gets the leave event when maximizing/restore a window, see BUG 385140 | ||||
520 | const auto oldDeco = decoration(); | ||||
521 | update(); | ||||
522 | if (oldDeco && | ||||
523 | oldDeco == decoration() && | ||||
524 | !decoration()->client()->isMove() && | ||||
525 | !decoration()->client()->isResize() && | ||||
526 | !areButtonsPressed()) { | ||||
527 | // position of window did not change, we need to send HoverMotion manually | ||||
528 | const QPointF p = m_pos - decoration()->client()->pos(); | ||||
529 | QHoverEvent event(QEvent::HoverMove, p, p); | ||||
530 | QCoreApplication::instance()->sendEvent(decoration()->decoration(), &event); | ||||
531 | } | ||||
532 | }, Qt::QueuedConnection); | ||||
515 | } | 533 | } | ||
516 | disconnect(m_windowGeometryConnection); | 534 | | ||
517 | m_windowGeometryConnection = QMetaObject::Connection(); | 535 | static bool s_cursorUpdateBlocking = false; | ||
518 | breakPointerConstraints(oldWindow->surface()); | 536 | | ||
537 | void PointerInputRedirection::focusUpdate(Toplevel *focusOld, Toplevel *focusNow) | ||||
538 | { | ||||
539 | if (AbstractClient *ac = qobject_cast<AbstractClient*>(focusOld)) { | ||||
540 | ac->leaveEvent(); | ||||
541 | breakPointerConstraints(ac->surface()); | ||||
519 | disconnectPointerConstraintsConnection(); | 542 | disconnectPointerConstraintsConnection(); | ||
520 | } | 543 | } | ||
521 | if (AbstractClient *c = qobject_cast<AbstractClient*>(t)) { | 544 | disconnect(m_focusGeometryConnection); | ||
522 | // only send enter if it wasn't on deco for the same client before | 545 | m_focusGeometryConnection = QMetaObject::Connection(); | ||
523 | if (decoration().isNull() || decoration()->client() != c) { | 546 | | ||
524 | c->enterEvent(m_pos.toPoint()); | 547 | if (AbstractClient *ac = qobject_cast<AbstractClient*>(focusNow)) { | ||
548 | ac->enterEvent(m_pos.toPoint()); | ||||
525 | workspace()->updateFocusMousePosition(m_pos.toPoint()); | 549 | workspace()->updateFocusMousePosition(m_pos.toPoint()); | ||
526 | } | 550 | } | ||
551 | | ||||
552 | auto seat = waylandServer()->seat(); | ||||
553 | if (!focusNow || !focusNow->surface() || decoration()) { | ||||
554 | // no new surface or internal window or on decoration -> cleanup | ||||
555 | warpXcbOnSurfaceLeft(nullptr); | ||||
556 | seat->setFocusedPointerSurface(nullptr); | ||||
557 | return; | ||||
558 | } | ||||
559 | | ||||
560 | if (internalWindow()) { | ||||
561 | // enter internal window | ||||
562 | // TODO: do this instead via Wayland protocol as below | ||||
563 | const auto pos = at()->pos(); | ||||
564 | QEnterEvent enterEvent(pos, pos, m_pos); | ||||
565 | QCoreApplication::sendEvent(internalWindow().data(), &enterEvent); | ||||
527 | } | 566 | } | ||
528 | if (t && t->surface()) { | 567 | | ||
529 | setWindow(t); | | |||
530 | // TODO: add convenient API to update global pos together with updating focused surface | 568 | // TODO: add convenient API to update global pos together with updating focused surface | ||
531 | warpXcbOnSurfaceLeft(t->surface()); | 569 | warpXcbOnSurfaceLeft(focusNow->surface()); | ||
570 | | ||||
571 | // TODO: why? in order to reset the cursor icon? | ||||
532 | s_cursorUpdateBlocking = true; | 572 | s_cursorUpdateBlocking = true; | ||
533 | seat->setFocusedPointerSurface(nullptr); | 573 | seat->setFocusedPointerSurface(nullptr); | ||
534 | s_cursorUpdateBlocking = false; | 574 | s_cursorUpdateBlocking = false; | ||
575 | | ||||
535 | seat->setPointerPos(m_pos.toPoint()); | 576 | seat->setPointerPos(m_pos.toPoint()); | ||
536 | seat->setFocusedPointerSurface(t->surface(), t->inputTransformation()); | 577 | seat->setFocusedPointerSurface(focusNow->surface(), focusNow->inputTransformation()); | ||
537 | m_windowGeometryConnection = connect(t, &Toplevel::geometryChanged, this, | 578 | | ||
579 | m_focusGeometryConnection = connect(focusNow, &Toplevel::geometryChanged, this, | ||||
538 | [this] { | 580 | [this] { | ||
539 | if (window().isNull()) { | 581 | // TODO: why no assert possible? | ||
582 | if (!focus()) { | ||||
540 | return; | 583 | return; | ||
541 | } | 584 | } | ||
542 | // TODO: can we check on the client instead? | 585 | // TODO: can we check on the client instead? | ||
543 | if (workspace()->getMovingClient()) { | 586 | if (workspace()->getMovingClient()) { | ||
544 | // don't update while moving | 587 | // don't update while moving | ||
545 | return; | 588 | return; | ||
546 | } | 589 | } | ||
547 | auto seat = waylandServer()->seat(); | 590 | auto seat = waylandServer()->seat(); | ||
548 | if (window().data()->surface() != seat->focusedPointerSurface()) { | 591 | if (focus()->surface() != seat->focusedPointerSurface()) { | ||
549 | return; | 592 | return; | ||
550 | } | 593 | } | ||
551 | seat->setFocusedPointerSurfaceTransformation(window().data()->inputTransformation()); | 594 | seat->setFocusedPointerSurfaceTransformation(focus()->inputTransformation()); | ||
552 | } | 595 | } | ||
553 | ); | 596 | ); | ||
554 | m_constraintsConnection = connect(window()->surface(), &KWayland::Server::SurfaceInterface::pointerConstraintsChanged, | 597 | | ||
598 | m_constraintsConnection = connect(focusNow->surface(), &KWayland::Server::SurfaceInterface::pointerConstraintsChanged, | ||||
555 | this, &PointerInputRedirection::updatePointerConstraints); | 599 | this, &PointerInputRedirection::updatePointerConstraints); | ||
556 | m_constraintsActivatedConnection = connect(workspace(), &Workspace::clientActivated, | 600 | m_constraintsActivatedConnection = connect(workspace(), &Workspace::clientActivated, | ||
557 | this, &PointerInputRedirection::updatePointerConstraints); | 601 | this, &PointerInputRedirection::updatePointerConstraints); | ||
558 | // check whether a pointer confinement/lock fires | | |||
559 | updatePointerConstraints(); | 602 | updatePointerConstraints(); | ||
560 | } else { | | |||
561 | setWindow(); | | |||
562 | warpXcbOnSurfaceLeft(nullptr); | | |||
563 | seat->setFocusedPointerSurface(nullptr); | | |||
564 | t = nullptr; | | |||
565 | } | | |||
566 | } | 603 | } | ||
567 | 604 | | |||
568 | void PointerInputRedirection::breakPointerConstraints(KWayland::Server::SurfaceInterface *surface) | 605 | void PointerInputRedirection::breakPointerConstraints(KWayland::Server::SurfaceInterface *surface) | ||
569 | { | 606 | { | ||
570 | // cancel pointer constraints | 607 | // cancel pointer constraints | ||
571 | if (surface) { | 608 | if (surface) { | ||
572 | auto c = surface->confinedPointer(); | 609 | auto c = surface->confinedPointer(); | ||
573 | if (c && c->isConfined()) { | 610 | if (c && c->isConfined()) { | ||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Line(s) | 655 | if (m_enableConstraints == set) { | |||
619 | return; | 656 | return; | ||
620 | } | 657 | } | ||
621 | m_enableConstraints = set; | 658 | m_enableConstraints = set; | ||
622 | updatePointerConstraints(); | 659 | updatePointerConstraints(); | ||
623 | } | 660 | } | ||
624 | 661 | | |||
625 | void PointerInputRedirection::updatePointerConstraints() | 662 | void PointerInputRedirection::updatePointerConstraints() | ||
626 | { | 663 | { | ||
627 | if (window().isNull()) { | 664 | if (focus().isNull()) { | ||
628 | return; | 665 | return; | ||
629 | } | 666 | } | ||
630 | const auto s = window()->surface(); | 667 | const auto s = focus()->surface(); | ||
631 | if (!s) { | 668 | if (!s) { | ||
632 | return; | 669 | return; | ||
633 | } | 670 | } | ||
634 | if (s != waylandServer()->seat()->focusedPointerSurface()) { | 671 | if (s != waylandServer()->seat()->focusedPointerSurface()) { | ||
635 | return; | 672 | return; | ||
636 | } | 673 | } | ||
637 | if (!supportsWarping()) { | 674 | if (!supportsWarping()) { | ||
638 | return; | 675 | return; | ||
639 | } | 676 | } | ||
640 | const bool canConstrain = m_enableConstraints && window() == workspace()->activeClient(); | 677 | const bool canConstrain = m_enableConstraints && focus() == workspace()->activeClient(); | ||
641 | const auto cf = s->confinedPointer(); | 678 | const auto cf = s->confinedPointer(); | ||
642 | if (cf) { | 679 | if (cf) { | ||
643 | if (cf->isConfined()) { | 680 | if (cf->isConfined()) { | ||
644 | if (!canConstrain) { | 681 | if (!canConstrain) { | ||
645 | cf->setConfined(false); | 682 | cf->setConfined(false); | ||
646 | m_confined = false; | 683 | m_confined = false; | ||
647 | disconnectConfinedPointerRegionConnection(); | 684 | disconnectConfinedPointerRegionConnection(); | ||
648 | } | 685 | } | ||
649 | return; | 686 | return; | ||
650 | } | 687 | } | ||
651 | const QRegion r = getConstraintRegion(window().data(), cf.data()); | 688 | const QRegion r = getConstraintRegion(focus().data(), cf.data()); | ||
652 | if (canConstrain && r.contains(m_pos.toPoint())) { | 689 | if (canConstrain && r.contains(m_pos.toPoint())) { | ||
653 | cf->setConfined(true); | 690 | cf->setConfined(true); | ||
654 | m_confined = true; | 691 | m_confined = true; | ||
655 | m_confinedPointerRegionConnection = connect(cf.data(), &KWayland::Server::ConfinedPointerInterface::regionChanged, this, | 692 | m_confinedPointerRegionConnection = connect(cf.data(), &KWayland::Server::ConfinedPointerInterface::regionChanged, this, | ||
656 | [this] { | 693 | [this] { | ||
657 | if (!window()) { | 694 | if (!focus()) { | ||
658 | return; | 695 | return; | ||
659 | } | 696 | } | ||
660 | const auto s = window()->surface(); | 697 | const auto s = focus()->surface(); | ||
661 | if (!s) { | 698 | if (!s) { | ||
662 | return; | 699 | return; | ||
663 | } | 700 | } | ||
664 | const auto cf = s->confinedPointer(); | 701 | const auto cf = s->confinedPointer(); | ||
665 | if (!getConstraintRegion(window().data(), cf.data()).contains(m_pos.toPoint())) { | 702 | if (!getConstraintRegion(focus().data(), cf.data()).contains(m_pos.toPoint())) { | ||
666 | // pointer no longer in confined region, break the confinement | 703 | // pointer no longer in confined region, break the confinement | ||
667 | cf->setConfined(false); | 704 | cf->setConfined(false); | ||
668 | m_confined = false; | 705 | m_confined = false; | ||
669 | } else { | 706 | } else { | ||
670 | if (!cf->isConfined()) { | 707 | if (!cf->isConfined()) { | ||
671 | cf->setConfined(true); | 708 | cf->setConfined(true); | ||
672 | m_confined = true; | 709 | m_confined = true; | ||
673 | } | 710 | } | ||
Show All 9 Lines | |||||
683 | const auto lock = s->lockedPointer(); | 720 | const auto lock = s->lockedPointer(); | ||
684 | if (lock) { | 721 | if (lock) { | ||
685 | if (lock->isLocked()) { | 722 | if (lock->isLocked()) { | ||
686 | if (!canConstrain) { | 723 | if (!canConstrain) { | ||
687 | const auto hint = lock->cursorPositionHint(); | 724 | const auto hint = lock->cursorPositionHint(); | ||
688 | lock->setLocked(false); | 725 | lock->setLocked(false); | ||
689 | m_locked = false; | 726 | m_locked = false; | ||
690 | disconnectLockedPointerAboutToBeUnboundConnection(); | 727 | disconnectLockedPointerAboutToBeUnboundConnection(); | ||
691 | if (! (hint.x() < 0 || hint.y() < 0) && window()) { | 728 | if (! (hint.x() < 0 || hint.y() < 0) && focus()) { | ||
692 | processMotion(window()->pos() - window()->clientContentPos() + hint, waylandServer()->seat()->timestamp()); | 729 | processMotion(focus()->pos() - focus()->clientContentPos() + hint, waylandServer()->seat()->timestamp()); | ||
693 | } | 730 | } | ||
694 | } | 731 | } | ||
695 | return; | 732 | return; | ||
696 | } | 733 | } | ||
697 | const QRegion r = getConstraintRegion(window().data(), lock.data()); | 734 | const QRegion r = getConstraintRegion(focus().data(), lock.data()); | ||
698 | if (canConstrain && r.contains(m_pos.toPoint())) { | 735 | if (canConstrain && r.contains(m_pos.toPoint())) { | ||
699 | lock->setLocked(true); | 736 | lock->setLocked(true); | ||
700 | m_locked = true; | 737 | m_locked = true; | ||
701 | 738 | | |||
702 | // The client might cancel pointer locking from its side by unbinding the LockedPointerInterface. | 739 | // The client might cancel pointer locking from its side by unbinding the LockedPointerInterface. | ||
703 | // In this case the cached cursor position hint must be fetched before the resource goes away | 740 | // In this case the cached cursor position hint must be fetched before the resource goes away | ||
704 | m_lockedPointerAboutToBeUnboundConnection = connect(lock.data(), &KWayland::Server::LockedPointerInterface::aboutToBeUnbound, this, | 741 | m_lockedPointerAboutToBeUnboundConnection = connect(lock.data(), &KWayland::Server::LockedPointerInterface::aboutToBeUnbound, this, | ||
705 | [this, lock]() { | 742 | [this, lock]() { | ||
706 | const auto hint = lock->cursorPositionHint(); | 743 | const auto hint = lock->cursorPositionHint(); | ||
707 | if (hint.x() < 0 || hint.y() < 0 || !window()) { | 744 | if (hint.x() < 0 || hint.y() < 0 || !focus()) { | ||
708 | return; | 745 | return; | ||
709 | } | 746 | } | ||
710 | auto globalHint = window()->pos() - window()->clientContentPos() + hint; | 747 | auto globalHint = focus()->pos() - focus()->clientContentPos() + hint; | ||
711 | 748 | | |||
712 | // When the resource finally goes away, reposition the cursor according to the hint | 749 | // When the resource finally goes away, reposition the cursor according to the hint | ||
713 | connect(lock.data(), &KWayland::Server::LockedPointerInterface::unbound, this, | 750 | connect(lock.data(), &KWayland::Server::LockedPointerInterface::unbound, this, | ||
714 | [this, globalHint]() { | 751 | [this, globalHint]() { | ||
715 | processMotion(globalHint, waylandServer()->seat()->timestamp()); | 752 | processMotion(globalHint, waylandServer()->seat()->timestamp()); | ||
716 | }); | 753 | }); | ||
717 | } | 754 | } | ||
718 | ); | 755 | ); | ||
Show All 31 Lines | 765 | { | |||
750 | } | 787 | } | ||
751 | // warp pointer to 0/0 to trigger leave events on previously focused X window | 788 | // warp pointer to 0/0 to trigger leave events on previously focused X window | ||
752 | xcb_warp_pointer(c, XCB_WINDOW_NONE, kwinApp()->x11RootWindow(), 0, 0, 0, 0, 0, 0), | 789 | xcb_warp_pointer(c, XCB_WINDOW_NONE, kwinApp()->x11RootWindow(), 0, 0, 0, 0, 0, 0), | ||
753 | xcb_flush(c); | 790 | xcb_flush(c); | ||
754 | } | 791 | } | ||
755 | 792 | | |||
756 | QPointF PointerInputRedirection::applyPointerConfinement(const QPointF &pos) const | 793 | QPointF PointerInputRedirection::applyPointerConfinement(const QPointF &pos) const | ||
757 | { | 794 | { | ||
758 | if (!window()) { | 795 | if (!focus()) { | ||
759 | return pos; | 796 | return pos; | ||
760 | } | 797 | } | ||
761 | auto s = window()->surface(); | 798 | auto s = focus()->surface(); | ||
762 | if (!s) { | 799 | if (!s) { | ||
763 | return pos; | 800 | return pos; | ||
764 | } | 801 | } | ||
765 | auto cf = s->confinedPointer(); | 802 | auto cf = s->confinedPointer(); | ||
766 | if (!cf) { | 803 | if (!cf) { | ||
767 | return pos; | 804 | return pos; | ||
768 | } | 805 | } | ||
769 | if (!cf->isConfined()) { | 806 | if (!cf->isConfined()) { | ||
770 | return pos; | 807 | return pos; | ||
771 | } | 808 | } | ||
772 | 809 | | |||
773 | const QRegion confinementRegion = getConstraintRegion(window().data(), cf.data()); | 810 | const QRegion confinementRegion = getConstraintRegion(focus().data(), cf.data()); | ||
774 | if (confinementRegion.contains(pos.toPoint())) { | 811 | if (confinementRegion.contains(pos.toPoint())) { | ||
775 | return pos; | 812 | return pos; | ||
776 | } | 813 | } | ||
777 | QPointF p = pos; | 814 | QPointF p = pos; | ||
778 | // allow either x or y to pass | 815 | // allow either x or y to pass | ||
779 | p = QPointF(m_pos.x(), pos.y()); | 816 | p = QPointF(m_pos.x(), pos.y()); | ||
780 | if (confinementRegion.contains(p.toPoint())) { | 817 | if (confinementRegion.contains(p.toPoint())) { | ||
781 | return p; | 818 | return p; | ||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Line(s) | 874 | { | |||
838 | if (supportsWarping()) { | 875 | if (supportsWarping()) { | ||
839 | kwinApp()->platform()->warpPointer(pos); | 876 | kwinApp()->platform()->warpPointer(pos); | ||
840 | processMotion(pos, waylandServer()->seat()->timestamp()); | 877 | processMotion(pos, waylandServer()->seat()->timestamp()); | ||
841 | } | 878 | } | ||
842 | } | 879 | } | ||
843 | 880 | | |||
844 | bool PointerInputRedirection::supportsWarping() const | 881 | bool PointerInputRedirection::supportsWarping() const | ||
845 | { | 882 | { | ||
846 | if (!m_inited) { | 883 | if (!inited()) { | ||
847 | return false; | 884 | return false; | ||
848 | } | 885 | } | ||
849 | if (m_supportsWarping) { | 886 | if (m_supportsWarping) { | ||
850 | return true; | 887 | return true; | ||
851 | } | 888 | } | ||
852 | if (kwinApp()->platform()->supportsPointerWarping()) { | 889 | if (kwinApp()->platform()->supportsPointerWarping()) { | ||
853 | return true; | 890 | return true; | ||
854 | } | 891 | } | ||
855 | return false; | 892 | return false; | ||
856 | } | 893 | } | ||
857 | 894 | | |||
858 | void PointerInputRedirection::updateAfterScreenChange() | 895 | void PointerInputRedirection::updateAfterScreenChange() | ||
859 | { | 896 | { | ||
860 | if (!m_inited) { | 897 | if (!inited()) { | ||
861 | return; | 898 | return; | ||
862 | } | 899 | } | ||
863 | if (screenContainsPos(m_pos)) { | 900 | if (screenContainsPos(m_pos)) { | ||
864 | // pointer still on a screen | 901 | // pointer still on a screen | ||
865 | return; | 902 | return; | ||
866 | } | 903 | } | ||
867 | // pointer no longer on a screen, reposition to closes screen | 904 | // pointer no longer on a screen, reposition to closes screen | ||
868 | const QPointF pos = screens()->geometry(screens()->number(m_pos.toPoint())).center(); | 905 | const QPointF pos = screens()->geometry(screens()->number(m_pos.toPoint())).center(); | ||
869 | // TODO: better way to get timestamps | 906 | // TODO: better way to get timestamps | ||
870 | processMotion(pos, waylandServer()->seat()->timestamp()); | 907 | processMotion(pos, waylandServer()->seat()->timestamp()); | ||
871 | } | 908 | } | ||
872 | 909 | | |||
873 | QImage PointerInputRedirection::cursorImage() const | 910 | QImage PointerInputRedirection::cursorImage() const | ||
874 | { | 911 | { | ||
875 | if (!m_inited) { | 912 | if (!inited()) { | ||
876 | return QImage(); | 913 | return QImage(); | ||
877 | } | 914 | } | ||
878 | return m_cursor->image(); | 915 | return m_cursor->image(); | ||
879 | } | 916 | } | ||
880 | 917 | | |||
881 | QPoint PointerInputRedirection::cursorHotSpot() const | 918 | QPoint PointerInputRedirection::cursorHotSpot() const | ||
882 | { | 919 | { | ||
883 | if (!m_inited) { | 920 | if (!inited()) { | ||
884 | return QPoint(); | 921 | return QPoint(); | ||
885 | } | 922 | } | ||
886 | return m_cursor->hotSpot(); | 923 | return m_cursor->hotSpot(); | ||
887 | } | 924 | } | ||
888 | 925 | | |||
889 | void PointerInputRedirection::markCursorAsRendered() | 926 | void PointerInputRedirection::markCursorAsRendered() | ||
890 | { | 927 | { | ||
891 | if (!m_inited) { | 928 | if (!inited()) { | ||
892 | return; | 929 | return; | ||
893 | } | 930 | } | ||
894 | m_cursor->markAsRendered(); | 931 | m_cursor->markAsRendered(); | ||
895 | } | 932 | } | ||
896 | 933 | | |||
934 | QPointF PointerInputRedirection::position() const | ||||
935 | { | ||||
936 | return m_pos.toPoint(); | ||||
937 | } | ||||
938 | | ||||
897 | void PointerInputRedirection::setEffectsOverrideCursor(Qt::CursorShape shape) | 939 | void PointerInputRedirection::setEffectsOverrideCursor(Qt::CursorShape shape) | ||
898 | { | 940 | { | ||
899 | if (!m_inited) { | 941 | if (!inited()) { | ||
900 | return; | 942 | return; | ||
901 | } | 943 | } | ||
902 | // current pointer focus window should get a leave event | 944 | // current pointer focus window should get a leave event | ||
903 | update(); | 945 | update(); | ||
904 | m_cursor->setEffectsOverrideCursor(shape); | 946 | m_cursor->setEffectsOverrideCursor(shape); | ||
905 | } | 947 | } | ||
906 | 948 | | |||
907 | void PointerInputRedirection::removeEffectsOverrideCursor() | 949 | void PointerInputRedirection::removeEffectsOverrideCursor() | ||
908 | { | 950 | { | ||
909 | if (!m_inited) { | 951 | if (!inited()) { | ||
910 | return; | 952 | return; | ||
911 | } | 953 | } | ||
912 | // cursor position might have changed while there was an effect in place | 954 | // cursor position might have changed while there was an effect in place | ||
913 | update(); | 955 | update(); | ||
914 | m_cursor->removeEffectsOverrideCursor(); | 956 | m_cursor->removeEffectsOverrideCursor(); | ||
915 | } | 957 | } | ||
916 | 958 | | |||
917 | void PointerInputRedirection::setWindowSelectionCursor(const QByteArray &shape) | 959 | void PointerInputRedirection::setWindowSelectionCursor(const QByteArray &shape) | ||
918 | { | 960 | { | ||
919 | if (!m_inited) { | 961 | if (!inited()) { | ||
920 | return; | 962 | return; | ||
921 | } | 963 | } | ||
922 | // send leave to current pointer focus window | 964 | // send leave to current pointer focus window | ||
923 | updateToReset(); | 965 | updateToReset(); | ||
924 | m_cursor->setWindowSelectionCursor(shape); | 966 | m_cursor->setWindowSelectionCursor(shape); | ||
925 | } | 967 | } | ||
926 | 968 | | |||
927 | void PointerInputRedirection::removeWindowSelectionCursor() | 969 | void PointerInputRedirection::removeWindowSelectionCursor() | ||
928 | { | 970 | { | ||
929 | if (!m_inited) { | 971 | if (!inited()) { | ||
930 | return; | 972 | return; | ||
931 | } | 973 | } | ||
932 | update(); | 974 | update(); | ||
933 | m_cursor->removeWindowSelectionCursor(); | 975 | m_cursor->removeWindowSelectionCursor(); | ||
934 | } | 976 | } | ||
935 | 977 | | |||
936 | CursorImage::CursorImage(PointerInputRedirection *parent) | 978 | CursorImage::CursorImage(PointerInputRedirection *parent) | ||
937 | : QObject(parent) | 979 | : QObject(parent) | ||
▲ Show 20 Lines • Show All 359 Lines • ▼ Show 20 Line(s) | 1321 | { | |||
1297 | if (workspace() && workspace()->getMovingClient()) { | 1339 | if (workspace() && workspace()->getMovingClient()) { | ||
1298 | setSource(CursorSource::MoveResize); | 1340 | setSource(CursorSource::MoveResize); | ||
1299 | return; | 1341 | return; | ||
1300 | } | 1342 | } | ||
1301 | if (!m_pointer->decoration().isNull()) { | 1343 | if (!m_pointer->decoration().isNull()) { | ||
1302 | setSource(CursorSource::Decoration); | 1344 | setSource(CursorSource::Decoration); | ||
1303 | return; | 1345 | return; | ||
1304 | } | 1346 | } | ||
1305 | if (!m_pointer->window().isNull() && waylandServer()->seat()->focusedPointer()) { | 1347 | if (!m_pointer->focus().isNull() && waylandServer()->seat()->focusedPointer()) { | ||
1306 | setSource(CursorSource::PointerSurface); | 1348 | setSource(CursorSource::PointerSurface); | ||
1307 | return; | 1349 | return; | ||
1308 | } | 1350 | } | ||
1309 | setSource(CursorSource::Fallback); | 1351 | setSource(CursorSource::Fallback); | ||
1310 | } | 1352 | } | ||
1311 | 1353 | | |||
1312 | void CursorImage::setSource(CursorSource source) | 1354 | void CursorImage::setSource(CursorSource source) | ||
1313 | { | 1355 | { | ||
▲ Show 20 Lines • Show All 56 Lines • Show Last 20 Lines |