Fix includes
[quassel.git] / src / qtui / statusnotifieritemdbus.cpp
1 /***************************************************************************
2  *   The original file is part of the KDE libraries                        *
3  *   Copyright (C) 2009 by Marco Martin <notmart@gmail.com>                *
4  *   Quasselfied 2010 by Manuel Nickschas <sputnick@quassel-irc.org>       *
5  *                                                                         *
6  *   This file is free software; you can redistribute it and/or modify     *
7  *   it under the terms of the GNU Library General Public License (LGPL)   *
8  *   as published by the Free Software Foundation; either version 2 of the *
9  *   License, or (at your option) any later version.                       *
10  *                                                                         *
11  *   This program is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14  *   GNU General Public License for more details.                          *
15  *                                                                         *
16  *   You should have received a copy of the GNU General Public License     *
17  *   along with this program; if not, write to the                         *
18  *   Free Software Foundation, Inc.,                                       *
19  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
20  ***************************************************************************/
21
22 #include "mainwin.h"
23 #include "qtui.h"
24 #include "statusnotifieritemdbus.h"
25 #include "statusnotifieritem.h"
26
27 #include <QDBusConnection>
28 #include <QPixmap>
29 #include <QImage>
30 #include <QApplication>
31 #include <QMenu>
32 #include <QMovie>
33
34 #ifdef HAVE_KDE
35 #  include <KWindowInfo>
36 #  include <KWindowSystem>
37 #endif
38
39 #include "statusnotifierwatcher.h"
40 #include "statusnotifieritemadaptor.h"
41
42 #ifdef Q_OS_WIN64
43 __inline int toInt(WId wid)
44 {
45         return (int)((__int64)wid);
46 }
47
48 #else
49 __inline int toInt(WId wid)
50 {
51         return (int)wid;
52 }
53 #endif
54
55 // Marshall the ImageStruct data into a D-BUS argument
56 const QDBusArgument &operator<<(QDBusArgument &argument, const DBusImageStruct &icon)
57 {
58     argument.beginStructure();
59     argument << icon.width;
60     argument << icon.height;
61     argument << icon.data;
62     argument.endStructure();
63     return argument;
64 }
65
66 // Retrieve the ImageStruct data from the D-BUS argument
67 const QDBusArgument &operator>>(const QDBusArgument &argument, DBusImageStruct &icon)
68 {
69     qint32 width;
70     qint32 height;
71     QByteArray data;
72
73     argument.beginStructure();
74     argument >> width;
75     argument >> height;
76     argument >> data;
77     argument.endStructure();
78
79     icon.width = width;
80     icon.height = height;
81     icon.data = data;
82
83     return argument;
84 }
85
86
87 // Marshall the ImageVector data into a D-BUS argument
88 const QDBusArgument &operator<<(QDBusArgument &argument, const DBusImageVector &iconVector)
89 {
90     argument.beginArray(qMetaTypeId<DBusImageStruct>());
91     for (int i=0; i<iconVector.size(); ++i) {
92         argument << iconVector[i];
93     }
94     argument.endArray();
95     return argument;
96 }
97
98 // Retrieve the ImageVector data from the D-BUS argument
99 const QDBusArgument &operator>>(const QDBusArgument &argument, DBusImageVector &iconVector)
100 {
101     argument.beginArray();
102     iconVector.clear();
103
104     while ( !argument.atEnd() ) {
105        DBusImageStruct element;
106        argument >> element;
107        iconVector.append(element);
108     }
109
110     argument.endArray();
111
112
113     return argument;
114 }
115
116 // Marshall the ToolTipStruct data into a D-BUS argument
117 const QDBusArgument &operator<<(QDBusArgument &argument, const DBusToolTipStruct &toolTip)
118 {
119     argument.beginStructure();
120     argument << toolTip.icon;
121     argument << toolTip.image;
122     argument << toolTip.title;
123     argument << toolTip.subTitle;
124     argument.endStructure();
125     return argument;
126 }
127
128 // Retrieve the ToolTipStruct data from the D-BUS argument
129 const QDBusArgument &operator>>(const QDBusArgument &argument, DBusToolTipStruct &toolTip)
130 {
131     QString icon;
132     DBusImageVector image;
133     QString title;
134     QString subTitle;
135
136     argument.beginStructure();
137     argument >> icon;
138     argument >> image;
139     argument >> title;
140     argument >> subTitle;
141     argument.endStructure();
142
143     toolTip.icon = icon;
144     toolTip.image = image;
145     toolTip.title = title;
146     toolTip.subTitle = subTitle;
147
148     return argument;
149 }
150
151
152 int StatusNotifierItemDBus::s_serviceCount = 0;
153
154 StatusNotifierItemDBus::StatusNotifierItemDBus(StatusNotifierItem *parent)
155   : QObject(parent),
156     m_statusNotifierItem(parent),
157     m_service(QString("org.kde.StatusNotifierItem-%1-%2")
158                       .arg(QCoreApplication::applicationPid())
159                       .arg(++s_serviceCount)),
160     m_dbus(QDBusConnection::connectToBus(QDBusConnection::SessionBus, m_service))
161 {
162    new StatusNotifierItemAdaptor(this);
163    //qDebug() << "service is" << m_service;
164    registerService();
165 }
166
167 StatusNotifierItemDBus::~StatusNotifierItemDBus()
168 {
169     unregisterService();
170 }
171
172 QDBusConnection StatusNotifierItemDBus::dbusConnection() const
173 {
174     return m_dbus;
175 }
176
177 // FIXME: prevent double registrations, also test this on platforms != KDE
178 //
179 void StatusNotifierItemDBus::registerService()
180 {
181     //qDebug() << "registering to" << m_service;
182     m_dbus.registerService(m_service);
183     m_dbus.registerObject("/StatusNotifierItem", this);
184 }
185
186 // FIXME: see above
187 void StatusNotifierItemDBus::unregisterService()
188 {
189     //qDebug() << "unregistering from" << m_service;
190     if(m_dbus.isConnected()) {
191         m_dbus.unregisterObject("/StatusNotifierItem");
192         m_dbus.unregisterService(m_service);
193     }
194 }
195
196 QString StatusNotifierItemDBus::service() const
197 {
198     return m_service;
199 }
200
201 //DBUS slots
202 //Values and calls have been adapted to Quassel
203
204 QString StatusNotifierItemDBus::Category() const
205 {
206     return QString("Communications"); // no need to make this configurable for Quassel
207 }
208
209 QString StatusNotifierItemDBus::Title() const
210 {
211     return m_statusNotifierItem->title();
212 }
213
214 QString StatusNotifierItemDBus::Id() const
215 {
216     return QString("QuasselIRC");
217 }
218
219 QString StatusNotifierItemDBus::Status() const
220 {
221     return m_statusNotifierItem->metaObject()->enumerator(m_statusNotifierItem->metaObject()->indexOfEnumerator("State")).valueToKey(m_statusNotifierItem->state());
222 }
223
224 int StatusNotifierItemDBus::WindowId() const
225 {
226     return toInt(QtUi::mainWindow()->winId());
227 }
228
229
230 //Icon
231 //We don't need to support serialized icon data in Quassel
232
233 QString StatusNotifierItemDBus::IconName() const
234 {
235     return m_statusNotifierItem->iconName();
236 }
237
238 DBusImageVector StatusNotifierItemDBus::IconPixmap() const
239 {
240     return DBusImageVector();
241 }
242
243 QString StatusNotifierItemDBus::OverlayIconName() const
244 {
245     return QString();
246 }
247
248 DBusImageVector StatusNotifierItemDBus::OverlayIconPixmap() const
249 {
250     return DBusImageVector();
251 }
252
253 //Requesting attention icon and movie
254
255 QString StatusNotifierItemDBus::AttentionIconName() const
256 {
257     return m_statusNotifierItem->attentionIconName();
258 }
259
260 DBusImageVector StatusNotifierItemDBus::AttentionIconPixmap() const
261 {
262     return DBusImageVector();
263 }
264
265 QString StatusNotifierItemDBus::AttentionMovieName() const
266 {
267     return QString();
268 }
269
270
271 //ToolTip
272
273 DBusToolTipStruct StatusNotifierItemDBus::ToolTip() const
274 {
275     DBusToolTipStruct toolTip;
276     toolTip.icon = m_statusNotifierItem->toolTipIconName();
277     toolTip.image = DBusImageVector();
278     toolTip.title = m_statusNotifierItem->toolTipTitle();
279     toolTip.subTitle = m_statusNotifierItem->toolTipSubTitle();
280
281     return toolTip;
282 }
283
284 QString StatusNotifierItemDBus::IconThemePath() const
285 {
286     return m_statusNotifierItem->iconThemePath();
287 }
288
289 //Menu
290
291 QDBusObjectPath StatusNotifierItemDBus::Menu() const
292 {
293     return QDBusObjectPath(m_statusNotifierItem->menuObjectPath());
294 }
295
296
297 //Interaction
298
299 void StatusNotifierItemDBus::ContextMenu(int x, int y)
300 {
301     if (!m_statusNotifierItem->trayMenu()) {
302         return;
303     }
304
305     //TODO: nicer placement, possible?
306     if (!m_statusNotifierItem->trayMenu()->isVisible()) {
307 #ifdef HAVE_KDE
308         m_statusNotifierItem->trayMenu()->setWindowFlags(Qt::Window|Qt::FramelessWindowHint);
309 #endif
310         m_statusNotifierItem->trayMenu()->popup(QPoint(x,y));
311 #ifdef HAVE_KDE
312         KWindowSystem::setState(m_statusNotifierItem->trayMenu()->winId(), NET::SkipTaskbar|NET::SkipPager|NET::KeepAbove);
313         KWindowSystem::setType(m_statusNotifierItem->trayMenu()->winId(), NET::PopupMenu);
314         KWindowSystem::forceActiveWindow(m_statusNotifierItem->trayMenu()->winId());
315 #endif
316     } else {
317         m_statusNotifierItem->trayMenu()->hide();
318     }
319 }
320
321 void StatusNotifierItemDBus::Activate(int x, int y)
322 {
323     m_statusNotifierItem->activated(QPoint(x,y));
324 }
325
326 void StatusNotifierItemDBus::SecondaryActivate(int x, int y)
327 {
328     Q_UNUSED(x)
329     Q_UNUSED(y)
330     // emit m_statusNotifierItem->secondaryActivateRequested(QPoint(x,y));
331 }
332
333 void StatusNotifierItemDBus::Scroll(int delta, const QString &orientation)
334 {
335     Q_UNUSED(delta)
336     Q_UNUSED(orientation)
337     // Qt::Orientation dir = (orientation.toLower() == "horizontal" ? Qt::Horizontal : Qt::Vertical);
338     // emit m_statusNotifierItem->scrollRequested(delta, dir);
339 }