#include "systemtray.h"
KNotificationBackend::KNotificationBackend(QObject *parent) : AbstractNotificationBackend(parent) {
-
+ connect(QtUi::mainWindow()->systemTray(), SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
+ SLOT(notificationActivated(QSystemTrayIcon::ActivationReason)));
}
void KNotificationBackend::notify(const Notification &n) {
if(n && _notificationIds.contains(n))
id = _notificationIds.value(n);
- emit activated(id);
+ notificationActivated(id);
+}
+
+void KNotificationBackend::notificationActivated(QSystemTrayIcon::ActivationReason reason) {
+ if(reason == QSystemTrayIcon::Trigger && _notificationIds.count() > 0) {
+ notificationActivated(_notificationIds.values().at(0)); // we choose a random one for now
+ }
+}
+
+void KNotificationBackend::notificationActivated(uint notificationId) {
+ QHash<KNotification *, uint>::iterator i = _notificationIds.begin();
+ while(i != _notificationIds.end()) {
+ if(i.value() == notificationId)
+ i = _notificationIds.erase(i);
+ else
+ ++i;
+ }
+
+ QtUi::mainWindow()->systemTray()->setInhibitActivation();
+ emit activated(notificationId);
+
+ if(!_notificationIds.count())
+ QtUi::mainWindow()->systemTray()->setAlert(false);
+
}
void KNotificationBackend::notificationClosed() {
#ifndef KNOTIFICATIONBACKEND_H_
#define KNOTIFICATIONBACKEND_H_
+#include <KSystemTrayIcon>
+
#include "abstractnotificationbackend.h"
#include "settingspage.h"
private slots:
void notificationActivated();
+ void notificationActivated(QSystemTrayIcon::ActivationReason);
+ void notificationActivated(uint notificationId);
void notificationClosed();
private:
# include <KStatusBar>
#endif
+#ifdef Q_WS_X11
+# include <QX11Info>
+#endif
+
#include "aboutdlg.h"
#include "awaylogfilter.h"
#include "awaylogview.h"
_titleSetter(this),
_awayLog(0)
{
+#ifdef Q_WS_WIN
+ dwTickCount = 0;
+#endif
+
QtUiSettings uiSettings;
QString style = uiSettings.value("Style", QString()).toString();
if(!style.isEmpty()) {
void MainWin::setupSystray() {
_systemTray = new SystemTray(this);
-
-#ifndef Q_WS_MAC
- connect(systemTray(), SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(systrayActivated(QSystemTrayIcon::ActivationReason)));
-#endif
-
}
void MainWin::setupToolBars() {
#endif
}
-void MainWin::changeEvent(QEvent *event) {
- if(event->type() == QEvent::WindowStateChange) {
- if(windowState() & Qt::WindowMinimized) {
- QtUiSettings s;
- if(s.value("UseSystemTrayIcon").toBool() && s.value("MinimizeOnMinimize").toBool()) {
- hideToTray();
- event->accept();
- }
- }
- }
-}
-
void MainWin::connectedToCore() {
Q_CHECK_PTR(Client::bufferViewManager());
connect(Client::bufferViewManager(), SIGNAL(bufferViewConfigAdded(int)), this, SLOT(addBufferView(int)));
}
}
-void MainWin::systrayActivated(QSystemTrayIcon::ActivationReason activationReason) {
- if(activationReason == QSystemTrayIcon::Trigger) {
- toggleMinimizedToTray();
+bool MainWin::event(QEvent *event) {
+ if(event->type() == QEvent::WindowActivate)
+ QtUi::closeNotifications();
+ return QMainWindow::event(event);
+}
+
+void MainWin::changeEvent(QEvent *event) {
+ if(event->type() == QEvent::WindowStateChange) {
+ if(windowState() & Qt::WindowMinimized) {
+ QtUiSettings s;
+ if(s.value("UseSystemTrayIcon").toBool() && s.value("MinimizeOnMinimize").toBool()) {
+ hideToTray();
+ event->accept();
+ return;
+ }
+ }
}
+
+#ifdef Q_WS_WIN
+ else if(event->type() == QEvent::ActivationChange)
+ dwTickCount = GetTickCount(); // needed for toggleMinimizedToTray()
+#endif
+
+ event->ignore();
}
void MainWin::hideToTray() {
qWarning() << Q_FUNC_INFO << "was called with no SystemTray available!";
return;
}
- clearFocus();
hide();
systemTray()->setIconVisible();
}
void MainWin::toggleMinimizedToTray() {
+#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 :)
+ // courtesy: KSystemTrayIcon
+ if(GetTickCount() - dwTickCount >= 300)
+ // we weren't active in the last 300ms -> activate
+ forceActivated();
+ else
+ hideToTray();
+
+#else
+
+ if(!isVisible() || isMinimized())
+ // restore
+ forceActivated();
+ else
+ hideToTray();
+
+#endif
+}
+
+void MainWin::forceActivated() {
+#ifdef Q_WS_X11
+ // Bypass focus stealing prevention
+ QX11Info::setAppUserTime(QX11Info::appTime());
+#endif
+
if(windowState() & Qt::WindowMinimized) {
// restore
setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
- show();
- activateWindow();
- raise();
- } else {
- setWindowState((windowState() & ~Qt::WindowActive) | Qt::WindowMinimized);
- hideToTray();
}
+
+ move(frameGeometry().topLeft()); // avoid placement policies
+ show();
+ raise();
+ activateWindow();
}
void MainWin::messagesInserted(const QModelIndex &parent, int start, int end) {
}
}
-bool MainWin::event(QEvent *event) {
- if(event->type() == QEvent::WindowActivate)
- QtUi::closeNotifications();
- return QMainWindow::event(event);
-}
-
void MainWin::clientNetworkCreated(NetworkId id) {
const Network *net = Client::network(id);
QAction *act = new QAction(net->networkName(), this);
# include <QMainWindow>
#endif
+#ifdef Q_WS_WIN
+# include <windows.h>
+#endif
+
#include <QSystemTrayIcon>
#include "qtui.h"
inline SystemTray *systemTray() const;
- virtual bool event(QEvent *event);
+ bool event(QEvent *event);
static void flagRemoteCoreOnly(QObject *object) { object->setProperty("REMOTE_CORE_ONLY", true); }
static bool isRemoteCoreOnly(QObject *object) { return object->property("REMOTE_CORE_ONLY").toBool(); }
void saveStateToSessionSettings(SessionSettings &s);
void showStatusBarMessage(const QString &message);
+ void toggleMinimizedToTray();
+
+ //! Bring window to front and focus it
+ void forceActivated();
+
protected:
void closeEvent(QCloseEvent *event);
- virtual void changeEvent(QEvent *event);
+ void changeEvent(QEvent *event);
protected slots:
void connectedToCore();
void updateLagIndicator(int lag = -1);
void disconnectedFromCore();
void setDisconnectedState();
- void systrayActivated(QSystemTrayIcon::ActivationReason);
private slots:
void addBufferView(int bufferViewConfigId);
void setupToolBars();
void updateIcon();
- void hideToTray();
- void toggleMinimizedToTray();
void enableMenus();
+ void hideToTray();
+
SystemTray *_systemTray;
QList<BufferViewDock *> _bufferViews;
QWidget *_awayLog;
friend class QtUi;
+
+#ifdef Q_WS_WIN
+ DWORD dwTickCount;
+#endif
};
SystemTray *MainWin::systemTray() const {
BufferId bufId = (*i).bufferId;
if(bufId.isValid())
Client::bufferModel()->switchToBuffer(bufId);
+ foreach(AbstractNotificationBackend *backend, _notificationBackends)
+ backend->close(notificationId);
_notifications.erase(i);
break;
} else ++i;
}
}
-#ifdef Q_WS_X11
- // Bypass focus stealing prevention
- QX11Info::setAppUserTime(QX11Info::appTime());
-#endif
-
- if(_mainWin->windowState() & Qt::WindowMinimized) {
- // restore
- _mainWin->setWindowState((_mainWin->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
- _mainWin->show();
- }
- _mainWin->raise();
- _mainWin->activateWindow();
+ mainWindow()->forceActivated();
}
: QObject(parent),
_state(Inactive),
_alert(false),
+ _inhibitActivation(false),
_currentIdx(0)
{
loadAnimations();
_currentIdx = _idxOffEnd;
- _trayIcon = new QSystemTrayIcon(_phases.at(_currentIdx), this);
+
+#ifndef HAVE_KDE
+ _trayIcon = new QSystemTrayIcon(_phases.at(_currentIdx), QtUi::mainWindow());
+#else
+ _trayIcon = new KSystemTrayIcon(_phases.at(_currentIdx), QtUi::mainWindow());
+ // We don't want to trigger a minimize if a highlight is pending, so we brutally remove the internal connection for that
+ disconnect(_trayIcon, SIGNAL(activated( QSystemTrayIcon::ActivationReason)),
+ _trayIcon, SLOT(activateOrHide(QSystemTrayIcon::ActivationReason)));
+#endif
_animationTimer.setInterval(150);
_animationTimer.setSingleShot(false);
_trayIcon->show();
}
- connect(_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SIGNAL(activated(QSystemTrayIcon::ActivationReason)));
+ qApp->installEventFilter(this);
+
+#ifndef Q_WS_MAC
+ connect(_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SLOT(on_activated(QSystemTrayIcon::ActivationReason)));
+#endif
connect(_trayIcon, SIGNAL(messageClicked()), SIGNAL(messageClicked()));
}
void SystemTray::showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon icon, int millisecondsTimeoutHint) {
_trayIcon->showMessage(title, message, icon, millisecondsTimeoutHint);
}
+
+bool SystemTray::eventFilter(QObject *obj, QEvent *event) {
+ Q_UNUSED(obj);
+ if(event->type() == QEvent::MouseButtonRelease) {
+ _inhibitActivation = false;
+ }
+ return false;
+}
+
+void SystemTray::on_activated(QSystemTrayIcon::ActivationReason reason) {
+ emit activated(reason);
+
+ if(reason == QSystemTrayIcon::Trigger && !_inhibitActivation) {
+
+# ifdef HAVE_KDE
+ // the slot is private, but meh, who cares :)
+ QMetaObject::invokeMethod(_trayIcon, "activateOrHide", Q_ARG(QSystemTrayIcon::ActivationReason, QSystemTrayIcon::Trigger));
+# else
+ QtUi::mainWindow()->toggleMinimizedToTray();
+# endif
+
+ }
+}
#ifndef SYSTEMTRAY_H_
#define SYSTEMTRAY_H_
-#include <QSystemTrayIcon>
+#ifdef HAVE_KDE
+# include <KSystemTrayIcon>
+#else
+# include <QSystemTrayIcon>
+#endif
+
#include <QTimer>
#include "icon.h"
~SystemTray();
inline bool isSystemTrayAvailable() const;
- Icon icon() const;
- QString toolTip() const;
+ inline bool isAlerted() const;
+
+ inline void setInhibitActivation();
public slots:
void setState(State);
void showMessage(const QString &title, const QString &message,
QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information, int millisecondsTimeoutHint = 10000);
-
signals:
void activated(QSystemTrayIcon::ActivationReason);
void iconChanged(const Icon &);
void messageClicked();
+protected:
+ bool eventFilter(QObject *obj, QEvent *event);
+
private slots:
void nextPhase();
+ void on_activated(QSystemTrayIcon::ActivationReason);
private:
void loadAnimations();
+#ifdef HAVE_KDE
+ KSystemTrayIcon *_trayIcon;
+#else
QSystemTrayIcon *_trayIcon;
+#endif
+
QMenu *_trayMenu;
State _state;
bool _alert;
+ bool _inhibitActivation;
int _idxOffStart, _idxOffEnd, _idxOnStart, _idxOnEnd, _idxAlertStart;
int _currentIdx;
// inlines
bool SystemTray::isSystemTrayAvailable() const { return QSystemTrayIcon::isSystemTrayAvailable(); }
+bool SystemTray::isAlerted() const { return _alert; }
+void SystemTray::setInhibitActivation() { _inhibitActivation = true; }
#endif
notificationSettings.notify("Systray/Animate", this, SLOT(animateChanged(const QVariant &)));
connect(QtUi::mainWindow()->systemTray(), SIGNAL(messageClicked()), SLOT(notificationActivated()));
+ connect(QtUi::mainWindow()->systemTray(), SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
+ SLOT(notificationActivated(QSystemTrayIcon::ActivationReason)));
}
void SystrayNotificationBackend::notify(const Notification ¬ification) {
if(_notifications.isEmpty()) {
*/
_notifications.clear();
+ _activeId = 0;
closeBubble();
QtUi::mainWindow()->systemTray()->setAlert(false);
}
void SystrayNotificationBackend::showBubble() {
// fancy stuff later: show messages in order
// for now, we just show the last message
- if(_notifications.isEmpty()) return;
+ if(_notifications.isEmpty())
+ return;
Notification n = _notifications.takeLast();
_activeId = n.notificationId;
QString title = Client::networkModel()->networkName(n.bufferId) + " - " + Client::networkModel()->bufferName(n.bufferId);
}
void SystrayNotificationBackend::notificationActivated() {
- emit activated(_activeId);
+ if(QtUi::mainWindow()->systemTray()->isAlerted()) {
+ QtUi::mainWindow()->systemTray()->setInhibitActivation();
+ emit activated(_activeId);
+ }
+}
+
+void SystrayNotificationBackend::notificationActivated(QSystemTrayIcon::ActivationReason reason) {
+ if(reason == QSystemTrayIcon::Trigger) {
+ notificationActivated();
+ }
}
void SystrayNotificationBackend::showBubbleChanged(const QVariant &v) {
#ifndef SYSTRAYNOTIFICATIONBACKEND_H_
#define SYSTRAYNOTIFICATIONBACKEND_H_
+#include <QSystemTrayIcon>
+
#include "abstractnotificationbackend.h"
#include "settingspage.h"
void showBubble();
void closeBubble();
void notificationActivated();
+ void notificationActivated(QSystemTrayIcon::ActivationReason);
void animateChanged(const QVariant &);
void showBubbleChanged(const QVariant &);