From: Manuel Nickschas Date: Tue, 16 Feb 2010 20:33:28 +0000 (+0100) Subject: Refactor the system tray's context menu X-Git-Tag: 0.6-beta1~5 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=4476cfb22f36ad9ba96e4978c3bcce1c2f6b5a04;hp=b858144c9d38623bdd9afaa02c404d9515243ab7 Refactor the system tray's context menu Should now work with and without QSystemTrayIcon support in Qt. There's still some fugly workaround for QMenu's focus issues, which will probably require some X11 hackery at some point to do it a bit less fugly, but maybe the DBusMenu is specced earlier... --- diff --git a/src/qtui/legacysystemtray.cpp b/src/qtui/legacysystemtray.cpp index 18bf02c4..99698000 100644 --- a/src/qtui/legacysystemtray.cpp +++ b/src/qtui/legacysystemtray.cpp @@ -43,9 +43,6 @@ LegacySystemTray::LegacySystemTray(QWidget *parent) connect(_trayIcon, SIGNAL(messageClicked()), SIGNAL(messageClicked())); - setTrayMenu(_trayIcon->contextMenu()); - _trayIcon->setContextMenu(trayMenu()); - _blinkTimer.setInterval(500); _blinkTimer.setSingleShot(false); connect(&_blinkTimer, SIGNAL(timeout()), SLOT(on_blinkTimeout())); @@ -56,6 +53,8 @@ void LegacySystemTray::init() { setMode(Legacy); SystemTray::init(); + + _trayIcon->setContextMenu(trayMenu()); } void LegacySystemTray::syncLegacyIcon() { diff --git a/src/qtui/statusnotifieritem.cpp b/src/qtui/statusnotifieritem.cpp index da15475b..4df13dc5 100644 --- a/src/qtui/statusnotifieritem.cpp +++ b/src/qtui/statusnotifieritem.cpp @@ -45,13 +45,6 @@ StatusNotifierItem::~StatusNotifierItem() { } void StatusNotifierItem::init() { -// workaround until we handle the tray menu more sanely -#ifdef QT_NO_SYSTEMTRAYICON - setTrayMenu(new QMenu(associatedWidget())); -#endif - - trayMenu()->installEventFilter(this); - qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType(); @@ -64,6 +57,7 @@ void StatusNotifierItem::init() { setMode(StatusNotifier); StatusNotifierItemParent::init(); + trayMenu()->installEventFilter(this); } void StatusNotifierItem::registerToDaemon() { @@ -165,11 +159,17 @@ void StatusNotifierItem::activated(const QPoint &pos) { bool StatusNotifierItem::eventFilter(QObject *watched, QEvent *event) { if(mode() == StatusNotifier) { //FIXME: ugly ugly workaround to weird QMenu's focus problems +#ifdef HAVE_KDE if(watched == trayMenu() && (event->type() == QEvent::WindowDeactivate || (event->type() == QEvent::MouseButtonRelease && static_cast(event)->button() == Qt::LeftButton))) { // put at the back of event queue to let the action activate anyways QTimer::singleShot(0, trayMenu(), SLOT(hide())); } +#else + if(watched == trayMenu() && event->type() == QEvent::HoverLeave) { + trayMenu()->hide(); + } +#endif } return StatusNotifierItemParent::eventFilter(watched, event); } diff --git a/src/qtui/statusnotifieritemdbus.cpp b/src/qtui/statusnotifieritemdbus.cpp index db93d5c2..9c0487b9 100644 --- a/src/qtui/statusnotifieritemdbus.cpp +++ b/src/qtui/statusnotifieritemdbus.cpp @@ -254,7 +254,9 @@ void StatusNotifierItemDBus::ContextMenu(int x, int y) //TODO: nicer placement, possible? if (!m_statusNotifierItem->trayMenu()->isVisible()) { +#ifdef HAVE_KDE m_statusNotifierItem->trayMenu()->setWindowFlags(Qt::Window|Qt::FramelessWindowHint); +#endif m_statusNotifierItem->trayMenu()->popup(QPoint(x,y)); #ifdef HAVE_KDE KWindowSystem::setState(m_statusNotifierItem->trayMenu()->winId(), NET::SkipTaskbar|NET::SkipPager|NET::KeepAbove); diff --git a/src/qtui/systemtray.cpp b/src/qtui/systemtray.cpp index 6b2b33cd..139c968d 100644 --- a/src/qtui/systemtray.cpp +++ b/src/qtui/systemtray.cpp @@ -17,16 +17,19 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#include #include #include "systemtray.h" +#include "action.h" #include "actioncollection.h" #include "client.h" #include "iconloader.h" #include "qtui.h" #ifdef HAVE_KDE +# include # include # include #endif @@ -52,31 +55,53 @@ QWidget *SystemTray::associatedWidget() const { return _associatedWidget; } -void SystemTray::setTrayMenu(QMenu *menu) { - if(menu) - _trayMenu = menu; - else - _trayMenu = new QMenu(); - +void SystemTray::init() { ActionCollection *coll = QtUi::actionCollection("General"); + _minimizeRestoreAction = new Action(tr("&Minimize"), this, this, SLOT(minimizeRestore())); + +#ifdef HAVE_KDE + KMenu *kmenu; + _trayMenu = kmenu = new KMenu(); + kmenu->addTitle(qApp->windowIcon(), "Quassel IRC"); +#else + _trayMenu = new QMenu(associatedWidget()); +#endif + + _trayMenu->setTitle("Quassel IRC"); + +#ifndef HAVE_KDE + _trayMenu->setAttribute(Qt::WA_Hover); +#endif _trayMenu->addAction(coll->action("ConnectCore")); _trayMenu->addAction(coll->action("DisconnectCore")); _trayMenu->addAction(coll->action("CoreInfo")); -#ifndef HAVE_KDE _trayMenu->addSeparator(); + _trayMenu->addAction(_minimizeRestoreAction); _trayMenu->addAction(coll->action("Quit")); -#endif /* HAVE_KDE */ + + connect(_trayMenu, SIGNAL(aboutToShow()), SLOT(trayMenuAboutToShow())); +} + +void SystemTray::trayMenuAboutToShow() { + if(GraphicalUi::isMainWidgetVisible()) + _minimizeRestoreAction->setText(tr("&Minimize")); + else + _minimizeRestoreAction->setText(tr("&Restore")); } void SystemTray::setMode(Mode mode_) { if(mode_ != _mode) { _mode = mode_; - if(_mode == Legacy) { - _trayMenu->setWindowFlags(Qt::Popup); - } else { - _trayMenu->setWindowFlags(Qt::Window); +#ifdef HAVE_KDE + if(_trayMenu) { + if(_mode == Legacy) { + _trayMenu->setWindowFlags(Qt::Popup); + } else { + _trayMenu->setWindowFlags(Qt::Window); + } } +#endif } } @@ -129,3 +154,7 @@ void SystemTray::showMessage(const QString &title, const QString &message, Messa void SystemTray::activate(SystemTray::ActivationReason reason) { emit activated(reason); } + +void SystemTray::minimizeRestore() { + GraphicalUi::toggleMainWidget(); +} diff --git a/src/qtui/systemtray.h b/src/qtui/systemtray.h index dc31edc7..df79ddf5 100644 --- a/src/qtui/systemtray.h +++ b/src/qtui/systemtray.h @@ -23,6 +23,7 @@ #include "icon.h" +class Action; class QMenu; class SystemTray : public QObject { @@ -61,7 +62,7 @@ public: explicit SystemTray(QWidget *parent); virtual ~SystemTray(); - virtual void init() {} + virtual void init(); inline State state() const; inline bool isAlerted() const; @@ -96,9 +97,10 @@ protected: inline QString toolTipTitle() const; inline QString toolTipSubTitle() const; inline QMenu *trayMenu() const; - void setTrayMenu(QMenu *); private slots: + void minimizeRestore(); + void trayMenuAboutToShow(); private: Mode _mode; @@ -109,6 +111,7 @@ private: QMenu *_trayMenu; QWidget *_associatedWidget; + Action *_minimizeRestoreAction; }; // inlines diff --git a/src/uisupport/graphicalui.cpp b/src/uisupport/graphicalui.cpp index 2d1943ff..8e5fe943 100644 --- a/src/uisupport/graphicalui.cpp +++ b/src/uisupport/graphicalui.cpp @@ -101,9 +101,13 @@ bool GraphicalUi::checkMainWidgetVisibility(bool perform) { // therefore we watch for activation event and use our stopwatch :) if(GetTickCount() - _dwTickCount < 300) { // we were active in the last 300ms -> hide it - minimizeRestore(false); + if(perform) + minimizeRestore(false); + return false; } else { - minimizeRestore(true); + if(perform) + minimizeRestore(true); + return true; } #elif defined(HAVE_KDE) && defined(Q_WS_X11) @@ -182,6 +186,10 @@ bool GraphicalUi::checkMainWidgetVisibility(bool perform) { return true; } +bool GraphicalUi::isMainWidgetVisible() { + return !instance()->checkMainWidgetVisibility(false); +} + void GraphicalUi::minimizeRestore(bool show) { if(show) activateMainWidget(); diff --git a/src/uisupport/graphicalui.h b/src/uisupport/graphicalui.h index 88d94fe9..6d6306ed 100644 --- a/src/uisupport/graphicalui.h +++ b/src/uisupport/graphicalui.h @@ -61,6 +61,9 @@ public: //! Toggle main widget static void toggleMainWidget(); + //! Check if the main widget if (fully, in KDE) visible + static bool isMainWidgetVisible(); + protected: //! This is the widget we associate global actions with, typically the main window void setMainWidget(QWidget *); @@ -70,7 +73,7 @@ protected: * it should be activated or hidden. Without KDE, we need to resort to checking the current state * as Qt knows it, ignoring windows covering it. * @param performToggle If true, toggle the window's state in addition to checking visibility - * @return True, if the window is currently visible + * @return True, if the window is currently *not* visible (needs activation) */ bool checkMainWidgetVisibility(bool performToggle);