File indexing completed on 2024-04-28 05:35:49
0001 /* 0002 SPDX-FileCopyrightText: 2014 Bhushan Shah <bhush94@gmail.com> 0003 SPDX-FileCopyrightText: 2014 Marco Martin <notmart@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "plasmawindowedview.h" 0009 0010 #include <QMenu> 0011 #include <QQmlContext> 0012 #include <QQmlEngine> 0013 #include <QQmlExpression> 0014 #include <QQmlProperty> 0015 #include <QQuickItem> 0016 #include <QResizeEvent> 0017 0018 #include <PlasmaQuick/AppletQuickItem> 0019 0020 #include <KActionCollection> 0021 #include <KIconLoader> 0022 #include <KLocalizedString> 0023 #include <KStatusNotifierItem> 0024 0025 PlasmaWindowedView::PlasmaWindowedView(QWindow *parent) 0026 : QQuickView(parent) 0027 , m_applet(nullptr) 0028 , m_statusNotifier(nullptr) 0029 , m_withStatusNotifier(false) 0030 { 0031 engine()->rootContext()->setContextProperty(QStringLiteral("root"), contentItem()); 0032 // access appletInterface.Layout.minimumWidth, to create the Layout attached object for appletInterface as a sideeffect 0033 QQmlExpression *expr = new QQmlExpression( 0034 engine()->rootContext(), 0035 contentItem(), 0036 QStringLiteral("Qt.createQmlObject('import QtQuick; import QtQuick.Layouts; import org.kde.kirigami as Kirigami; " 0037 "Rectangle {color: Kirigami.Theme.backgroundColor; anchors.fill:parent; " 0038 "property Item appletInterface; onAppletInterfaceChanged: print(appletInterface?.Layout.minimumWidth)}', root, \"\");")); 0039 m_rootObject = expr->evaluate().value<QQuickItem *>(); 0040 } 0041 0042 PlasmaWindowedView::~PlasmaWindowedView() 0043 { 0044 } 0045 0046 void PlasmaWindowedView::setHasStatusNotifier(bool stay) 0047 { 0048 Q_ASSERT(!m_statusNotifier); 0049 m_withStatusNotifier = stay; 0050 } 0051 0052 void PlasmaWindowedView::setApplet(Plasma::Applet *applet) 0053 { 0054 m_applet = applet; 0055 if (!applet) { 0056 return; 0057 } 0058 0059 m_appletInterface = PlasmaQuick::AppletQuickItem::itemForApplet(applet); 0060 0061 if (!m_appletInterface) { 0062 return; 0063 } 0064 0065 m_appletInterface->setParentItem(m_rootObject); 0066 m_rootObject->setProperty("appletInterface", QVariant::fromValue(m_appletInterface.data())); 0067 m_appletInterface->setVisible(true); 0068 setTitle(applet->title()); 0069 setIcon(QIcon::fromTheme(applet->icon())); 0070 0071 const QSize switchSize(m_appletInterface->property("switchWidth").toInt(), m_appletInterface->property("switchHeight").toInt()); 0072 QRect geom = m_applet->config().readEntry("geometry", QRect()); 0073 0074 if (geom.isValid()) { 0075 geom.setWidth(qMax(geom.width(), switchSize.width() + 1)); 0076 geom.setHeight(qMax(geom.height(), switchSize.height() + 1)); 0077 setGeometry(geom); 0078 } 0079 setMinimumSize(QSize(qMax((int)KIconLoader::SizeEnormous, switchSize.width() + 1), qMax((int)KIconLoader::SizeEnormous, switchSize.height() + 1))); 0080 0081 foreach (QObject *child, m_appletInterface->children()) { 0082 // find for the needed property of Layout: minimum/maximum/preferred sizes and fillWidth/fillHeight 0083 if (child->property("minimumWidth").isValid() && child->property("minimumHeight").isValid() && child->property("preferredWidth").isValid() 0084 && child->property("preferredHeight").isValid() && child->property("maximumWidth").isValid() && child->property("maximumHeight").isValid() 0085 && child->property("fillWidth").isValid() && child->property("fillHeight").isValid()) { 0086 m_layout = child; 0087 } 0088 } 0089 0090 if (m_layout) { 0091 connect(m_layout, SIGNAL(minimumWidthChanged()), this, SLOT(minimumWidthChanged())); 0092 connect(m_layout, SIGNAL(minimumHeightChanged()), this, SLOT(minimumHeightChanged())); 0093 } 0094 minimumWidthChanged(); 0095 minimumHeightChanged(); 0096 QObject::connect(applet->containment(), 0097 &Plasma::Containment::configureRequested, 0098 this, 0099 static_cast<void (PlasmaWindowedView::*)(Plasma::Applet *)>(&PlasmaWindowedView::showConfigurationInterface)); 0100 0101 Q_ASSERT(!m_statusNotifier); 0102 if (m_withStatusNotifier) { 0103 m_statusNotifier = new KStatusNotifierItem(applet->pluginMetaData().pluginId(), this); 0104 m_statusNotifier->setStandardActionsEnabled(false); // we add our own "Close" entry manually below 0105 0106 updateSniIcon(); 0107 connect(applet, &Plasma::Applet::iconChanged, this, &PlasmaWindowedView::updateSniIcon); 0108 0109 updateSniTitle(); 0110 connect(applet, &Plasma::Applet::titleChanged, this, &PlasmaWindowedView::updateSniTitle); 0111 0112 updateSniStatus(); 0113 connect(applet, &Plasma::Applet::statusChanged, this, &PlasmaWindowedView::updateSniStatus); 0114 0115 // set up actions 0116 for (auto a : applet->contextualActions()) { 0117 m_statusNotifier->contextMenu()->addAction(a); 0118 } 0119 m_statusNotifier->contextMenu()->addSeparator(); 0120 QAction *closeAction = new QAction(QIcon::fromTheme(QStringLiteral("window-close")), i18n("Close %1", applet->title()), this); 0121 connect(closeAction, &QAction::triggered, this, [this]() { 0122 m_statusNotifier->deleteLater(); 0123 close(); 0124 }); 0125 m_statusNotifier->contextMenu()->addAction(closeAction); 0126 0127 connect(m_statusNotifier.data(), &KStatusNotifierItem::activateRequested, this, [this](bool /*active*/, const QPoint & /*pos*/) { 0128 if (isVisible() && isActive()) { 0129 hide(); 0130 } else { 0131 show(); 0132 raise(); 0133 } 0134 }); 0135 auto syncStatus = [this]() { 0136 switch (m_applet->status()) { 0137 case Plasma::Types::AcceptingInputStatus: 0138 case Plasma::Types::RequiresAttentionStatus: 0139 case Plasma::Types::NeedsAttentionStatus: 0140 m_statusNotifier->setStatus(KStatusNotifierItem::NeedsAttention); 0141 break; 0142 case Plasma::Types::ActiveStatus: 0143 m_statusNotifier->setStatus(KStatusNotifierItem::Active); 0144 break; 0145 default: 0146 m_statusNotifier->setStatus(KStatusNotifierItem::Passive); 0147 } 0148 }; 0149 connect(applet, &Plasma::Applet::statusChanged, this, syncStatus); 0150 syncStatus(); 0151 } 0152 } 0153 0154 void PlasmaWindowedView::showConfigurationInterface() 0155 { 0156 if (!m_applet) { 0157 return; 0158 } 0159 0160 if (!m_configView) { 0161 m_configView = new PlasmaQuick::ConfigView(m_applet); 0162 m_configView->init(); 0163 m_configView->setTransientParent(this); 0164 } 0165 0166 m_configView->show(); 0167 m_configView->requestActivate(); 0168 } 0169 0170 void PlasmaWindowedView::resizeEvent(QResizeEvent *ev) 0171 { 0172 if (!m_applet) { 0173 return; 0174 } 0175 0176 QQuickItem *i = PlasmaQuick::AppletQuickItem::itemForApplet(m_applet); 0177 if (!i) { 0178 return; 0179 } 0180 0181 minimumWidthChanged(); 0182 minimumHeightChanged(); 0183 0184 i->setSize(ev->size()); 0185 contentItem()->setSize(ev->size()); 0186 0187 m_applet->config().writeEntry("geometry", QRect(position(), ev->size())); 0188 } 0189 0190 void PlasmaWindowedView::mouseReleaseEvent(QMouseEvent *ev) 0191 { 0192 QQuickWindow::mouseReleaseEvent(ev); 0193 0194 if ((!(ev->buttons() & Qt::RightButton) && ev->button() != Qt::RightButton) || ev->isAccepted()) { 0195 return; 0196 } 0197 0198 Q_EMIT m_applet->contextualActionsAboutToShow(); 0199 0200 QMenu menu; 0201 0202 foreach (QAction *action, m_applet->contextualActions()) { 0203 if (action) { 0204 menu.addAction(action); 0205 } 0206 } 0207 0208 if (!m_applet->failedToLaunch()) { 0209 QAction *configureApplet = m_applet->internalAction(QStringLiteral("configure")); 0210 if (configureApplet && configureApplet->isEnabled()) { 0211 menu.addAction(configureApplet); 0212 } 0213 } 0214 0215 menu.exec(ev->globalPosition().toPoint()); 0216 ev->setAccepted(true); 0217 } 0218 0219 void PlasmaWindowedView::keyPressEvent(QKeyEvent *ev) 0220 { 0221 if (ev->matches(QKeySequence::Quit)) { 0222 m_statusNotifier->deleteLater(); 0223 close(); 0224 } 0225 QQuickView::keyReleaseEvent(ev); 0226 } 0227 0228 void PlasmaWindowedView::moveEvent(QMoveEvent *ev) 0229 { 0230 Q_UNUSED(ev) 0231 m_applet->config().writeEntry("geometry", QRect(position(), size())); 0232 } 0233 0234 void PlasmaWindowedView::hideEvent(QHideEvent *ev) 0235 { 0236 Q_UNUSED(ev) 0237 m_applet->config().sync(); 0238 if (!m_withStatusNotifier) { 0239 m_applet->deleteLater(); 0240 deleteLater(); 0241 } 0242 } 0243 0244 void PlasmaWindowedView::showConfigurationInterface(Plasma::Applet *applet) 0245 { 0246 if (m_configView) { 0247 m_configView->hide(); 0248 m_configView->deleteLater(); 0249 } 0250 0251 if (!applet || !applet->containment()) { 0252 return; 0253 } 0254 0255 m_configView = new PlasmaQuick::ConfigView(applet); 0256 0257 m_configView->init(); 0258 m_configView->show(); 0259 } 0260 0261 void PlasmaWindowedView::minimumWidthChanged() 0262 { 0263 if (!m_layout || !m_appletInterface) { 0264 return; 0265 } 0266 0267 setMinimumWidth( 0268 qMax(m_appletInterface->property("switchWidth").toInt() + 1, qMax((int)KIconLoader::SizeEnormous, m_layout->property("minimumWidth").toInt()))); 0269 } 0270 0271 void PlasmaWindowedView::minimumHeightChanged() 0272 { 0273 if (!m_layout || !m_appletInterface) { 0274 return; 0275 } 0276 0277 setMinimumHeight( 0278 qMax(m_appletInterface->property("switchHeight").toInt() + 1, qMax((int)KIconLoader::SizeEnormous, m_layout->property("minimumHeight").toInt()))); 0279 } 0280 0281 void PlasmaWindowedView::maximumWidthChanged() 0282 { 0283 if (!m_layout) { 0284 return; 0285 } 0286 0287 setMaximumWidth(m_layout->property("maximumWidth").toInt()); 0288 } 0289 0290 void PlasmaWindowedView::maximumHeightChanged() 0291 { 0292 if (!m_layout) { 0293 return; 0294 } 0295 0296 setMaximumHeight(m_layout->property("maximumHeight").toInt()); 0297 } 0298 0299 void PlasmaWindowedView::updateSniIcon() 0300 { 0301 m_statusNotifier->setIconByName(m_applet->icon()); 0302 } 0303 0304 void PlasmaWindowedView::updateSniTitle() 0305 { 0306 m_statusNotifier->setTitle(m_applet->title()); 0307 m_statusNotifier->setToolTipTitle(m_applet->title()); 0308 } 0309 0310 void PlasmaWindowedView::updateSniStatus() 0311 { 0312 switch (m_applet->status()) { 0313 case Plasma::Types::UnknownStatus: 0314 case Plasma::Types::PassiveStatus: 0315 case Plasma::Types::HiddenStatus: 0316 m_statusNotifier->setStatus(KStatusNotifierItem::Passive); 0317 break; 0318 case Plasma::Types::ActiveStatus: 0319 case Plasma::Types::AcceptingInputStatus: 0320 m_statusNotifier->setStatus(KStatusNotifierItem::Active); 0321 break; 0322 case Plasma::Types::NeedsAttentionStatus: 0323 case Plasma::Types::RequiresAttentionStatus: 0324 m_statusNotifier->setStatus(KStatusNotifierItem::NeedsAttention); 0325 break; 0326 } 0327 }