File indexing completed on 2024-11-24 05:00:55
0001 /* This file is part of the KDE libraries 0002 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 #include "kdeplatformsystemtrayicon.h" 0007 #include <QAction> 0008 #include <QActionGroup> 0009 #include <QApplication> 0010 #include <QIcon> 0011 #include <QMenu> 0012 #include <QRect> 0013 #include <kstatusnotifieritem.h> 0014 0015 #include "statusnotifierwatcher_interface.h" 0016 0017 SystemTrayMenu::SystemTrayMenu() 0018 : QPlatformMenu() 0019 , m_enabled(QVariant::Bool) 0020 , m_visible(QVariant::Bool) 0021 , m_separatorsCollapsible(QVariant::Bool) 0022 , m_tag(0) 0023 { 0024 } 0025 0026 SystemTrayMenu::~SystemTrayMenu() 0027 { 0028 if (m_menu) { 0029 m_menu->deleteLater(); 0030 } 0031 } 0032 0033 QPlatformMenuItem *SystemTrayMenu::createMenuItem() const 0034 { 0035 return new SystemTrayMenuItem(); 0036 } 0037 0038 QPlatformMenu *SystemTrayMenu::createSubMenu() const 0039 { 0040 return new SystemTrayMenu(); 0041 } 0042 0043 void SystemTrayMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) 0044 { 0045 if (SystemTrayMenuItem *ours = qobject_cast<SystemTrayMenuItem *>(menuItem)) { 0046 bool inserted = false; 0047 if (SystemTrayMenuItem *oursBefore = qobject_cast<SystemTrayMenuItem *>(before)) { 0048 for (auto it = m_items.begin(); it != m_items.end(); ++it) { 0049 if (*it == oursBefore) { 0050 m_items.insert(it, ours); 0051 if (m_menu) { 0052 m_menu->insertAction(oursBefore->action(), ours->action()); 0053 } 0054 inserted = true; 0055 break; 0056 } 0057 } 0058 } 0059 if (!inserted) { 0060 m_items.append(ours); 0061 if (m_menu) { 0062 m_menu->addAction(ours->action()); 0063 } 0064 } 0065 } 0066 } 0067 0068 QPlatformMenuItem *SystemTrayMenu::menuItemAt(int position) const 0069 { 0070 if (position < m_items.size()) { 0071 return m_items.at(position); 0072 } 0073 return nullptr; 0074 } 0075 0076 QPlatformMenuItem *SystemTrayMenu::menuItemForTag(quintptr tag) const 0077 { 0078 auto it = std::find_if(m_items.constBegin(), m_items.constEnd(), [tag](SystemTrayMenuItem *item) { 0079 return item->tag() == tag; 0080 }); 0081 if (it != m_items.constEnd()) { 0082 return *it; 0083 } 0084 return nullptr; 0085 } 0086 0087 void SystemTrayMenu::removeMenuItem(QPlatformMenuItem *menuItem) 0088 { 0089 if (SystemTrayMenuItem *ours = qobject_cast<SystemTrayMenuItem *>(menuItem)) { 0090 m_items.removeOne(ours); 0091 if (ours->action() && m_menu) { 0092 m_menu->removeAction(ours->action()); 0093 } 0094 } 0095 } 0096 0097 void SystemTrayMenu::setEnabled(bool enabled) 0098 { 0099 m_enabled = enabled; 0100 if (m_menu) { 0101 m_menu->setEnabled(enabled); 0102 } 0103 } 0104 0105 void SystemTrayMenu::setIcon(const QIcon &icon) 0106 { 0107 m_icon = icon; 0108 if (m_menu) { 0109 m_menu->setIcon(icon); 0110 } 0111 } 0112 0113 void SystemTrayMenu::setTag(quintptr tag) 0114 { 0115 m_tag = tag; 0116 } 0117 0118 void SystemTrayMenu::setText(const QString &text) 0119 { 0120 m_text = text; 0121 if (m_menu) { 0122 m_menu->setTitle(text); 0123 } 0124 } 0125 0126 void SystemTrayMenu::setVisible(bool visible) 0127 { 0128 m_visible = visible; 0129 if (m_menu) { 0130 m_menu->setVisible(visible); 0131 } 0132 } 0133 0134 void SystemTrayMenu::syncMenuItem(QPlatformMenuItem *menuItem) 0135 { 0136 Q_UNUSED(menuItem) 0137 // nothing to do 0138 } 0139 0140 void SystemTrayMenu::syncSeparatorsCollapsible(bool enable) 0141 { 0142 m_separatorsCollapsible = enable; 0143 if (m_menu) { 0144 m_menu->setSeparatorsCollapsible(enable); 0145 } 0146 } 0147 0148 quintptr SystemTrayMenu::tag() const 0149 { 0150 return m_tag; 0151 } 0152 0153 QMenu *SystemTrayMenu::menu() 0154 { 0155 if (!m_menu) { 0156 createMenu(); 0157 } 0158 return m_menu; 0159 } 0160 0161 void SystemTrayMenu::createMenu() 0162 { 0163 m_menu = new QMenu(); 0164 connect(m_menu, &QMenu::aboutToShow, this, &QPlatformMenu::aboutToShow); 0165 connect(m_menu, &QMenu::aboutToHide, this, &QPlatformMenu::aboutToHide); 0166 0167 if (!m_icon.isNull()) { 0168 m_menu->setIcon(m_icon); 0169 } 0170 if (m_menu->title() != m_text) { 0171 m_menu->setTitle(m_text); 0172 } 0173 if (!m_enabled.isNull()) { 0174 m_menu->setEnabled(m_enabled.toBool()); 0175 } 0176 if (!m_visible.isNull()) { 0177 m_menu->setVisible(m_visible.toBool()); 0178 } 0179 if (!m_separatorsCollapsible.isNull()) { 0180 m_menu->setSeparatorsCollapsible(m_separatorsCollapsible.toBool()); 0181 } 0182 for (auto item : std::as_const(m_items)) { 0183 m_menu->addAction(item->action()); 0184 } 0185 } 0186 0187 SystemTrayMenuItem::SystemTrayMenuItem() 0188 : QPlatformMenuItem() 0189 , m_tag(0) 0190 , m_action(new QAction(this)) 0191 { 0192 connect(m_action, &QAction::triggered, this, &QPlatformMenuItem::activated); 0193 connect(m_action, &QAction::hovered, this, &QPlatformMenuItem::hovered); 0194 } 0195 0196 SystemTrayMenuItem::~SystemTrayMenuItem() 0197 { 0198 } 0199 0200 void SystemTrayMenuItem::setCheckable(bool checkable) 0201 { 0202 m_action->setCheckable(checkable); 0203 } 0204 0205 void SystemTrayMenuItem::setChecked(bool isChecked) 0206 { 0207 m_action->setChecked(isChecked); 0208 } 0209 0210 void SystemTrayMenuItem::setEnabled(bool enabled) 0211 { 0212 m_action->setEnabled(enabled); 0213 } 0214 0215 void SystemTrayMenuItem::setFont(const QFont &font) 0216 { 0217 m_action->setFont(font); 0218 } 0219 0220 void SystemTrayMenuItem::setIcon(const QIcon &icon) 0221 { 0222 m_action->setIcon(icon); 0223 } 0224 0225 void SystemTrayMenuItem::setIsSeparator(bool isSeparator) 0226 { 0227 m_action->setSeparator(isSeparator); 0228 } 0229 0230 void SystemTrayMenuItem::setMenu(QPlatformMenu *menu) 0231 { 0232 if (SystemTrayMenu *ourMenu = qobject_cast<SystemTrayMenu *>(menu)) { 0233 m_action->setMenu(ourMenu->menu()); 0234 } 0235 } 0236 0237 void SystemTrayMenuItem::setRole(QPlatformMenuItem::MenuRole role) 0238 { 0239 Q_UNUSED(role) 0240 } 0241 0242 void SystemTrayMenuItem::setShortcut(const QKeySequence &shortcut) 0243 { 0244 m_action->setShortcut(shortcut); 0245 } 0246 0247 void SystemTrayMenuItem::setTag(quintptr tag) 0248 { 0249 m_tag = tag; 0250 } 0251 0252 void SystemTrayMenuItem::setText(const QString &text) 0253 { 0254 m_action->setText(text); 0255 } 0256 0257 void SystemTrayMenuItem::setVisible(bool isVisible) 0258 { 0259 m_action->setVisible(isVisible); 0260 } 0261 0262 void SystemTrayMenuItem::setIconSize(int size) 0263 { 0264 Q_UNUSED(size) 0265 } 0266 0267 void SystemTrayMenuItem::setHasExclusiveGroup(bool hasExclusiveGroup) 0268 { 0269 if (hasExclusiveGroup) { 0270 if (!m_action->actionGroup()) { 0271 m_action->setActionGroup(new QActionGroup(m_action)); 0272 } 0273 } else { 0274 QActionGroup *actionGroup = m_action->actionGroup(); 0275 if (actionGroup) { 0276 m_action->setActionGroup(nullptr); 0277 delete actionGroup; 0278 } 0279 } 0280 } 0281 0282 quintptr SystemTrayMenuItem::tag() const 0283 { 0284 return m_tag; 0285 } 0286 0287 QAction *SystemTrayMenuItem::action() const 0288 { 0289 return m_action; 0290 } 0291 0292 KDEPlatformSystemTrayIcon::KDEPlatformSystemTrayIcon() 0293 : QPlatformSystemTrayIcon() 0294 { 0295 } 0296 0297 KDEPlatformSystemTrayIcon::~KDEPlatformSystemTrayIcon() 0298 { 0299 } 0300 0301 void KDEPlatformSystemTrayIcon::init() 0302 { 0303 if (!m_sni) { 0304 m_sni = new KStatusNotifierItem(); 0305 m_sni->setStandardActionsEnabled(false); 0306 m_sni->setTitle(QApplication::applicationDisplayName()); 0307 m_sni->setStatus(KStatusNotifierItem::Active); 0308 connect(m_sni, &KStatusNotifierItem::activateRequested, [this](bool active, const QPoint &pos) { 0309 Q_UNUSED(active) 0310 Q_UNUSED(pos) 0311 Q_EMIT activated(QPlatformSystemTrayIcon::Trigger); 0312 }); 0313 connect(m_sni, &KStatusNotifierItem::secondaryActivateRequested, [this](const QPoint &pos) { 0314 Q_UNUSED(pos) 0315 Q_EMIT activated(QPlatformSystemTrayIcon::MiddleClick); 0316 }); 0317 } 0318 } 0319 0320 void KDEPlatformSystemTrayIcon::cleanup() 0321 { 0322 delete m_sni; 0323 m_sni = nullptr; 0324 } 0325 0326 void KDEPlatformSystemTrayIcon::updateIcon(const QIcon &icon) 0327 { 0328 if (!m_sni) { 0329 return; 0330 } 0331 if (icon.name().isEmpty()) { 0332 m_sni->setIconByPixmap(icon); 0333 m_sni->setToolTipIconByPixmap(icon); 0334 } else { 0335 m_sni->setIconByName(icon.name()); 0336 m_sni->setToolTipIconByName(icon.name()); 0337 } 0338 } 0339 0340 void KDEPlatformSystemTrayIcon::updateToolTip(const QString &tooltip) 0341 { 0342 if (!m_sni) { 0343 return; 0344 } 0345 m_sni->setToolTipTitle(tooltip); 0346 } 0347 0348 void KDEPlatformSystemTrayIcon::updateMenu(QPlatformMenu *menu) 0349 { 0350 if (!m_sni) { 0351 return; 0352 } 0353 if (SystemTrayMenu *ourMenu = qobject_cast<SystemTrayMenu *>(menu)) { 0354 m_sni->setContextMenu(ourMenu->menu()); 0355 } 0356 } 0357 0358 QPlatformMenu *KDEPlatformSystemTrayIcon::createMenu() const 0359 { 0360 return new SystemTrayMenu(); 0361 } 0362 0363 QRect KDEPlatformSystemTrayIcon::geometry() const 0364 { 0365 // StatusNotifierItem doesn't provide the geometry 0366 return QRect(); 0367 } 0368 0369 void KDEPlatformSystemTrayIcon::showMessage(const QString &title, const QString &msg, const QIcon &icon, MessageIcon iconType, int secs) 0370 { 0371 Q_UNUSED(iconType) 0372 if (!m_sni) { 0373 return; 0374 } 0375 m_sni->showMessage(title, msg, icon.name(), secs); 0376 } 0377 0378 bool KDEPlatformSystemTrayIcon::isSystemTrayAvailable() const 0379 { 0380 org::kde::StatusNotifierWatcher systrayHost(QStringLiteral("org.kde.StatusNotifierWatcher"), 0381 QStringLiteral("/StatusNotifierWatcher"), 0382 QDBusConnection::sessionBus()); 0383 if (systrayHost.isValid()) { 0384 return systrayHost.isStatusNotifierHostRegistered(); 0385 } 0386 0387 return false; 0388 } 0389 0390 bool KDEPlatformSystemTrayIcon::supportsMessages() const 0391 { 0392 return true; 0393 }