690ed9e4f21d1b4b0b49172b3fbd7e92be27eb76
[quassel.git] / src / qtui / statusnotifieritem.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2010 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This contains code from KStatusNotifierItem, part of the KDE libs     *
6  *   Copyright (C) 2009 Marco Martin <notmart@gmail.com>                   *
7  *                                                                         *
8  *   This program is free software; you can redistribute it and/or modify  *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation; either version 2 of the License, or     *
11  *   (at your option) version 3.                                           *
12  *                                                                         *
13  *   This program is distributed in the hope that it will be useful,       *
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
16  *   GNU General Public License for more details.                          *
17  *                                                                         *
18  *   You should have received a copy of the GNU General Public License     *
19  *   along with this program; if not, write to the                         *
20  *   Free Software Foundation, Inc.,                                       *
21  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
22  ***************************************************************************/
23
24 #ifdef HAVE_DBUS
25
26 #include "statusnotifieritem.h"
27 #include "statusnotifieritemdbus.h"
28
29 #include <QMenu>
30 #include <QMouseEvent>
31
32 const int StatusNotifierItem::_protocolVersion = 0;
33
34 StatusNotifierItem::StatusNotifierItem(QWidget *parent)
35   : StatusNotifierItemParent(parent),
36   _statusNotifierItemDBus(0),
37   _statusNotifierWatcher(0)
38 {
39
40 }
41
42 StatusNotifierItem::~StatusNotifierItem() {
43   delete _statusNotifierWatcher;
44
45 }
46
47 void StatusNotifierItem::init() {
48   qDBusRegisterMetaType<DBusImageStruct>();
49   qDBusRegisterMetaType<DBusImageVector>();
50   qDBusRegisterMetaType<DBusToolTipStruct>();
51
52   _statusNotifierItemDBus = new StatusNotifierItemDBus(this);
53   connect(this, SIGNAL(toolTipChanged(QString,QString)), _statusNotifierItemDBus, SIGNAL(NewToolTip()));
54
55   connect(QDBusConnection::sessionBus().interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)),
56                                                      SLOT(serviceChange(QString,QString,QString)));
57
58   setMode(StatusNotifier);
59
60   StatusNotifierItemParent::init();
61   trayMenu()->installEventFilter(this);
62 }
63
64 void StatusNotifierItem::registerToDaemon() {
65   if(!_statusNotifierWatcher) {
66     QString interface("org.kde.StatusNotifierWatcher");
67     _statusNotifierWatcher = new org::kde::StatusNotifierWatcher(interface, "/StatusNotifierWatcher",
68                                                                  QDBusConnection::sessionBus());
69   }
70   if(_statusNotifierWatcher->isValid()
71     && _statusNotifierWatcher->property("ProtocolVersion").toInt() == _protocolVersion) {
72
73     _statusNotifierWatcher->RegisterStatusNotifierItem(_statusNotifierItemDBus->service());
74
75   } else {
76     qDebug() << "StatusNotifierWatcher not reachable!";
77     setMode(Legacy);
78   }
79 }
80
81 // FIXME remove deprecated slot with Qt 4.6
82 void StatusNotifierItem::serviceChange(const QString& name, const QString& oldOwner, const QString& newOwner) {
83   bool legacy = false;
84   if(name == "org.kde.StatusNotifierWatcher") {
85     if(newOwner.isEmpty()) {
86       //unregistered
87       //qDebug() << "Connection to the StatusNotifierWatcher lost";
88       legacy = true;
89     } else if(oldOwner.isEmpty()) {
90       //registered
91       legacy = false;
92     }
93   } else if(name.startsWith(QLatin1String("org.kde.StatusNotifierHost-"))) {
94     if(newOwner.isEmpty() && (!_statusNotifierWatcher ||
95                               !_statusNotifierWatcher->property("IsStatusNotifierHostRegistered").toBool())) {
96       //qDebug() << "Connection to the last StatusNotifierHost lost";
97       legacy = true;
98     } else if(oldOwner.isEmpty()) {
99       //qDebug() << "New StatusNotifierHost";
100       legacy = false;
101     }
102   } else {
103     return;
104   }
105
106   // qDebug() << "Service " << name << "status change, old owner:" << oldOwner << "new:" << newOwner;
107
108   if(legacy == (mode() == Legacy)) {
109     return;
110   }
111
112   if(legacy) {
113     //unregistered
114     setMode(Legacy);
115   } else {
116     //registered
117     setMode(StatusNotifier);
118   }
119 }
120
121 void StatusNotifierItem::setMode(Mode mode_) {
122   StatusNotifierItemParent::setMode(mode_);
123
124   if(mode() == StatusNotifier) {
125     registerToDaemon();
126   }
127 }
128
129 void StatusNotifierItem::setState(State state_) {
130   StatusNotifierItemParent::setState(state_);
131
132   emit _statusNotifierItemDBus->NewStatus(metaObject()->enumerator(metaObject()->indexOfEnumerator("State")).valueToKey(state()));
133   emit _statusNotifierItemDBus->NewIcon();
134 }
135
136 QString StatusNotifierItem::title() const {
137   return QString("Quassel IRC");
138 }
139
140 QString StatusNotifierItem::iconName() const {
141   if(state() == Passive)
142     return QString("quassel_inactive");
143   else
144     return QString("quassel");
145 }
146
147 QString StatusNotifierItem::attentionIconName() const {
148   return QString("quassel_message");
149 }
150
151 QString StatusNotifierItem::toolTipIconName() const {
152   return QString("quassel");
153 }
154
155 void StatusNotifierItem::activated(const QPoint &pos) {
156   Q_UNUSED(pos)
157   activate(Trigger);
158 }
159
160 bool StatusNotifierItem::eventFilter(QObject *watched, QEvent *event) {
161   if(mode() == StatusNotifier) {
162     //FIXME: ugly ugly workaround to weird QMenu's focus problems
163 #ifdef HAVE_KDE
164     if(watched == trayMenu() &&
165        (event->type() == QEvent::WindowDeactivate || (event->type() == QEvent::MouseButtonRelease && static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton))) {
166       // put at the back of event queue to let the action activate anyways
167       QTimer::singleShot(0, trayMenu(), SLOT(hide()));
168     }
169 #else
170     if(watched == trayMenu() && event->type() == QEvent::HoverLeave) {
171       trayMenu()->hide();
172     }
173 #endif
174   }
175   return StatusNotifierItemParent::eventFilter(watched, event);
176 }
177
178 #endif