From 296fc177814b5ea0c76b43f360d0c9d309d1593c Mon Sep 17 00:00:00 2001 From: Hartmnt Date: Fri, 7 Jun 2024 14:25:46 +0000 Subject: [PATCH] Add new tray icon --- src/mumble/CMakeLists.txt | 2 + src/mumble/Global.cpp | 1 + src/mumble/Global.h | 2 + src/mumble/Log_unix.cpp | 28 +++++++-- src/mumble/Log_win.cpp | 26 ++++++++- src/mumble/MainWindow.cpp | 12 ++++ src/mumble/MainWindow.h | 1 + src/mumble/main.cpp | 4 ++ src/mumble/widgets/TrayIcon.cpp | 100 ++++++++++++++++++++++++++++++++ src/mumble/widgets/TrayIcon.h | 31 ++++++++++ 10 files changed, 200 insertions(+), 7 deletions(-) create mode 100644 src/mumble/widgets/TrayIcon.cpp create mode 100644 src/mumble/widgets/TrayIcon.h diff --git a/src/mumble/CMakeLists.txt b/src/mumble/CMakeLists.txt index fa41283bcca..aef67ab2ef8 100644 --- a/src/mumble/CMakeLists.txt +++ b/src/mumble/CMakeLists.txt @@ -309,6 +309,8 @@ set(MUMBLE_SOURCES "widgets/SearchDialogTree.h" "widgets/SemanticSlider.cpp" "widgets/SemanticSlider.h" + "widgets/TrayIcon.cpp" + "widgets/TrayIcon.h" "${SHARED_SOURCE_DIR}/ACL.cpp" diff --git a/src/mumble/Global.cpp b/src/mumble/Global.cpp index 06cab015838..de46978b0fd 100644 --- a/src/mumble/Global.cpp +++ b/src/mumble/Global.cpp @@ -93,6 +93,7 @@ void Global::migrateDataDir(const QDir &toDir) { Global::Global(const QString &qsConfigPath) { mw = 0; + trayIcon = 0; db = 0; pluginManager = 0; nam = 0; diff --git a/src/mumble/Global.h b/src/mumble/Global.h index c129d26e214..3f624e67fa4 100644 --- a/src/mumble/Global.h +++ b/src/mumble/Global.h @@ -34,6 +34,7 @@ class OverlayClient; class LogEmitter; class DeveloperConsole; class TalkingUI; +class TrayIcon; class QNetworkAccessManager; @@ -50,6 +51,7 @@ struct Global Q_DECL_FINAL { static Global &get(); MainWindow *mw; + TrayIcon *trayIcon; Settings s; boost::shared_ptr< ServerHandler > sh; boost::shared_ptr< AudioInput > ai; diff --git a/src/mumble/Log_unix.cpp b/src/mumble/Log_unix.cpp index 7e9159dcbab..ef3bfdbde15 100644 --- a/src/mumble/Log_unix.cpp +++ b/src/mumble/Log_unix.cpp @@ -1,14 +1,32 @@ -// Copyright 2012-2023 The Mumble Developers. All rights reserved. +// Copyright 2012-2024 The Mumble Developers. All rights reserved. // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file at the root of the // Mumble source tree or at . #include "Log.h" #include "MainWindow.h" -#include "Settings.h" - -#include +#include "widgets/TrayIcon.h" +#include "Global.h" void Log::postNotification(MsgType mt, const QString &plain) { - // FIXME + if (mt == MsgType::TextMessage || mt == MsgType::PrivateTextMessage) { + // Use custom icon for text messages + Global::get().trayIcon->showMessage(msgName(mt), plain, Global::get().mw->iconComment); + return; + } + + QSystemTrayIcon::MessageIcon msgIcon; + switch (mt) { + case DebugInfo: + case CriticalError: + msgIcon = QSystemTrayIcon::Critical; + break; + case Warning: + msgIcon = QSystemTrayIcon::Warning; + break; + default: + msgIcon = QSystemTrayIcon::Information; + break; + } + Global::get().trayIcon->showMessage(msgName(mt), plain, msgIcon); } diff --git a/src/mumble/Log_win.cpp b/src/mumble/Log_win.cpp index 04384099f0f..ef3bfdbde15 100644 --- a/src/mumble/Log_win.cpp +++ b/src/mumble/Log_win.cpp @@ -1,10 +1,32 @@ -// Copyright 2012-2023 The Mumble Developers. All rights reserved. +// Copyright 2012-2024 The Mumble Developers. All rights reserved. // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file at the root of the // Mumble source tree or at . #include "Log.h" +#include "MainWindow.h" +#include "widgets/TrayIcon.h" +#include "Global.h" void Log::postNotification(MsgType mt, const QString &plain) { - // FIXME + if (mt == MsgType::TextMessage || mt == MsgType::PrivateTextMessage) { + // Use custom icon for text messages + Global::get().trayIcon->showMessage(msgName(mt), plain, Global::get().mw->iconComment); + return; + } + + QSystemTrayIcon::MessageIcon msgIcon; + switch (mt) { + case DebugInfo: + case CriticalError: + msgIcon = QSystemTrayIcon::Critical; + break; + case Warning: + msgIcon = QSystemTrayIcon::Warning; + break; + default: + msgIcon = QSystemTrayIcon::Information; + break; + } + Global::get().trayIcon->showMessage(msgName(mt), plain, msgIcon); } diff --git a/src/mumble/MainWindow.cpp b/src/mumble/MainWindow.cpp index b4e46f3f5f2..43a169676c6 100644 --- a/src/mumble/MainWindow.cpp +++ b/src/mumble/MainWindow.cpp @@ -82,6 +82,7 @@ #include #include "widgets/SemanticSlider.h" +#include "widgets/TrayIcon.h" #ifdef Q_OS_WIN # include @@ -111,6 +112,7 @@ MainWindow::MainWindow(QWidget *p) SvgIcon::addSvgPixmapsToIcon(qiTalkingOn, QLatin1String("skin:talking_on.svg")); SvgIcon::addSvgPixmapsToIcon(qiTalkingShout, QLatin1String("skin:talking_alt.svg")); SvgIcon::addSvgPixmapsToIcon(qiTalkingWhisper, QLatin1String("skin:talking_whisper.svg")); + SvgIcon::addSvgPixmapsToIcon(iconComment, QLatin1String("skin:comment.svg")); #ifdef Q_OS_MAC if (QFile::exists(QLatin1String("skin:mumble.icns"))) @@ -193,6 +195,7 @@ MainWindow::MainWindow(QWidget *p) QObject::connect(this, &MainWindow::serverSynchronized, Global::get().pluginManager, &PluginManager::on_serverSynchronized); + QObject::connect(this, &MainWindow::serverSynchronized, this, &MainWindow::userStateChanged); QAccessible::installFactory(AccessibleSlider::semanticSliderFactory); } @@ -2536,6 +2539,8 @@ void MainWindow::updateMenuPermissions() { } void MainWindow::userStateChanged() { + Global::get().trayIcon->updateIcon(); + ClientUser *user = ClientUser::get(Global::get().uiSession); if (!user) { Global::get().bAttenuateOthers = false; @@ -2606,6 +2611,7 @@ void MainWindow::on_qaAudioMute_triggered() { } updateAudioToolTips(); + Global::get().trayIcon->updateIcon(); } void MainWindow::setAudioMute(bool mute) { @@ -2650,6 +2656,7 @@ void MainWindow::on_qaAudioDeaf_triggered() { } updateAudioToolTips(); + Global::get().trayIcon->updateIcon(); } void MainWindow::setAudioDeaf(bool deaf) { @@ -2762,6 +2769,7 @@ void MainWindow::pttReleased() { void MainWindow::on_PushToMute_triggered(bool down, QVariant) { Global::get().bPushToMute = down; updateUserModel(); + Global::get().trayIcon->updateIcon(); } void MainWindow::on_VolumeUp_triggered(bool down, QVariant) { @@ -3375,6 +3383,7 @@ void MainWindow::serverDisconnected(QAbstractSocket::SocketError err, QString re qaServerBanList->setEnabled(false); qtvUsers->setCurrentIndex(QModelIndex()); qteChat->setEnabled(false); + Global::get().trayIcon->updateIcon(); #ifdef Q_OS_MAC // Remove App Nap suppression now that we're disconnected. @@ -3582,6 +3591,8 @@ void MainWindow::serverDisconnected(QAbstractSocket::SocketError err, QString re if (Global::get().s.bMinimalView) { qdwMinimalViewNote->show(); } + + Global::get().trayIcon->updateIcon(); } void MainWindow::resolverError(QAbstractSocket::SocketError, QString reason) { @@ -3984,6 +3995,7 @@ void MainWindow::openConfigDialog() { setupView(false); updateTransmitModeComboBox(Global::get().s.atTransmit); updateUserModel(); + Global::get().trayIcon->updateIcon(); if (Global::get().s.requireRestartToApply) { if (Global::get().s.requireRestartToApply diff --git a/src/mumble/MainWindow.h b/src/mumble/MainWindow.h index db02e150b0a..8b8cc3e7085 100644 --- a/src/mumble/MainWindow.h +++ b/src/mumble/MainWindow.h @@ -80,6 +80,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindow { QIcon qiIcon, qiIconMutePushToMute, qiIconMuteSelf, qiIconMuteServer, qiIconDeafSelf, qiIconDeafServer, qiIconMuteSuppressed; QIcon qiTalkingOn, qiTalkingWhisper, qiTalkingShout, qiTalkingOff; + QIcon iconComment; std::unordered_map< unsigned int, qt_unique_ptr< UserLocalNicknameDialog > > qmUserNicknameTracker; /// "Action" for when there are no actions available diff --git a/src/mumble/main.cpp b/src/mumble/main.cpp index be28b37cf8e..73d90ccfee8 100644 --- a/src/mumble/main.cpp +++ b/src/mumble/main.cpp @@ -51,6 +51,8 @@ #include "VersionCheck.h" #include "Global.h" +#include "widgets/TrayIcon.h" + #include #include #include @@ -684,6 +686,8 @@ int main(int argc, char **argv) { Global::get().mw = new MainWindow(nullptr); Global::get().mw->show(); + Global::get().trayIcon = new TrayIcon(); + Global::get().talkingUI = new TalkingUI(); // Set TalkingUI's position diff --git a/src/mumble/widgets/TrayIcon.cpp b/src/mumble/widgets/TrayIcon.cpp new file mode 100644 index 00000000000..af9d9fcdfdb --- /dev/null +++ b/src/mumble/widgets/TrayIcon.cpp @@ -0,0 +1,100 @@ +// Copyright 2024 The Mumble Developers. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file at the root of the +// Mumble source tree or at . + +#include "TrayIcon.h" + +#include "../ClientUser.h" +#include "../MainWindow.h" +#include "../Global.h" + +#include + +TrayIcon::TrayIcon() + : QSystemTrayIcon(Global::get().mw), m_statusIcon(nullptr), m_contextMenu(Global::get().mw), + m_showHideAction(tr("Show"), Global::get().mw) { + setIcon(Global::get().mw->qiIcon); + setToolTip("Mumble"); + + QObject::connect(this, &QSystemTrayIcon::activated, this, &TrayIcon::on_icon_clicked); + + QObject::connect(m_contextMenu, &QMenu::aboutToShow, this, &TrayIcon::on_contextMenu_aboutToShow); + setContextMenu(m_contextMenu); + + show(); +} + +void TrayIcon::updateIcon() { + QIcon *newIcon = nullptr; + + ClientUser *p = ClientUser::get(Global::get().uiSession); + + if (Global::get().s.bDeaf) { + newIcon = &Global::get().mw->qiIconDeafSelf; + } else if (p && p->bDeaf) { + newIcon = &Global::get().mw->qiIconDeafServer; + } else if (Global::get().s.bMute) { + newIcon = &Global::get().mw->qiIconMuteSelf; + } else if (p && p->bMute) { + newIcon = &Global::get().mw->qiIconMuteServer; + } else if (p && p->bSuppress) { + newIcon = &Global::get().mw->qiIconMuteSuppressed; + } else if (Global::get().s.bStateInTray && Global::get().bPushToMute) { + newIcon = &Global::get().mw->qiIconMutePushToMute; + } else if (p && Global::get().s.bStateInTray) { + switch (p->tsState) { + case Settings::Talking: + case Settings::MutedTalking: + newIcon = &Global::get().mw->qiTalkingOn; + break; + case Settings::Whispering: + newIcon = &Global::get().mw->qiTalkingWhisper; + break; + case Settings::Shouting: + newIcon = &Global::get().mw->qiTalkingShout; + break; + case Settings::Passive: + default: + newIcon = &Global::get().mw->qiTalkingOff; + break; + } + } else { + newIcon = &Global::get().mw->qiIcon; + } + + if (newIcon != m_statusIcon) { + m_statusIcon = newIcon; + setIcon(*m_statusIcon); + } +} + +void TrayIcon::on_icon_clicked(QSystemTrayIcon::ActivationReason reason) { + qDebug() << reason; + switch (reason) { + case QSystemTrayIcon::Unknown: + case QSystemTrayIcon::Context: + case QSystemTrayIcon::DoubleClick: + case QSystemTrayIcon::Trigger: + case QSystemTrayIcon::MiddleClick: + default: + break; + } +} + +void TrayIcon::on_contextMenu_aboutToShow() { + m_contextMenu->clear(); + + if (Global::get().mw->isVisible()) { + m_showHideAction->setText(tr("Hide")); + } else { + m_showHideAction->setText(tr("Show")); + } + + m_contextMenu->addAction(m_showHideAction); + m_contextMenu->addSeparator(); + m_contextMenu->addAction(Global::get().mw->qaAudioMute); + m_contextMenu->addAction(Global::get().mw->qaAudioDeaf); + m_contextMenu->addSeparator(); + m_contextMenu->addAction(Global::get().mw->qaQuit); +} diff --git a/src/mumble/widgets/TrayIcon.h b/src/mumble/widgets/TrayIcon.h new file mode 100644 index 00000000000..016751f27fe --- /dev/null +++ b/src/mumble/widgets/TrayIcon.h @@ -0,0 +1,31 @@ +// Copyright 2024 The Mumble Developers. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file at the root of the +// Mumble source tree or at . + +#ifndef MUMBLE_MUMBLE_WIDGETS_TRAYICCON_H_ +#define MUMBLE_MUMBLE_WIDGETS_TRAYICCON_H_ + +#include "../../QtUtils.h" +#include +#include +#include + +class TrayIcon : public QSystemTrayIcon { + Q_OBJECT + +public: + TrayIcon(); + + void updateIcon(); + +private: + QIcon *m_statusIcon; + QMenu *m_contextMenu; + QAction *m_showHideAction; + + void on_icon_clicked(QSystemTrayIcon::ActivationReason reason); + void on_contextMenu_aboutToShow(); +}; + +#endif // MUMBLE_MUMBLE_WIDGETS_TRAYICCON_H_