File indexing completed on 2024-11-10 04:57:54

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 "input_event.h"
0009 #include "internalwindow.h"
0010 #include "keyboard_input.h"
0011 #include "wayland/seat.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 }
0024 
0025 void PopupInputFilter::handleWindowAdded(Window *window)
0026 {
0027     if (m_popupWindows.contains(window)) {
0028         return;
0029     }
0030     if (window->hasPopupGrab()) {
0031         // TODO: verify that the Window is allowed as a popup
0032         m_popupWindows << window;
0033         connect(window, &Window::closed, this, [this, window]() {
0034             m_popupWindows.removeOne(window);
0035             // Move focus to the parent popup. If that's the last popup, then move focus back to the parent
0036             if (!m_popupWindows.isEmpty() && m_popupWindows.last()->surface()) {
0037                 auto seat = waylandServer()->seat();
0038                 seat->setFocusedKeyboardSurface(m_popupWindows.last()->surface());
0039             } else {
0040                 input()->keyboard()->update();
0041             }
0042         });
0043     }
0044 }
0045 
0046 bool PopupInputFilter::pointerEvent(MouseEvent *event, quint32 nativeButton)
0047 {
0048     if (m_popupWindows.isEmpty()) {
0049         return false;
0050     }
0051     if (event->type() == QMouseEvent::MouseButtonPress) {
0052         auto pointerFocus = input()->findToplevel(event->globalPos());
0053         if (!pointerFocus || !Window::belongToSameApplication(pointerFocus, m_popupWindows.constLast())) {
0054             // a press on a window (or no window) not belonging to the popup window
0055             cancelPopups();
0056             // filter out this press
0057             return true;
0058         }
0059         if (pointerFocus && pointerFocus->isDecorated()) {
0060             // test whether it is on the decoration
0061             if (!exclusiveContains(pointerFocus->clientGeometry(), event->globalPos())) {
0062                 cancelPopups();
0063                 return true;
0064             }
0065         }
0066     }
0067     return false;
0068 }
0069 
0070 bool PopupInputFilter::keyEvent(KeyEvent *event)
0071 {
0072     if (m_popupWindows.isEmpty()) {
0073         return false;
0074     }
0075 
0076     auto seat = waylandServer()->seat();
0077 
0078     auto last = m_popupWindows.last();
0079     if (last->surface() == nullptr) {
0080         return false;
0081     }
0082 
0083     seat->setFocusedKeyboardSurface(last->surface());
0084 
0085     if (!passToInputMethod(event)) {
0086         passToWaylandServer(event);
0087     }
0088 
0089     return true;
0090 }
0091 
0092 bool PopupInputFilter::touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time)
0093 {
0094     if (m_popupWindows.isEmpty()) {
0095         return false;
0096     }
0097     auto pointerFocus = input()->findToplevel(pos);
0098     if (!pointerFocus || !Window::belongToSameApplication(pointerFocus, m_popupWindows.constLast())) {
0099         // a touch on a window (or no window) not belonging to the popup window
0100         cancelPopups();
0101         // filter out this touch
0102         return true;
0103     }
0104     if (pointerFocus && pointerFocus->isDecorated()) {
0105         // test whether it is on the decoration
0106         if (!exclusiveContains(pointerFocus->clientGeometry(), pos)) {
0107             cancelPopups();
0108             return true;
0109         }
0110     }
0111     return false;
0112 }
0113 
0114 void PopupInputFilter::cancelPopups()
0115 {
0116     while (!m_popupWindows.isEmpty()) {
0117         auto c = m_popupWindows.takeLast();
0118         c->popupDone();
0119     }
0120 }
0121 
0122 }
0123 
0124 #include "moc_popup_input_filter.cpp"