File indexing completed on 2024-10-06 13:22:07
0001 /* 0002 SPDX-FileCopyrightText: 2017 Martin Graesslin <mgraesslin@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 0006 */ 0007 #include "popup_input_filter.h" 0008 #include "deleted.h" 0009 #include "input_event.h" 0010 #include "internalwindow.h" 0011 #include "wayland/seat_interface.h" 0012 #include "wayland_server.h" 0013 #include "window.h" 0014 #include "workspace.h" 0015 0016 namespace KWin 0017 { 0018 0019 PopupInputFilter::PopupInputFilter() 0020 : QObject() 0021 { 0022 connect(workspace(), &Workspace::windowAdded, this, &PopupInputFilter::handleWindowAdded); 0023 connect(workspace(), &Workspace::internalWindowAdded, this, &PopupInputFilter::handleWindowAdded); 0024 } 0025 0026 void PopupInputFilter::handleWindowAdded(Window *window) 0027 { 0028 if (m_popupWindows.contains(window)) { 0029 return; 0030 } 0031 if (window->hasPopupGrab()) { 0032 // TODO: verify that the Window is allowed as a popup 0033 connect(window, &Window::windowShown, this, &PopupInputFilter::handleWindowAdded, Qt::UniqueConnection); 0034 connect(window, &Window::windowClosed, this, &PopupInputFilter::handleWindowRemoved, Qt::UniqueConnection); 0035 m_popupWindows << window; 0036 } 0037 } 0038 0039 void PopupInputFilter::handleWindowRemoved(Window *window) 0040 { 0041 m_popupWindows.removeOne(window); 0042 } 0043 0044 bool PopupInputFilter::pointerEvent(MouseEvent *event, quint32 nativeButton) 0045 { 0046 if (m_popupWindows.isEmpty()) { 0047 return false; 0048 } 0049 if (event->type() == QMouseEvent::MouseButtonPress) { 0050 auto pointerFocus = input()->findToplevel(event->globalPos()); 0051 if (!pointerFocus || !Window::belongToSameApplication(pointerFocus, m_popupWindows.constLast())) { 0052 // a press on a window (or no window) not belonging to the popup window 0053 cancelPopups(); 0054 // filter out this press 0055 return true; 0056 } 0057 if (pointerFocus && pointerFocus->isDecorated()) { 0058 // test whether it is on the decoration 0059 if (!pointerFocus->clientGeometry().contains(event->globalPos())) { 0060 cancelPopups(); 0061 return true; 0062 } 0063 } 0064 } 0065 return false; 0066 } 0067 0068 bool PopupInputFilter::keyEvent(KeyEvent *event) 0069 { 0070 if (m_popupWindows.isEmpty()) { 0071 return false; 0072 } 0073 0074 auto seat = waylandServer()->seat(); 0075 0076 auto last = m_popupWindows.last(); 0077 if (last->surface() == nullptr) { 0078 return false; 0079 } 0080 0081 seat->setFocusedKeyboardSurface(last->surface()); 0082 0083 if (!passToInputMethod(event)) { 0084 passToWaylandServer(event); 0085 } 0086 0087 return true; 0088 } 0089 0090 bool PopupInputFilter::touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) 0091 { 0092 if (m_popupWindows.isEmpty()) { 0093 return false; 0094 } 0095 auto pointerFocus = input()->findToplevel(pos); 0096 if (!pointerFocus || !Window::belongToSameApplication(pointerFocus, m_popupWindows.constLast())) { 0097 // a touch on a window (or no window) not belonging to the popup window 0098 cancelPopups(); 0099 // filter out this touch 0100 return true; 0101 } 0102 if (pointerFocus && pointerFocus->isDecorated()) { 0103 // test whether it is on the decoration 0104 if (!pointerFocus->clientGeometry().contains(pos)) { 0105 cancelPopups(); 0106 return true; 0107 } 0108 } 0109 return false; 0110 } 0111 0112 void PopupInputFilter::cancelPopups() 0113 { 0114 while (!m_popupWindows.isEmpty()) { 0115 auto c = m_popupWindows.takeLast(); 0116 c->popupDone(); 0117 } 0118 } 0119 0120 }