Changeset View
Changeset View
Standalone View
Standalone View
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 Martin Gräßlin <mgraesslin@kde.org> | 5 | Copyright (C) 2013 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 208 Lines • ▼ Show 20 Line(s) | |||||
222 | public: | 223 | public: | ||
223 | bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { | 224 | bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { | ||
224 | if (!waylandServer()->isScreenLocked()) { | 225 | if (!waylandServer()->isScreenLocked()) { | ||
225 | return false; | 226 | return false; | ||
226 | } | 227 | } | ||
227 | auto seat = waylandServer()->seat(); | 228 | auto seat = waylandServer()->seat(); | ||
228 | seat->setTimestamp(event->timestamp()); | 229 | seat->setTimestamp(event->timestamp()); | ||
229 | if (event->type() == QEvent::MouseMove) { | 230 | if (event->type() == QEvent::MouseMove) { | ||
230 | input()->pointer()->update(); | | |||
231 | if (pointerSurfaceAllowed()) { | 231 | if (pointerSurfaceAllowed()) { | ||
232 | // TODO: should the pointer position always stay in sync, i.e. not do the check? | ||||
232 | seat->setPointerPos(event->screenPos().toPoint()); | 233 | seat->setPointerPos(event->screenPos().toPoint()); | ||
233 | } | 234 | } | ||
234 | } else if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) { | 235 | } else if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) { | ||
235 | if (pointerSurfaceAllowed()) { | 236 | if (pointerSurfaceAllowed()) { | ||
237 | // TODO: can we leak presses/releases here when we move the mouse in between from an allowed surface to | ||||
238 | // disallowed one or vice versa? | ||||
236 | event->type() == QEvent::MouseButtonPress ? seat->pointerButtonPressed(nativeButton) : seat->pointerButtonReleased(nativeButton); | 239 | event->type() == QEvent::MouseButtonPress ? seat->pointerButtonPressed(nativeButton) : seat->pointerButtonReleased(nativeButton); | ||
237 | } | 240 | } | ||
238 | } | 241 | } | ||
239 | return true; | 242 | return true; | ||
240 | } | 243 | } | ||
241 | bool wheelEvent(QWheelEvent *event) override { | 244 | bool wheelEvent(QWheelEvent *event) override { | ||
242 | if (!waylandServer()->isScreenLocked()) { | 245 | if (!waylandServer()->isScreenLocked()) { | ||
243 | return false; | 246 | return false; | ||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Line(s) | 256 | bool keyEvent(QKeyEvent * event) override { | |||
288 | return true; | 291 | return true; | ||
289 | } | 292 | } | ||
290 | bool touchDown(quint32 id, const QPointF &pos, quint32 time) override { | 293 | bool touchDown(quint32 id, const QPointF &pos, quint32 time) override { | ||
291 | if (!waylandServer()->isScreenLocked()) { | 294 | if (!waylandServer()->isScreenLocked()) { | ||
292 | return false; | 295 | return false; | ||
293 | } | 296 | } | ||
294 | auto seat = waylandServer()->seat(); | 297 | auto seat = waylandServer()->seat(); | ||
295 | seat->setTimestamp(time); | 298 | seat->setTimestamp(time); | ||
296 | if (!seat->isTouchSequence()) { | | |||
297 | input()->touch()->update(pos); | | |||
298 | } | | |||
299 | if (touchSurfaceAllowed()) { | 299 | if (touchSurfaceAllowed()) { | ||
300 | input()->touch()->insertId(id, seat->touchDown(pos)); | 300 | input()->touch()->insertId(id, seat->touchDown(pos)); | ||
301 | } | 301 | } | ||
302 | return true; | 302 | return true; | ||
303 | } | 303 | } | ||
304 | bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override { | 304 | bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override { | ||
305 | if (!waylandServer()->isScreenLocked()) { | 305 | if (!waylandServer()->isScreenLocked()) { | ||
306 | return false; | 306 | return false; | ||
▲ Show 20 Lines • Show All 165 Lines • ▼ Show 20 Line(s) | 471 | if (event->type() == QEvent::KeyPress) { | |||
472 | c->keyPressEvent(event->key() | event->modifiers()); | 472 | c->keyPressEvent(event->key() | event->modifiers()); | ||
473 | if (c->isMove() || c->isResize()) { | 473 | if (c->isMove() || c->isResize()) { | ||
474 | // only update if mode didn't end | 474 | // only update if mode didn't end | ||
475 | c->updateMoveResize(input()->globalPointer()); | 475 | c->updateMoveResize(input()->globalPointer()); | ||
476 | } | 476 | } | ||
477 | } | 477 | } | ||
478 | return true; | 478 | return true; | ||
479 | } | 479 | } | ||
480 | | ||||
481 | bool touchDown(quint32 id, const QPointF &pos, quint32 time) override { | ||||
482 | Q_UNUSED(id) | ||||
483 | Q_UNUSED(pos) | ||||
484 | Q_UNUSED(time) | ||||
485 | AbstractClient *c = workspace()->getMovingClient(); | ||||
486 | if (!c) { | ||||
487 | return false; | ||||
488 | } | ||||
489 | return true; | ||||
490 | } | ||||
491 | | ||||
492 | bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override { | ||||
493 | Q_UNUSED(time) | ||||
494 | AbstractClient *c = workspace()->getMovingClient(); | ||||
495 | if (!c) { | ||||
496 | return false; | ||||
497 | } | ||||
498 | if (!m_set) { | ||||
499 | m_id = id; | ||||
500 | m_set = true; | ||||
501 | } | ||||
502 | if (m_id == id) { | ||||
503 | c->updateMoveResize(pos.toPoint()); | ||||
504 | } | ||||
505 | return true; | ||||
506 | } | ||||
507 | | ||||
508 | bool touchUp(quint32 id, quint32 time) override { | ||||
509 | Q_UNUSED(time) | ||||
510 | AbstractClient *c = workspace()->getMovingClient(); | ||||
511 | if (!c) { | ||||
512 | return false; | ||||
513 | } | ||||
514 | if (m_id == id || !m_set) { | ||||
515 | c->endMoveResize(); | ||||
516 | m_set = false; | ||||
517 | // pass through to update decoration filter later on | ||||
518 | return false; | ||||
519 | } | ||||
520 | m_set = false; | ||||
521 | return true; | ||||
522 | } | ||||
523 | private: | ||||
524 | quint32 m_id = 0; | ||||
525 | bool m_set = false; | ||||
480 | }; | 526 | }; | ||
481 | 527 | | |||
482 | class WindowSelectorFilter : public InputEventFilter { | 528 | class WindowSelectorFilter : public InputEventFilter { | ||
483 | public: | 529 | public: | ||
484 | bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { | 530 | bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { | ||
485 | Q_UNUSED(nativeButton) | 531 | Q_UNUSED(nativeButton) | ||
486 | if (!m_active) { | 532 | if (!m_active) { | ||
487 | return false; | 533 | return false; | ||
▲ Show 20 Lines • Show All 271 Lines • ▼ Show 20 Line(s) | |||||
759 | 805 | | |||
760 | class InternalWindowEventFilter : public InputEventFilter { | 806 | class InternalWindowEventFilter : public InputEventFilter { | ||
761 | bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { | 807 | bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { | ||
762 | Q_UNUSED(nativeButton) | 808 | Q_UNUSED(nativeButton) | ||
763 | auto internal = input()->pointer()->internalWindow(); | 809 | auto internal = input()->pointer()->internalWindow(); | ||
764 | if (!internal) { | 810 | if (!internal) { | ||
765 | return false; | 811 | return false; | ||
766 | } | 812 | } | ||
767 | if (event->buttons() == Qt::NoButton) { | | |||
768 | // update pointer window only if no button is pressed | | |||
769 | input()->pointer()->update(); | | |||
770 | } | | |||
771 | if (!internal) { | | |||
772 | return false; | | |||
773 | } | | |||
774 | // find client | 813 | // find client | ||
775 | switch (event->type()) | 814 | switch (event->type()) | ||
776 | { | 815 | { | ||
777 | case QEvent::MouseButtonPress: | 816 | case QEvent::MouseButtonPress: | ||
778 | case QEvent::MouseButtonRelease: { | 817 | case QEvent::MouseButtonRelease: { | ||
779 | auto s = waylandServer()->findClient(internal); | 818 | auto s = waylandServer()->findClient(internal); | ||
780 | if (s && s->isDecorated()) { | 819 | if (s && s->isDecorated()) { | ||
781 | // only perform mouse commands on decorated internal windows | 820 | // only perform mouse commands on decorated internal windows | ||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Line(s) | |||||
878 | bool touchDown(quint32 id, const QPointF &pos, quint32 time) override { | 917 | bool touchDown(quint32 id, const QPointF &pos, quint32 time) override { | ||
879 | auto seat = waylandServer()->seat(); | 918 | auto seat = waylandServer()->seat(); | ||
880 | if (seat->isTouchSequence()) { | 919 | if (seat->isTouchSequence()) { | ||
881 | // something else is getting the events | 920 | // something else is getting the events | ||
882 | return false; | 921 | return false; | ||
883 | } | 922 | } | ||
884 | auto touch = input()->touch(); | 923 | auto touch = input()->touch(); | ||
885 | if (touch->internalPressId() != -1) { | 924 | if (touch->internalPressId() != -1) { | ||
886 | // already on a decoration, ignore further touch points, but filter out | 925 | // already on internal window, ignore further touch points, but filter out | ||
887 | return true; | 926 | return true; | ||
888 | } | 927 | } | ||
889 | // a new touch point | 928 | // a new touch point | ||
890 | seat->setTimestamp(time); | 929 | seat->setTimestamp(time); | ||
891 | touch->update(pos); | | |||
892 | auto internal = touch->internalWindow(); | 930 | auto internal = touch->internalWindow(); | ||
893 | if (!internal) { | 931 | if (!internal) { | ||
894 | return false; | 932 | return false; | ||
895 | } | 933 | } | ||
896 | touch->setInternalPressId(id); | 934 | touch->setInternalPressId(id); | ||
897 | // Qt's touch event API is rather complex, let's do fake mouse events instead | 935 | // Qt's touch event API is rather complex, let's do fake mouse events instead | ||
898 | m_lastGlobalTouchPos = pos; | 936 | m_lastGlobalTouchPos = pos; | ||
899 | m_lastLocalTouchPos = pos - QPointF(internal->x(), internal->y()); | 937 | m_lastLocalTouchPos = pos - QPointF(internal->x(), internal->y()); | ||
938 | | ||||
939 | QEnterEvent enterEvent(m_lastLocalTouchPos, m_lastLocalTouchPos, pos); | ||||
940 | QCoreApplication::sendEvent(internal.data(), &enterEvent); | ||||
941 | | ||||
900 | QMouseEvent e(QEvent::MouseButtonPress, m_lastLocalTouchPos, pos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers()); | 942 | QMouseEvent e(QEvent::MouseButtonPress, m_lastLocalTouchPos, pos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers()); | ||
901 | e.setAccepted(false); | 943 | e.setAccepted(false); | ||
902 | QCoreApplication::sendEvent(internal.data(), &e); | 944 | QCoreApplication::sendEvent(internal.data(), &e); | ||
903 | return true; | 945 | return true; | ||
904 | } | 946 | } | ||
905 | bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override { | 947 | bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override { | ||
906 | auto touch = input()->touch(); | 948 | auto touch = input()->touch(); | ||
907 | auto internal = touch->internalWindow(); | 949 | auto internal = touch->internalWindow(); | ||
908 | if (!internal) { | 950 | if (!internal) { | ||
909 | return false; | 951 | return false; | ||
910 | } | 952 | } | ||
911 | if (touch->internalPressId() == -1) { | 953 | if (touch->internalPressId() == -1) { | ||
912 | return false; | 954 | return false; | ||
913 | } | 955 | } | ||
914 | waylandServer()->seat()->setTimestamp(time); | 956 | waylandServer()->seat()->setTimestamp(time); | ||
915 | if (touch->internalPressId() != qint32(id)) { | 957 | if (touch->internalPressId() != qint32(id)) { | ||
916 | // ignore, but filter out | 958 | // ignore, but filter out | ||
917 | return true; | 959 | return true; | ||
918 | } | 960 | } | ||
919 | m_lastGlobalTouchPos = pos; | 961 | m_lastGlobalTouchPos = pos; | ||
920 | m_lastLocalTouchPos = pos - QPointF(internal->x(), internal->y()); | 962 | m_lastLocalTouchPos = pos - QPointF(internal->x(), internal->y()); | ||
963 | | ||||
921 | QMouseEvent e(QEvent::MouseMove, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers()); | 964 | QMouseEvent e(QEvent::MouseMove, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers()); | ||
922 | QCoreApplication::instance()->sendEvent(internal.data(), &e); | 965 | QCoreApplication::instance()->sendEvent(internal.data(), &e); | ||
923 | return true; | 966 | return true; | ||
924 | } | 967 | } | ||
925 | bool touchUp(quint32 id, quint32 time) override { | 968 | bool touchUp(quint32 id, quint32 time) override { | ||
926 | auto touch = input()->touch(); | 969 | auto touch = input()->touch(); | ||
927 | auto internal = touch->internalWindow(); | 970 | auto internal = touch->internalWindow(); | ||
928 | if (!internal) { | 971 | if (!internal) { | ||
929 | return false; | 972 | return false; | ||
930 | } | 973 | } | ||
931 | if (touch->internalPressId() == -1) { | 974 | if (touch->internalPressId() == -1) { | ||
932 | return false; | 975 | return false; | ||
933 | } | 976 | } | ||
934 | waylandServer()->seat()->setTimestamp(time); | 977 | waylandServer()->seat()->setTimestamp(time); | ||
935 | if (touch->internalPressId() != qint32(id)) { | 978 | if (touch->internalPressId() != qint32(id)) { | ||
936 | // ignore, but filter out | 979 | // ignore, but filter out | ||
937 | return true; | 980 | return true; | ||
938 | } | 981 | } | ||
939 | // send mouse up | 982 | // send mouse up | ||
940 | QMouseEvent e(QEvent::MouseButtonRelease, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::MouseButtons(), input()->keyboardModifiers()); | 983 | QMouseEvent e(QEvent::MouseButtonRelease, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::MouseButtons(), input()->keyboardModifiers()); | ||
941 | e.setAccepted(false); | 984 | e.setAccepted(false); | ||
942 | QCoreApplication::sendEvent(internal.data(), &e); | 985 | QCoreApplication::sendEvent(internal.data(), &e); | ||
943 | 986 | | |||
987 | QEvent leaveEvent(QEvent::Leave); | ||||
988 | QCoreApplication::sendEvent(internal.data(), &leaveEvent); | ||||
989 | | ||||
944 | m_lastGlobalTouchPos = QPointF(); | 990 | m_lastGlobalTouchPos = QPointF(); | ||
945 | m_lastLocalTouchPos = QPointF(); | 991 | m_lastLocalTouchPos = QPointF(); | ||
946 | input()->touch()->setInternalPressId(-1); | 992 | input()->touch()->setInternalPressId(-1); | ||
947 | return true; | 993 | return true; | ||
948 | } | 994 | } | ||
949 | private: | 995 | private: | ||
950 | QPointF m_lastGlobalTouchPos; | 996 | QPointF m_lastGlobalTouchPos; | ||
951 | QPointF m_lastLocalTouchPos; | 997 | QPointF m_lastLocalTouchPos; | ||
952 | }; | 998 | }; | ||
953 | 999 | | |||
954 | class DecorationEventFilter : public InputEventFilter { | 1000 | class DecorationEventFilter : public InputEventFilter { | ||
955 | public: | 1001 | public: | ||
956 | bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { | 1002 | bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { | ||
957 | Q_UNUSED(nativeButton) | 1003 | Q_UNUSED(nativeButton) | ||
958 | auto decoration = input()->pointer()->decoration(); | 1004 | auto decoration = input()->pointer()->decoration(); | ||
959 | if (!decoration) { | 1005 | if (!decoration) { | ||
960 | return false; | 1006 | return false; | ||
961 | } | 1007 | } | ||
962 | const QPointF p = event->globalPos() - decoration->client()->pos(); | 1008 | const QPointF p = event->globalPos() - decoration->client()->pos(); | ||
963 | switch (event->type()) { | 1009 | switch (event->type()) { | ||
964 | case QEvent::MouseMove: { | 1010 | case QEvent::MouseMove: { | ||
965 | if (event->buttons() == Qt::NoButton) { | | |||
966 | return false; | | |||
967 | } | | |||
968 | QHoverEvent e(QEvent::HoverMove, p, p); | 1011 | QHoverEvent e(QEvent::HoverMove, p, p); | ||
969 | QCoreApplication::instance()->sendEvent(decoration->decoration(), &e); | 1012 | QCoreApplication::instance()->sendEvent(decoration->decoration(), &e); | ||
970 | decoration->client()->processDecorationMove(p.toPoint(), event->globalPos()); | 1013 | decoration->client()->processDecorationMove(p.toPoint(), event->globalPos()); | ||
971 | return true; | 1014 | return true; | ||
972 | } | 1015 | } | ||
973 | case QEvent::MouseButtonPress: | 1016 | case QEvent::MouseButtonPress: | ||
974 | case QEvent::MouseButtonRelease: { | 1017 | case QEvent::MouseButtonRelease: { | ||
975 | const auto actionResult = performClientMouseAction(event, decoration->client()); | 1018 | const auto actionResult = performClientMouseAction(event, decoration->client()); | ||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Line(s) | 1070 | bool touchDown(quint32 id, const QPointF &pos, quint32 time) override { | |||
1029 | if (seat->isTouchSequence()) { | 1072 | if (seat->isTouchSequence()) { | ||
1030 | return false; | 1073 | return false; | ||
1031 | } | 1074 | } | ||
1032 | if (input()->touch()->decorationPressId() != -1) { | 1075 | if (input()->touch()->decorationPressId() != -1) { | ||
1033 | // already on a decoration, ignore further touch points, but filter out | 1076 | // already on a decoration, ignore further touch points, but filter out | ||
1034 | return true; | 1077 | return true; | ||
1035 | } | 1078 | } | ||
1036 | seat->setTimestamp(time); | 1079 | seat->setTimestamp(time); | ||
1037 | input()->touch()->update(pos); | | |||
1038 | auto decoration = input()->touch()->decoration(); | 1080 | auto decoration = input()->touch()->decoration(); | ||
1039 | if (!decoration) { | 1081 | if (!decoration) { | ||
1040 | return false; | 1082 | return false; | ||
1041 | } | 1083 | } | ||
1084 | | ||||
1042 | input()->touch()->setDecorationPressId(id); | 1085 | input()->touch()->setDecorationPressId(id); | ||
1043 | m_lastGlobalTouchPos = pos; | 1086 | m_lastGlobalTouchPos = pos; | ||
1044 | m_lastLocalTouchPos = pos - decoration->client()->pos(); | 1087 | m_lastLocalTouchPos = pos - decoration->client()->pos(); | ||
1088 | | ||||
1089 | QHoverEvent hoverEvent(QEvent::HoverMove, m_lastLocalTouchPos, m_lastLocalTouchPos); | ||||
1090 | QCoreApplication::sendEvent(decoration->decoration(), &hoverEvent); | ||||
1091 | | ||||
1045 | QMouseEvent e(QEvent::MouseButtonPress, m_lastLocalTouchPos, pos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers()); | 1092 | QMouseEvent e(QEvent::MouseButtonPress, m_lastLocalTouchPos, pos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers()); | ||
1046 | e.setAccepted(false); | 1093 | e.setAccepted(false); | ||
1047 | QCoreApplication::sendEvent(decoration->decoration(), &e); | 1094 | QCoreApplication::sendEvent(decoration->decoration(), &e); | ||
1048 | if (!e.isAccepted()) { | 1095 | if (!e.isAccepted()) { | ||
1049 | decoration->client()->processDecorationButtonPress(&e); | 1096 | decoration->client()->processDecorationButtonPress(&e); | ||
1050 | } | 1097 | } | ||
1051 | return true; | 1098 | return true; | ||
1052 | } | 1099 | } | ||
1053 | bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override { | 1100 | bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override { | ||
1054 | Q_UNUSED(time) | 1101 | Q_UNUSED(time) | ||
1055 | auto decoration = input()->touch()->decoration(); | 1102 | auto decoration = input()->touch()->decoration(); | ||
1056 | if (!decoration) { | 1103 | if (!decoration) { | ||
1057 | return false; | 1104 | return false; | ||
1058 | } | 1105 | } | ||
1059 | if (input()->touch()->decorationPressId() == -1) { | 1106 | if (input()->touch()->decorationPressId() == -1) { | ||
1060 | return false; | 1107 | return false; | ||
1061 | } | 1108 | } | ||
1062 | if (input()->touch()->decorationPressId() != qint32(id)) { | 1109 | if (input()->touch()->decorationPressId() != qint32(id)) { | ||
1063 | // ignore, but filter out | 1110 | // ignore, but filter out | ||
1064 | return true; | 1111 | return true; | ||
1065 | } | 1112 | } | ||
1066 | m_lastGlobalTouchPos = pos; | 1113 | m_lastGlobalTouchPos = pos; | ||
1067 | m_lastLocalTouchPos = pos - decoration->client()->pos(); | 1114 | m_lastLocalTouchPos = pos - decoration->client()->pos(); | ||
1068 | if (auto c = workspace()->getMovingClient()) { | 1115 | | ||
1069 | c->updateMoveResize(pos); | | |||
1070 | } else { | | |||
1071 | QHoverEvent e(QEvent::HoverMove, m_lastLocalTouchPos, m_lastLocalTouchPos); | 1116 | QHoverEvent e(QEvent::HoverMove, m_lastLocalTouchPos, m_lastLocalTouchPos); | ||
1072 | QCoreApplication::instance()->sendEvent(decoration->decoration(), &e); | 1117 | QCoreApplication::instance()->sendEvent(decoration->decoration(), &e); | ||
1073 | decoration->client()->processDecorationMove(m_lastLocalTouchPos.toPoint(), pos.toPoint()); | 1118 | decoration->client()->processDecorationMove(m_lastLocalTouchPos.toPoint(), pos.toPoint()); | ||
1074 | } | | |||
1075 | return true; | 1119 | return true; | ||
1076 | } | 1120 | } | ||
1077 | bool touchUp(quint32 id, quint32 time) override { | 1121 | bool touchUp(quint32 id, quint32 time) override { | ||
1078 | Q_UNUSED(time); | 1122 | Q_UNUSED(time); | ||
1079 | auto decoration = input()->touch()->decoration(); | 1123 | auto decoration = input()->touch()->decoration(); | ||
1080 | if (!decoration) { | 1124 | if (!decoration) { | ||
1081 | return false; | 1125 | return false; | ||
1082 | } | 1126 | } | ||
1083 | if (input()->touch()->decorationPressId() == -1) { | 1127 | if (input()->touch()->decorationPressId() == -1) { | ||
1084 | return false; | 1128 | return false; | ||
1085 | } | 1129 | } | ||
1086 | if (input()->touch()->decorationPressId() != qint32(id)) { | 1130 | if (input()->touch()->decorationPressId() != qint32(id)) { | ||
1087 | // ignore, but filter out | 1131 | // ignore, but filter out | ||
1088 | return true; | 1132 | return true; | ||
1089 | } | 1133 | } | ||
1134 | | ||||
1090 | // send mouse up | 1135 | // send mouse up | ||
1091 | if (auto c = workspace()->getMovingClient()) { | | |||
1092 | c->endMoveResize(); | | |||
1093 | } else { | | |||
1094 | QMouseEvent e(QEvent::MouseButtonRelease, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::MouseButtons(), input()->keyboardModifiers()); | 1136 | QMouseEvent e(QEvent::MouseButtonRelease, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::MouseButtons(), input()->keyboardModifiers()); | ||
1095 | e.setAccepted(false); | 1137 | e.setAccepted(false); | ||
1096 | QCoreApplication::sendEvent(decoration->decoration(), &e); | 1138 | QCoreApplication::sendEvent(decoration->decoration(), &e); | ||
1097 | decoration->client()->processDecorationButtonRelease(&e); | 1139 | decoration->client()->processDecorationButtonRelease(&e); | ||
1098 | if (input()->pointer()->decoration() == decoration) { | 1140 | | ||
1099 | // send motion to current pointer position | 1141 | QHoverEvent leaveEvent(QEvent::HoverLeave, QPointF(), QPointF()); | ||
1100 | const QPointF p = input()->pointer()->pos() - decoration->client()->pos(); | 1142 | QCoreApplication::sendEvent(decoration->decoration(), &leaveEvent); | ||
1101 | QHoverEvent event(QEvent::HoverMove, p, p); | | |||
1102 | QCoreApplication::instance()->sendEvent(decoration->decoration(), &event); | | |||
1103 | } else { | | |||
1104 | // send leave | | |||
1105 | QHoverEvent event(QEvent::HoverLeave, QPointF(), QPointF()); | | |||
1106 | QCoreApplication::instance()->sendEvent(decoration->decoration(), &event); | | |||
1107 | } | | |||
1108 | } | | |||
1109 | 1143 | | |||
1110 | m_lastGlobalTouchPos = QPointF(); | 1144 | m_lastGlobalTouchPos = QPointF(); | ||
1111 | m_lastLocalTouchPos = QPointF(); | 1145 | m_lastLocalTouchPos = QPointF(); | ||
1112 | input()->touch()->setDecorationPressId(-1); | 1146 | input()->touch()->setDecorationPressId(-1); | ||
1113 | return true; | 1147 | return true; | ||
1114 | } | 1148 | } | ||
1115 | private: | 1149 | private: | ||
1116 | QPointF m_lastGlobalTouchPos; | 1150 | QPointF m_lastGlobalTouchPos; | ||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Line(s) | |||||
1213 | class WindowActionInputFilter : public InputEventFilter | 1247 | class WindowActionInputFilter : public InputEventFilter | ||
1214 | { | 1248 | { | ||
1215 | public: | 1249 | public: | ||
1216 | bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { | 1250 | bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { | ||
1217 | Q_UNUSED(nativeButton) | 1251 | Q_UNUSED(nativeButton) | ||
1218 | if (event->type() != QEvent::MouseButtonPress) { | 1252 | if (event->type() != QEvent::MouseButtonPress) { | ||
1219 | return false; | 1253 | return false; | ||
1220 | } | 1254 | } | ||
1221 | AbstractClient *c = dynamic_cast<AbstractClient*>(input()->pointer()->window().data()); | 1255 | AbstractClient *c = dynamic_cast<AbstractClient*>(input()->pointer()->focus().data()); | ||
1222 | if (!c) { | 1256 | if (!c) { | ||
1223 | return false; | 1257 | return false; | ||
1224 | } | 1258 | } | ||
1225 | const auto actionResult = performClientMouseAction(event, c, MouseAction::ModifierAndWindow); | 1259 | const auto actionResult = performClientMouseAction(event, c, MouseAction::ModifierAndWindow); | ||
1226 | if (actionResult.first) { | 1260 | if (actionResult.first) { | ||
1227 | return actionResult.second; | 1261 | return actionResult.second; | ||
1228 | } | 1262 | } | ||
1229 | return false; | 1263 | return false; | ||
1230 | } | 1264 | } | ||
1231 | bool wheelEvent(QWheelEvent *event) override { | 1265 | bool wheelEvent(QWheelEvent *event) override { | ||
1232 | if (event->angleDelta().y() == 0) { | 1266 | if (event->angleDelta().y() == 0) { | ||
1233 | // only actions on vertical scroll | 1267 | // only actions on vertical scroll | ||
1234 | return false; | 1268 | return false; | ||
1235 | } | 1269 | } | ||
1236 | AbstractClient *c = dynamic_cast<AbstractClient*>(input()->pointer()->window().data()); | 1270 | AbstractClient *c = dynamic_cast<AbstractClient*>(input()->pointer()->focus().data()); | ||
1237 | if (!c) { | 1271 | if (!c) { | ||
1238 | return false; | 1272 | return false; | ||
1239 | } | 1273 | } | ||
1240 | const auto actionResult = performClientWheelAction(event, c, MouseAction::ModifierAndWindow); | 1274 | const auto actionResult = performClientWheelAction(event, c, MouseAction::ModifierAndWindow); | ||
1241 | if (actionResult.first) { | 1275 | if (actionResult.first) { | ||
1242 | return actionResult.second; | 1276 | return actionResult.second; | ||
1243 | } | 1277 | } | ||
1244 | return false; | 1278 | return false; | ||
1245 | } | 1279 | } | ||
1246 | bool touchDown(quint32 id, const QPointF &pos, quint32 time) override { | 1280 | bool touchDown(quint32 id, const QPointF &pos, quint32 time) override { | ||
1247 | Q_UNUSED(id) | 1281 | Q_UNUSED(id) | ||
1248 | Q_UNUSED(time) | 1282 | Q_UNUSED(time) | ||
1249 | auto seat = waylandServer()->seat(); | 1283 | auto seat = waylandServer()->seat(); | ||
1250 | if (seat->isTouchSequence()) { | 1284 | if (seat->isTouchSequence()) { | ||
1251 | return false; | 1285 | return false; | ||
1252 | } | 1286 | } | ||
1253 | input()->touch()->update(pos); | 1287 | AbstractClient *c = dynamic_cast<AbstractClient*>(input()->touch()->focus().data()); | ||
1254 | AbstractClient *c = dynamic_cast<AbstractClient*>(input()->touch()->window().data()); | | |||
1255 | if (!c) { | 1288 | if (!c) { | ||
1256 | return false; | 1289 | return false; | ||
1257 | } | 1290 | } | ||
1258 | bool wasAction = false; | 1291 | bool wasAction = false; | ||
1259 | const Options::MouseCommand command = c->getMouseCommand(Qt::LeftButton, &wasAction); | 1292 | const Options::MouseCommand command = c->getMouseCommand(Qt::LeftButton, &wasAction); | ||
1260 | if (wasAction) { | 1293 | if (wasAction) { | ||
1261 | return !c->performMouseCommand(command, pos.toPoint()); | 1294 | return !c->performMouseCommand(command, pos.toPoint()); | ||
1262 | } | 1295 | } | ||
1263 | return false; | 1296 | return false; | ||
1264 | } | 1297 | } | ||
1265 | }; | 1298 | }; | ||
1266 | 1299 | | |||
1267 | /** | 1300 | /** | ||
1268 | * The remaining default input filter which forwards events to other windows | 1301 | * The remaining default input filter which forwards events to other windows | ||
1269 | **/ | 1302 | **/ | ||
1270 | class ForwardInputFilter : public InputEventFilter | 1303 | class ForwardInputFilter : public InputEventFilter | ||
1271 | { | 1304 | { | ||
1272 | public: | 1305 | public: | ||
1273 | bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { | 1306 | bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { | ||
1274 | auto seat = waylandServer()->seat(); | 1307 | auto seat = waylandServer()->seat(); | ||
1275 | seat->setTimestamp(event->timestamp()); | 1308 | seat->setTimestamp(event->timestamp()); | ||
1276 | switch (event->type()) { | 1309 | switch (event->type()) { | ||
1277 | case QEvent::MouseMove: { | 1310 | case QEvent::MouseMove: { | ||
1278 | if (event->buttons() == Qt::NoButton) { | | |||
1279 | // update pointer window only if no button is pressed | | |||
1280 | input()->pointer()->update(); | | |||
1281 | input()->pointer()->updatePointerConstraints(); | | |||
1282 | } | | |||
1283 | seat->setPointerPos(event->globalPos()); | 1311 | seat->setPointerPos(event->globalPos()); | ||
1284 | MouseEvent *e = static_cast<MouseEvent*>(event); | 1312 | MouseEvent *e = static_cast<MouseEvent*>(event); | ||
1285 | if (e->delta() != QSizeF()) { | 1313 | if (e->delta() != QSizeF()) { | ||
1286 | seat->relativePointerMotion(e->delta(), e->deltaUnaccelerated(), e->timestampMicroseconds()); | 1314 | seat->relativePointerMotion(e->delta(), e->deltaUnaccelerated(), e->timestampMicroseconds()); | ||
1287 | } | 1315 | } | ||
1288 | break; | 1316 | break; | ||
1289 | } | 1317 | } | ||
1290 | case QEvent::MouseButtonPress: | 1318 | case QEvent::MouseButtonPress: | ||
1291 | seat->pointerButtonPressed(nativeButton); | 1319 | seat->pointerButtonPressed(nativeButton); | ||
1292 | break; | 1320 | break; | ||
1293 | case QEvent::MouseButtonRelease: | 1321 | case QEvent::MouseButtonRelease: | ||
1294 | seat->pointerButtonReleased(nativeButton); | 1322 | seat->pointerButtonReleased(nativeButton); | ||
1295 | if (event->buttons() == Qt::NoButton) { | | |||
1296 | input()->pointer()->update(); | | |||
1297 | } | | |||
1298 | break; | 1323 | break; | ||
1299 | default: | 1324 | default: | ||
1300 | break; | 1325 | break; | ||
1301 | } | 1326 | } | ||
1302 | return true; | 1327 | return true; | ||
1303 | } | 1328 | } | ||
1304 | bool wheelEvent(QWheelEvent *event) override { | 1329 | bool wheelEvent(QWheelEvent *event) override { | ||
1305 | auto seat = waylandServer()->seat(); | 1330 | auto seat = waylandServer()->seat(); | ||
Show All 17 Lines | 1336 | bool keyEvent(QKeyEvent *event) override { | |||
1323 | return true; | 1348 | return true; | ||
1324 | } | 1349 | } | ||
1325 | bool touchDown(quint32 id, const QPointF &pos, quint32 time) override { | 1350 | bool touchDown(quint32 id, const QPointF &pos, quint32 time) override { | ||
1326 | if (!workspace()) { | 1351 | if (!workspace()) { | ||
1327 | return false; | 1352 | return false; | ||
1328 | } | 1353 | } | ||
1329 | auto seat = waylandServer()->seat(); | 1354 | auto seat = waylandServer()->seat(); | ||
1330 | seat->setTimestamp(time); | 1355 | seat->setTimestamp(time); | ||
1331 | if (!seat->isTouchSequence()) { | | |||
1332 | input()->touch()->update(pos); | | |||
1333 | } | | |||
1334 | input()->touch()->insertId(id, seat->touchDown(pos)); | 1356 | input()->touch()->insertId(id, seat->touchDown(pos)); | ||
1335 | return true; | 1357 | return true; | ||
1336 | } | 1358 | } | ||
1337 | bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override { | 1359 | bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override { | ||
1338 | if (!workspace()) { | 1360 | if (!workspace()) { | ||
1339 | return false; | 1361 | return false; | ||
1340 | } | 1362 | } | ||
1341 | auto seat = waylandServer()->seat(); | 1363 | auto seat = waylandServer()->seat(); | ||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Line(s) | 1462 | bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { | |||
1442 | if (!seat->isDragPointer()) { | 1464 | if (!seat->isDragPointer()) { | ||
1443 | return false; | 1465 | return false; | ||
1444 | } | 1466 | } | ||
1445 | seat->setTimestamp(event->timestamp()); | 1467 | seat->setTimestamp(event->timestamp()); | ||
1446 | switch (event->type()) { | 1468 | switch (event->type()) { | ||
1447 | case QEvent::MouseMove: { | 1469 | case QEvent::MouseMove: { | ||
1448 | const auto pos = input()->globalPointer(); | 1470 | const auto pos = input()->globalPointer(); | ||
1449 | seat->setPointerPos(pos); | 1471 | seat->setPointerPos(pos); | ||
1450 | if (Toplevel *t = input()->findToplevel(pos.toPoint())) { | 1472 | if (Toplevel *t = input()->pointer()->at()) { | ||
1451 | // TODO: consider decorations | 1473 | // TODO: consider decorations | ||
1452 | if (t->surface() != seat->dragSurface()) { | 1474 | if (t->surface() != seat->dragSurface()) { | ||
1453 | if (AbstractClient *c = qobject_cast<AbstractClient*>(t)) { | 1475 | if (AbstractClient *c = qobject_cast<AbstractClient*>(t)) { | ||
1454 | workspace()->activateClient(c); | 1476 | workspace()->activateClient(c); | ||
1455 | } | 1477 | } | ||
1456 | seat->setDragTarget(t->surface(), t->inputTransformation()); | 1478 | seat->setDragTarget(t->surface(), t->inputTransformation()); | ||
1457 | } | 1479 | } | ||
1458 | } else { | 1480 | } else { | ||
▲ Show 20 Lines • Show All 206 Lines • ▼ Show 20 Line(s) | 1676 | { | |||
1665 | } | 1687 | } | ||
1666 | installInputEventFilter(new ScreenEdgeInputFilter); | 1688 | installInputEventFilter(new ScreenEdgeInputFilter); | ||
1667 | installInputEventFilter(new EffectsFilter); | 1689 | installInputEventFilter(new EffectsFilter); | ||
1668 | installInputEventFilter(new MoveResizeFilter); | 1690 | installInputEventFilter(new MoveResizeFilter); | ||
1669 | #ifdef KWIN_BUILD_TABBOX | 1691 | #ifdef KWIN_BUILD_TABBOX | ||
1670 | installInputEventFilter(new TabBoxInputFilter); | 1692 | installInputEventFilter(new TabBoxInputFilter); | ||
1671 | #endif | 1693 | #endif | ||
1672 | installInputEventFilter(new GlobalShortcutFilter); | 1694 | installInputEventFilter(new GlobalShortcutFilter); | ||
1673 | installInputEventFilter(new InternalWindowEventFilter); | | |||
1674 | installInputEventFilter(new DecorationEventFilter); | 1695 | installInputEventFilter(new DecorationEventFilter); | ||
1696 | installInputEventFilter(new InternalWindowEventFilter); | ||||
1675 | if (waylandServer()) { | 1697 | if (waylandServer()) { | ||
1676 | installInputEventFilter(new WindowActionInputFilter); | 1698 | installInputEventFilter(new WindowActionInputFilter); | ||
1677 | installInputEventFilter(new ForwardInputFilter); | 1699 | installInputEventFilter(new ForwardInputFilter); | ||
1678 | } | 1700 | } | ||
1679 | } | 1701 | } | ||
1680 | 1702 | | |||
1681 | void InputRedirection::reconfigure() | 1703 | void InputRedirection::reconfigure() | ||
1682 | { | 1704 | { | ||
▲ Show 20 Lines • Show All 395 Lines • ▼ Show 20 Line(s) | |||||
2078 | 2100 | | |||
2079 | InputDeviceHandler::InputDeviceHandler(InputRedirection *input) | 2101 | InputDeviceHandler::InputDeviceHandler(InputRedirection *input) | ||
2080 | : QObject(input) | 2102 | : QObject(input) | ||
2081 | { | 2103 | { | ||
2082 | } | 2104 | } | ||
2083 | 2105 | | |||
2084 | InputDeviceHandler::~InputDeviceHandler() = default; | 2106 | InputDeviceHandler::~InputDeviceHandler() = default; | ||
2085 | 2107 | | |||
2086 | void InputDeviceHandler::updateDecoration(Toplevel *t, const QPointF &pos) | 2108 | void InputDeviceHandler::init() | ||
2087 | { | 2109 | { | ||
2088 | const auto oldDeco = m_decoration; | 2110 | connect(workspace(), &Workspace::stackingOrderChanged, this, &InputDeviceHandler::update); | ||
2089 | bool needsReset = waylandServer()->isScreenLocked(); | 2111 | connect(workspace(), &Workspace::clientMinimizedChanged, this, &InputDeviceHandler::update); | ||
2090 | if (AbstractClient *c = dynamic_cast<AbstractClient*>(t)) { | 2112 | connect(VirtualDesktopManager::self(), &VirtualDesktopManager::currentChanged, this, &InputDeviceHandler::update); | ||
2091 | // check whether it's on a Decoration | | |||
2092 | if (c->decoratedClient()) { | | |||
2093 | const QRect clientRect = QRect(c->clientPos(), c->clientSize()).translated(c->pos()); | | |||
2094 | if (!clientRect.contains(pos.toPoint())) { | | |||
2095 | m_decoration = c->decoratedClient(); | | |||
2096 | } else { | | |||
2097 | needsReset = true; | | |||
2098 | } | 2113 | } | ||
2099 | } else { | 2114 | | ||
2100 | needsReset = true; | 2115 | bool InputDeviceHandler::setAt(Toplevel *toplevel) | ||
2116 | { | ||||
2117 | if (m_at == toplevel) { | ||||
2118 | return false; | ||||
2101 | } | 2119 | } | ||
2102 | } else { | 2120 | auto old = m_at; | ||
2103 | needsReset = true; | 2121 | m_at = toplevel; | ||
2122 | emit atChanged(old, toplevel); | ||||
2123 | return true; | ||||
2124 | } | ||||
2125 | | ||||
2126 | void InputDeviceHandler::setFocus(Toplevel *toplevel) | ||||
2127 | { | ||||
2128 | m_focus.focus = toplevel; | ||||
2129 | //TODO: call focusUpdate? | ||||
2130 | } | ||||
2131 | | ||||
2132 | void InputDeviceHandler::setDecoration(QPointer<Decoration::DecoratedClientImpl> decoration) | ||||
2133 | { | ||||
2134 | auto oldDeco = m_focus.decoration; | ||||
2135 | m_focus.decoration = decoration; | ||||
2136 | cleanupDecoration(oldDeco.data(), m_focus.decoration.data()); | ||||
2137 | emit decorationChanged(); | ||||
2138 | } | ||||
2139 | | ||||
2140 | void InputDeviceHandler::setInternalWindow(QWindow *window) | ||||
2141 | { | ||||
2142 | m_focus.internalWindow = window; | ||||
2143 | //TODO: call internalWindowUpdate? | ||||
2144 | } | ||||
2145 | | ||||
2146 | void InputDeviceHandler::updateFocus() | ||||
2147 | { | ||||
2148 | auto oldFocus = m_focus.focus; | ||||
2149 | m_focus.focus = m_at; | ||||
2150 | focusUpdate(oldFocus, m_focus.focus); | ||||
2151 | } | ||||
2152 | | ||||
2153 | bool InputDeviceHandler::updateDecoration() | ||||
2154 | { | ||||
2155 | const auto oldDeco = m_focus.decoration; | ||||
2156 | m_focus.decoration = nullptr; | ||||
2157 | | ||||
2158 | auto *ac = qobject_cast<AbstractClient*>(m_at); | ||||
2159 | if (ac && ac->decoratedClient()) { | ||||
2160 | const QRect clientRect = QRect(ac->clientPos(), ac->clientSize()).translated(ac->pos()); | ||||
2161 | if (!clientRect.contains(position().toPoint())) { | ||||
2162 | // input device above decoration | ||||
2163 | m_focus.decoration = ac->decoratedClient(); | ||||
2164 | } | ||||
2165 | } | ||||
2166 | | ||||
2167 | if (m_focus.decoration == oldDeco) { | ||||
2168 | // no change to decoration | ||||
2169 | return false; | ||||
2170 | } | ||||
2171 | cleanupDecoration(oldDeco.data(), m_focus.decoration.data()); | ||||
2172 | emit decorationChanged(); | ||||
2173 | return true; | ||||
2174 | } | ||||
2175 | | ||||
2176 | void InputDeviceHandler::updateInternalWindow(QWindow *window) | ||||
2177 | { | ||||
2178 | if (m_focus.internalWindow == window) { | ||||
2179 | // no change | ||||
2180 | return; | ||||
2181 | } | ||||
2182 | const auto oldInternal = m_focus.internalWindow; | ||||
2183 | m_focus.internalWindow = window; | ||||
2184 | cleanupInternalWindow(oldInternal, window); | ||||
2185 | } | ||||
2186 | | ||||
2187 | void InputDeviceHandler::update() | ||||
2188 | { | ||||
2189 | if (!m_inited) { | ||||
2190 | return; | ||||
2104 | } | 2191 | } | ||
2105 | if (needsReset) { | 2192 | const auto pos = position().toPoint(); | ||
2106 | m_decoration.clear(); | 2193 | auto internalWindow = findInternalWindow(pos); | ||
2194 | | ||||
2195 | Toplevel *toplevel; | ||||
2196 | if (internalWindow) { | ||||
2197 | toplevel = waylandServer()->findClient(internalWindow); | ||||
2198 | } else { | ||||
2199 | toplevel = input()->findToplevel(pos); | ||||
2107 | } | 2200 | } | ||
2108 | 2201 | | |||
2109 | bool leftSend = false; | 2202 | // Always set the toplevel at the position of the input device. | ||
2110 | auto oldWindow = qobject_cast<AbstractClient*>(window().data()); | 2203 | setAt(toplevel); | ||
2111 | if (oldWindow && (m_decoration && m_decoration->client() != oldWindow)) { | 2204 | | ||
2112 | leftSend = true; | 2205 | if (focusUpdatesBlocked()) { | ||
2113 | oldWindow->leaveEvent(); | 2206 | return; | ||
2114 | } | 2207 | } | ||
2115 | 2208 | | |||
2116 | if (oldDeco && oldDeco != m_decoration) { | 2209 | if (internalWindow) { | ||
2117 | if (oldDeco->client() != t && !leftSend) { | 2210 | if (m_focus.internalWindow != internalWindow) { | ||
2118 | leftSend = true; | 2211 | // changed internal window | ||
2119 | oldDeco->client()->leaveEvent(); | 2212 | updateDecoration(); | ||
2213 | updateInternalWindow(internalWindow); | ||||
2214 | updateFocus(); | ||||
2215 | } else if (updateDecoration()) { | ||||
2216 | // went onto or off from decoration, update focus | ||||
2217 | updateFocus(); | ||||
2120 | } | 2218 | } | ||
2121 | // send leave | 2219 | return; | ||
2122 | QHoverEvent event(QEvent::HoverLeave, QPointF(), QPointF()); | | |||
2123 | QCoreApplication::instance()->sendEvent(oldDeco->decoration(), &event); | | |||
2124 | } | 2220 | } | ||
2125 | if (m_decoration) { | 2221 | updateInternalWindow(nullptr); | ||
2126 | if (m_decoration->client() != oldWindow) { | 2222 | | ||
2127 | m_decoration->client()->enterEvent(pos.toPoint()); | 2223 | if (m_focus.focus != m_at) { | ||
2128 | workspace()->updateFocusMousePosition(pos.toPoint()); | 2224 | // focus change | ||
2225 | updateDecoration(); | ||||
2226 | updateFocus(); | ||||
2227 | return; | ||||
2129 | } | 2228 | } | ||
2130 | const QPointF p = pos - t->pos(); | 2229 | // check if switched to/from decoration while staying on the same Toplevel | ||
2131 | QHoverEvent event(QEvent::HoverMove, p, p); | 2230 | if (updateDecoration()) { | ||
2132 | QCoreApplication::instance()->sendEvent(m_decoration->decoration(), &event); | 2231 | // went onto or off from decoration, update focus | ||
2133 | m_decoration->client()->processDecorationMove(p.toPoint(), pos.toPoint()); | 2232 | updateFocus(); | ||
2134 | } | 2233 | } | ||
2135 | } | 2234 | } | ||
2136 | 2235 | | |||
2137 | void InputDeviceHandler::updateInternalWindow(const QPointF &pos) | 2236 | QWindow* InputDeviceHandler::findInternalWindow(const QPoint &pos) const | ||
2138 | { | 2237 | { | ||
2139 | const auto oldInternalWindow = m_internalWindow; | 2238 | if (waylandServer()->isScreenLocked()) { | ||
2140 | bool found = false; | 2239 | return nullptr; | ||
2141 | // TODO: screen locked check without going through wayland server | 2240 | } | ||
2142 | bool needsReset = waylandServer()->isScreenLocked(); | 2241 | | ||
2143 | const auto &internalClients = waylandServer()->internalClients(); | 2242 | const auto &internalClients = waylandServer()->internalClients(); | ||
2144 | const bool change = m_internalWindow.isNull() || !(m_internalWindow->flags().testFlag(Qt::Popup) && m_internalWindow->isVisible()); | 2243 | if (internalClients.isEmpty()) { | ||
2145 | if (!internalClients.isEmpty() && change) { | 2244 | return nullptr; | ||
2245 | } | ||||
2246 | | ||||
2146 | auto it = internalClients.end(); | 2247 | auto it = internalClients.end(); | ||
2147 | do { | 2248 | do { | ||
2148 | it--; | 2249 | --it; | ||
2149 | if (QWindow *w = (*it)->internalWindow()) { | 2250 | QWindow *w = (*it)->internalWindow(); | ||
2150 | if (!w->isVisible()) { | 2251 | if (!w || !w->isVisible()) { | ||
2252 | continue; | ||||
2253 | } | ||||
2254 | if (!(*it)->geometry().contains(pos)) { | ||||
2151 | continue; | 2255 | continue; | ||
2152 | } | 2256 | } | ||
2153 | if ((*it)->geometry().contains(pos.toPoint())) { | | |||
2154 | // check input mask | 2257 | // check input mask | ||
2155 | const QRegion mask = w->mask().translated(w->geometry().topLeft()); | 2258 | const QRegion mask = w->mask().translated(w->geometry().topLeft()); | ||
2156 | if (!mask.isEmpty() && !mask.contains(pos.toPoint())) { | 2259 | if (!mask.isEmpty() && !mask.contains(pos)) { | ||
2157 | continue; | 2260 | continue; | ||
2158 | } | 2261 | } | ||
2159 | if (w->property("outputOnly").toBool()) { | 2262 | if (w->property("outputOnly").toBool()) { | ||
2160 | continue; | 2263 | continue; | ||
2161 | } | 2264 | } | ||
2162 | m_internalWindow = QPointer<QWindow>(w); | 2265 | return w; | ||
2163 | found = true; | | |||
2164 | break; | | |||
2165 | } | | |||
2166 | } | | |||
2167 | } while (it != internalClients.begin()); | 2266 | } while (it != internalClients.begin()); | ||
2168 | if (!found) { | 2267 | | ||
2169 | needsReset = true; | 2268 | return nullptr; | ||
2170 | } | | |||
2171 | } | | |||
2172 | if (needsReset) { | | |||
2173 | m_internalWindow.clear(); | | |||
2174 | } | | |||
2175 | if (oldInternalWindow != m_internalWindow) { | | |||
2176 | // changed | | |||
2177 | if (oldInternalWindow) { | | |||
2178 | QEvent event(QEvent::Leave); | | |||
2179 | QCoreApplication::sendEvent(oldInternalWindow.data(), &event); | | |||
2180 | } | | |||
2181 | if (m_internalWindow) { | | |||
2182 | QEnterEvent event(pos - m_internalWindow->position(), | | |||
2183 | pos - m_internalWindow->position(), | | |||
2184 | pos); | | |||
2185 | QCoreApplication::sendEvent(m_internalWindow.data(), &event); | | |||
2186 | } | | |||
2187 | emit internalWindowChanged(); | | |||
2188 | } | | |||
2189 | } | 2269 | } | ||
2190 | 2270 | | |||
2191 | } // namespace | 2271 | } // namespace |