X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fqtui%2Fsystemtray.cpp;h=27aeb086c59bd44671c0204b045b1ad01d76fdcf;hp=9944823e1301ee4daaafee91039c473c1b3a64b6;hb=d452877910888c25d40590b5fff57eb8197ca9b0;hpb=c4b281a2f246e87c216d99c8c7f7bcd26b025cc0 diff --git a/src/qtui/systemtray.cpp b/src/qtui/systemtray.cpp index 9944823e..27aeb086 100644 --- a/src/qtui/systemtray.cpp +++ b/src/qtui/systemtray.cpp @@ -2,6 +2,9 @@ * Copyright (C) 2005-2010 by the Quassel Project * * devel@quassel-irc.org * * * + * This contains code from KStatusNotifierItem, part of the KDE libs * + * Copyright (C) 2009 Marco Martin * + * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * @@ -25,9 +28,13 @@ #include "client.h" #include "iconloader.h" #include "qtui.h" -#include "qtuisettings.h" -SystemTray::SystemTray(QObject *parent) +#ifdef HAVE_KDE +# include +# include +#endif + +SystemTray::SystemTray(QWidget *parent) : QObject(parent), _mode(Invalid), _state(Passive), @@ -35,15 +42,31 @@ SystemTray::SystemTray(QObject *parent) _passiveIcon(DesktopIcon("quassel_inactive")), _activeIcon(DesktopIcon("quassel")), _needsAttentionIcon(DesktopIcon("quassel_message")), - _trayMenu(0) + _trayMenu(0), + _associatedWidget(parent) { + Q_ASSERT(parent); + +#ifdef Q_WS_WIN + _dwTickCount = 0; + associatedWidget()->installEventFilter(this); +#endif + qApp->installEventFilter(this); } SystemTray::~SystemTray() { +#ifdef Q_WS_WIN + associatedWidget()->removeEventFilter(this); +#endif + _trayMenu->deleteLater(); } +QWidget *SystemTray::associatedWidget() const { + return _associatedWidget; +} + void SystemTray::setTrayMenu(QMenu *menu) { if(menu) _trayMenu = menu; @@ -59,7 +82,6 @@ void SystemTray::setTrayMenu(QMenu *menu) { _trayMenu->addSeparator(); _trayMenu->addAction(coll->action("Quit")); #endif /* HAVE_KDE */ - } void SystemTray::setMode(Mode mode_) { @@ -119,10 +141,133 @@ void SystemTray::showMessage(const QString &title, const QString &message, Messa Q_UNUSED(millisecondsTimeoutHint) } +void SystemTray::activate(SystemTray::ActivationReason reason) { + + emit activated(reason); + + if(reason == Trigger && !isActivationInhibited()) { + toggleMainWidget(); + } +} + bool SystemTray::eventFilter(QObject *obj, QEvent *event) { - Q_UNUSED(obj); - if(event->type() == QEvent::MouseButtonRelease) { + if(event->type() == QEvent::MouseMove || event->type() == QEvent::MouseButtonRelease) { _inhibitActivation = false; } - return false; +#ifdef Q_WS_WIN + if(obj == associatedWidget() && event->type() == QEvent::ActivationChange) { + _dwTickCount = GetTickCount(); + } +#endif + return QObject::eventFilter(obj, event); +} + +// Code taken from KStatusNotifierItem for handling minimize/restore + +bool SystemTray::checkVisibility(bool perform) { +#ifdef Q_WS_WIN + // the problem is that we lose focus when the systray icon is activated + // and we don't know the former active window + // 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); + } else { + minimizeRestore(true); + } + +#elif defined(HAVE_KDE) && defined(Q_WS_X11) + KWindowInfo info1 = KWindowSystem::windowInfo(associatedWidget()->winId(), NET::XAWMState | NET::WMState | NET::WMDesktop); + // mapped = visible (but possibly obscured) + bool mapped = (info1.mappingState() == NET::Visible) && !info1.isMinimized(); + + // - not mapped -> show, raise, focus + // - mapped + // - obscured -> raise, focus + // - not obscured -> hide + //info1.mappingState() != NET::Visible -> window on another desktop? + if(!mapped) { + if(perform) + minimizeRestore(true); + return true; + + } else { + QListIterator< WId > it (KWindowSystem::stackingOrder()); + it.toBack(); + while(it.hasPrevious()) { + WId id = it.previous(); + if(id == associatedWidget()->winId()) + break; + + KWindowInfo info2 = KWindowSystem::windowInfo(id, NET::WMDesktop | NET::WMGeometry | NET::XAWMState | NET::WMState | NET::WMWindowType); + + if(info2.mappingState() != NET::Visible) + continue; // not visible on current desktop -> ignore + + if(!info2.geometry().intersects(associatedWidget()->geometry())) + continue; // not obscuring the window -> ignore + + if(!info1.hasState(NET::KeepAbove) && info2.hasState(NET::KeepAbove)) + continue; // obscured by window kept above -> ignore + + NET::WindowType type = info2.windowType(NET::NormalMask | NET::DesktopMask + | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask + | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask); + + if(type == NET::Dock || type == NET::TopMenu) + continue; // obscured by dock or topmenu -> ignore + + if(perform) { + KWindowSystem::raiseWindow(associatedWidget()->winId()); + KWindowSystem::activateWindow(associatedWidget()->winId()); + } + return true; + } + + //not on current desktop? + if(!info1.isOnCurrentDesktop()) { + if(perform) + KWindowSystem::activateWindow(associatedWidget()->winId()); + return true; + } + + if(perform) + minimizeRestore(false); // hide + return false; + } +#else + + if(!associatedWidget()->isVisible() || associatedWidget()->isMinimized()) { + if(perform) + minimizeRestore(true); + return true; + } else { + if(perform) + minimizeRestore(false); + return false; + } + +#endif + + return true; +} + +void SystemTray::minimizeRestore(bool show) { + if(show) + GraphicalUi::activateMainWidget(); + else { + if(isSystemTrayAvailable()) { + if(!isVisible()) + setVisible(); + GraphicalUi::hideMainWidget(); + } + } +} + +void SystemTray::hideMainWidget() { + minimizeRestore(false); +} + +void SystemTray::toggleMainWidget() { + checkVisibility(true); }