diff --git a/src/scriptengines/qml/plasmoid/appletinterface.h b/src/scriptengines/qml/plasmoid/appletinterface.h --- a/src/scriptengines/qml/plasmoid/appletinterface.h +++ b/src/scriptengines/qml/plasmoid/appletinterface.h @@ -312,6 +312,13 @@ */ Q_INVOKABLE QStringList downloadedFiles() const; + /** + * Shows the associated context menu by the applet + * + * @p trigger tells what kind of event it is, @see ContainmentActions::eventToString + */ + Q_INVOKABLE void showContextMenu(const QPointF& pos = {}, const QString &trigger = {}); + QVariantList availableScreenRegion() const; QRect availableScreenRect() const; diff --git a/src/scriptengines/qml/plasmoid/appletinterface.cpp b/src/scriptengines/qml/plasmoid/appletinterface.cpp --- a/src/scriptengines/qml/plasmoid/appletinterface.cpp +++ b/src/scriptengines/qml/plasmoid/appletinterface.cpp @@ -826,7 +826,7 @@ desktopMenu->windowHandle()->setTransientParent(window()); } emit applet()->contextualActionsAboutToShow(); - ci->addAppletActions(desktopMenu, applet(), event); + ci->addAppletActions(desktopMenu, applet(), trigger); if (!desktopMenu->isEmpty()) { desktopMenu->setAttribute(Qt::WA_DeleteOnClose); @@ -842,5 +842,11 @@ return AppletQuickItem::eventFilter(watched, event); } +void AppletInterface::showContextMenu(const QPointF& _pos, const QString &trigger) +{ + const QPointF pos = _pos.isNull() ? QPoint(0,0) : _pos; + ContainmentInterface *ci = applet()->containment()->property("_plasma_graphicObject").value(); + ci->showContextMenu(mapToGlobal(pos).toPoint(), applet() != applet()->containment() ? this : nullptr, trigger); +} #include "moc_appletinterface.cpp" diff --git a/src/scriptengines/qml/plasmoid/containmentinterface.h b/src/scriptengines/qml/plasmoid/containmentinterface.h --- a/src/scriptengines/qml/plasmoid/containmentinterface.h +++ b/src/scriptengines/qml/plasmoid/containmentinterface.h @@ -164,8 +164,10 @@ void wheelEvent(QWheelEvent *event) override; void keyPressEvent(QKeyEvent *event) override; - void addAppletActions(QMenu *desktopMenu, Plasma::Applet *applet, QEvent *event); - void addContainmentActions(QMenu *desktopMenu, QEvent *event); + void addAppletActions(QMenu *desktopMenu, Plasma::Applet *applet, const QString &trigger); + void addContainmentActions(QMenu *desktopMenu, const QString &trigger); + + bool showContextMenu(const QPoint& pos, AppletInterface *applet, const QString &trigger); Q_SIGNALS: /** diff --git a/src/scriptengines/qml/plasmoid/containmentinterface.cpp b/src/scriptengines/qml/plasmoid/containmentinterface.cpp --- a/src/scriptengines/qml/plasmoid/containmentinterface.cpp +++ b/src/scriptengines/qml/plasmoid/containmentinterface.cpp @@ -955,15 +955,7 @@ } void ContainmentInterface::mousePressEvent(QMouseEvent *event) - { - //even if the menu is executed synchronously, other events may be processed - //by the qml incubator when plasma is loading, so we need to guard there - if (m_contextMenu) { - m_contextMenu.data()->close(); - return; - } - const QString trigger = Plasma::ContainmentActions::eventToString(event); Plasma::ContainmentActions *plugin = m_containment->containmentActions().value(trigger); @@ -985,16 +977,34 @@ //FIXME: very inefficient appletAt() implementation Plasma::Applet *applet = nullptr; + AppletInterface *ai = nullptr; foreach (QObject *appletObject, m_appletInterfaces) { - if (AppletInterface *ai = qobject_cast(appletObject)) { + ai = qobject_cast(appletObject); + if (ai) { if (ai->isVisible() && ai->contains(ai->mapFromItem(this, event->localPos()))) { applet = ai->applet(); break; } else { ai = nullptr; } } } + + if (showContextMenu(event->globalPos(), ai, trigger)) + event->accept(); + else + event->setAccepted(false); +} + +bool ContainmentInterface::showContextMenu(const QPoint &_pos, AppletInterface *applet, const QString &trigger) +{ + //even if the menu is executed synchronously, other events may be processed + //by the qml incubator when plasma is loading, so we need to guard there + if (m_contextMenu) { + m_contextMenu.data()->close(); + return true; + } + //qDebug() << "Invoking menu for applet" << applet; QMenu *desktopMenu = new QMenu; @@ -1015,9 +1025,9 @@ if (applet) { emit applet->contextualActionsAboutToShow(); - addAppletActions(desktopMenu, applet, event); + addAppletActions(desktopMenu, applet->applet(), trigger); } else { - addContainmentActions(desktopMenu, event); + addContainmentActions(desktopMenu, trigger); } //this is a workaround where Qt will fail to realize a mouse has been released @@ -1044,7 +1054,7 @@ } //end workaround - QPoint pos = event->globalPos(); + QPoint pos = _pos; if (window() && m_containment->containmentType() == Plasma::Types::PanelContainment) { desktopMenu->adjustSize(); @@ -1058,8 +1068,7 @@ if (desktopMenu->isEmpty()) { delete desktopMenu; - event->accept(); - return; + return true; } // Bug 344205 keep panel visible while menu is open @@ -1073,7 +1082,7 @@ KAcceleratorManager::manage(desktopMenu); desktopMenu->popup(pos); - event->setAccepted(true); + return true; } void ContainmentInterface::wheelEvent(QWheelEvent *event) @@ -1111,7 +1120,7 @@ AppletInterface::keyPressEvent(event); } -void ContainmentInterface::addAppletActions(QMenu *desktopMenu, Plasma::Applet *applet, QEvent *event) +void ContainmentInterface::addAppletActions(QMenu *desktopMenu, Plasma::Applet *applet, const QString &trigger) { foreach (QAction *action, applet->contextualActions()) { if (action) { @@ -1137,7 +1146,7 @@ QMenu *containmentMenu = new QMenu(i18nc("%1 is the name of the containment", "%1 Options", m_containment->title()), desktopMenu); if (m_containment->containmentType() != Plasma::Types::DesktopContainment) { - addContainmentActions(containmentMenu, event); + addContainmentActions(containmentMenu, trigger); } if (!containmentMenu->isEmpty()) { @@ -1180,18 +1189,15 @@ } } -void ContainmentInterface::addContainmentActions(QMenu *desktopMenu, QEvent *event) +void ContainmentInterface::addContainmentActions(QMenu *desktopMenu, const QString &trigger) { if (m_containment->corona()->immutability() != Plasma::Types::Mutable && !KAuthorized::authorizeKAction(QStringLiteral("plasma/containment_actions"))) { //qDebug() << "immutability"; return; } - //this is what ContainmentPrivate::prepareContainmentActions was - const QString trigger = Plasma::ContainmentActions::eventToString(event); Plasma::ContainmentActions *plugin = m_containment->containmentActions().value(trigger); - if (!plugin) { return; }