File indexing completed on 2024-04-21 14:54:20

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2021 Felix Ernst <fe.a.ernst@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 #include "khamburgermenuhelpers_p.h"
0009 
0010 #include "khamburgermenu.h"
0011 
0012 #include <QEvent>
0013 #include <QMenu>
0014 #include <QToolButton>
0015 #include <QWidget>
0016 #include <QWindow>
0017 
0018 ListenerContainer::ListenerContainer(KHamburgerMenuPrivate *hamburgerMenuPrivate)
0019     : QObject{hamburgerMenuPrivate}
0020     , m_listeners{std::vector<std::unique_ptr<QObject>>(4)}
0021 {
0022 }
0023 
0024 ListenerContainer::~ListenerContainer()
0025 {
0026 }
0027 
0028 bool AddOrRemoveActionListener::eventFilter(QObject * /*watched*/, QEvent *event)
0029 {
0030     if (event->type() == QEvent::ActionAdded || event->type() == QEvent::ActionRemoved) {
0031         static_cast<KHamburgerMenuPrivate *>(parent())->notifyMenuResetNeeded();
0032     }
0033     return false;
0034 }
0035 
0036 bool ButtonPressListener::eventFilter(QObject *watched, QEvent *event)
0037 {
0038     if (event->type() == QEvent::KeyPress || event->type() == QEvent::MouseButtonPress) {
0039         auto hamburgerMenuPrivate = static_cast<KHamburgerMenuPrivate *>(parent());
0040         auto q = static_cast<KHamburgerMenu *>(hamburgerMenuPrivate->q_ptr);
0041         Q_EMIT q->aboutToShowMenu();
0042         hamburgerMenuPrivate->resetMenu(); // This menu never has a parent which can be
0043         // problematic because it can lead to situations in which the QMenu itself is
0044         // treated like its own window.
0045         // To avoid this we set a sane transientParent() now even if it already has one
0046         // because the menu might be opened from another window this time.
0047         const auto watchedButton = qobject_cast<QToolButton *>(watched);
0048         if (!watchedButton) {
0049             return false;
0050         }
0051         auto menu = watchedButton->menu();
0052         if (!menu) {
0053             return false;
0054         }
0055         // ensure polished so the style can change the surfaceformat of the window which is
0056         // not possible once the window has been created
0057         menu->ensurePolished();
0058         menu->winId(); // trigger being a native widget already, to ensure windowHandle created
0059         // generic code if not known if the available parent widget is a native widget or not
0060         auto parentWindowHandle = watchedButton->windowHandle();
0061         if (!parentWindowHandle) {
0062             parentWindowHandle = watchedButton->nativeParentWidget()->windowHandle();
0063         }
0064         menu->windowHandle()->setTransientParent(parentWindowHandle);
0065     }
0066     return false;
0067 }
0068 
0069 bool VisibleActionsChangeListener::eventFilter(QObject *watched, QEvent *event)
0070 {
0071     if (event->type() == QEvent::Show || event->type() == QEvent::Hide) {
0072         if (!event->spontaneous()) {
0073             static_cast<KHamburgerMenuPrivate *>(parent())->notifyMenuResetNeeded();
0074         }
0075     } else if (event->type() == QEvent::ActionAdded || event->type() == QEvent::ActionRemoved) {
0076         Q_ASSERT_X(qobject_cast<QWidget *>(watched), "VisibileActionsChangeListener", "The watched QObject is expected to be a QWidget.");
0077         if (static_cast<QWidget *>(watched)->isVisible()) {
0078             static_cast<KHamburgerMenuPrivate *>(parent())->notifyMenuResetNeeded();
0079         }
0080     }
0081     return false;
0082 }
0083 
0084 bool VisibilityChangesListener::eventFilter(QObject * /*watched*/, QEvent *event)
0085 {
0086     if (event->type() == QEvent::Show || event->type() == QEvent::Hide) {
0087         if (!event->spontaneous()) {
0088             static_cast<KHamburgerMenuPrivate *>(parent())->updateVisibility();
0089         }
0090     }
0091     return false;
0092 }
0093 
0094 bool isWidgetActuallyVisible(const QWidget *widget)
0095 {
0096     Q_CHECK_PTR(widget);
0097     bool actuallyVisible = widget->isVisible();
0098     const QWidget *ancestorWidget = widget->parentWidget();
0099     while (actuallyVisible && ancestorWidget) {
0100         actuallyVisible = ancestorWidget->isVisible();
0101         ancestorWidget = ancestorWidget->parentWidget();
0102     }
0103     return actuallyVisible;
0104 }
0105 
0106 bool listContainsWidget(const std::forward_list<QPointer<const QWidget>> &list, const QWidget *widget)
0107 {
0108     for (const auto &item : list) {
0109         if (widget == item) {
0110             return true;
0111         }
0112     }
0113     return false;
0114 }
0115 
0116 #include "moc_khamburgermenuhelpers_p.cpp"