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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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
49#else
50__inline int toInt(WId wid)
51{
52 return (int)wid;
53}
54
55
56#endif
57
58// Marshall the ImageStruct data into a D-BUS argument
59const QDBusArgument &operator<<(QDBusArgument &argument, const DBusImageStruct &icon)
60{
61 argument.beginStructure();
62 argument << icon.width;
63 argument << icon.height;
64 argument << icon.data;
65 argument.endStructure();
66 return argument;
67}
68
69
70// Retrieve the ImageStruct data from the D-BUS argument
71const QDBusArgument &operator>>(const QDBusArgument &argument, DBusImageStruct &icon)
72{
73 qint32 width;
74 qint32 height;
75 QByteArray data;
76
77 argument.beginStructure();
78 argument >> width;
79 argument >> height;
80 argument >> data;
81 argument.endStructure();
82
83 icon.width = width;
84 icon.height = height;
85 icon.data = data;
86
87 return argument;
88}
89
90
91// Marshall the ImageVector data into a D-BUS argument
92const QDBusArgument &operator<<(QDBusArgument &argument, const DBusImageVector &iconVector)
93{
94 argument.beginArray(qMetaTypeId<DBusImageStruct>());
95 for (int i = 0; i < iconVector.size(); ++i) {
96 argument << iconVector[i];
97 }
98 argument.endArray();
99 return argument;
100}
101
102
103// Retrieve the ImageVector data from the D-BUS argument
104const QDBusArgument &operator>>(const QDBusArgument &argument, DBusImageVector &iconVector)
105{
106 argument.beginArray();
107 iconVector.clear();
108
109 while (!argument.atEnd()) {
110 DBusImageStruct element;
111 argument >> element;
112 iconVector.append(element);
113 }
114
115 argument.endArray();
116
117 return argument;
118}
119
120
121// Marshall the ToolTipStruct data into a D-BUS argument
122const QDBusArgument &operator<<(QDBusArgument &argument, const DBusToolTipStruct &toolTip)
123{
124 argument.beginStructure();
125 argument << toolTip.icon;
126 argument << toolTip.image;
127 argument << toolTip.title;
128 argument << toolTip.subTitle;
129 argument.endStructure();
130 return argument;
131}
132
133
134// Retrieve the ToolTipStruct data from the D-BUS argument
135const QDBusArgument &operator>>(const QDBusArgument &argument, DBusToolTipStruct &toolTip)
136{
137 QString icon;
138 DBusImageVector image;
139 QString title;
140 QString subTitle;
141
142 argument.beginStructure();
143 argument >> icon;
144 argument >> image;
145 argument >> title;
146 argument >> subTitle;
147 argument.endStructure();
148
149 toolTip.icon = icon;
150 toolTip.image = image;
151 toolTip.title = title;
152 toolTip.subTitle = subTitle;
153
154 return argument;
155}
156
157
158int StatusNotifierItemDBus::s_serviceCount = 0;
159
160StatusNotifierItemDBus::StatusNotifierItemDBus(StatusNotifierItem *parent)
161 : QObject(parent),
162 m_statusNotifierItem(parent),
163 m_service(QString("org.kde.StatusNotifierItem-%1-%2")
164 .arg(QCoreApplication::applicationPid())
165 .arg(++s_serviceCount)),
166 m_dbus(QDBusConnection::connectToBus(QDBusConnection::SessionBus, m_service))
167{
168 new StatusNotifierItemAdaptor(this);
169 //qDebug() << "service is" << m_service;
170 registerService();
171}
172
173
174StatusNotifierItemDBus::~StatusNotifierItemDBus()
175{
176 unregisterService();
177}
178
179
180QDBusConnection StatusNotifierItemDBus::dbusConnection() const
181{
182 return m_dbus;
183}
184
185
186// FIXME: prevent double registrations, also test this on platforms != KDE
187//
188void StatusNotifierItemDBus::registerService()
189{
190 //qDebug() << "registering to" << m_service;
191 m_dbus.registerService(m_service);
192 m_dbus.registerObject("/StatusNotifierItem", this);
193}
194
195
196// FIXME: see above
197void StatusNotifierItemDBus::unregisterService()
198{
199 //qDebug() << "unregistering from" << m_service;
200 if (m_dbus.isConnected()) {
201 m_dbus.unregisterObject("/StatusNotifierItem");
202 m_dbus.unregisterService(m_service);
203 }
204}
205
206
207QString StatusNotifierItemDBus::service() const
208{
209 return m_service;
210}
211
212
213//DBUS slots
214//Values and calls have been adapted to Quassel
215
216QString StatusNotifierItemDBus::Category() const
217{
218 return QString("Communications"); // no need to make this configurable for Quassel
219}
220
221
222QString StatusNotifierItemDBus::Title() const
223{
224 return m_statusNotifierItem->title();
225}
226
227
228QString StatusNotifierItemDBus::Id() const
229{
230 return QString("QuasselIRC");
231}
232
233
234QString StatusNotifierItemDBus::Status() const
235{
236 return m_statusNotifierItem->metaObject()->enumerator(m_statusNotifierItem->metaObject()->indexOfEnumerator("State")).valueToKey(m_statusNotifierItem->state());
237}
238
239
240int StatusNotifierItemDBus::WindowId() const
241{
242 return toInt(QtUi::mainWindow()->winId());
243}
244
245
246//Icon
247//We don't need to support serialized icon data in Quassel
248
249QString StatusNotifierItemDBus::IconName() const
250{
251 return m_statusNotifierItem->iconName();
252}
253
254
255DBusImageVector StatusNotifierItemDBus::IconPixmap() const
256{
257 return DBusImageVector();
258}
259
260
261QString StatusNotifierItemDBus::OverlayIconName() const
262{
263 return QString();
264}
265
266
267DBusImageVector StatusNotifierItemDBus::OverlayIconPixmap() const
268{
269 return DBusImageVector();
270}
271
272
273//Requesting attention icon and movie
274
275QString StatusNotifierItemDBus::AttentionIconName() const
276{
277 return m_statusNotifierItem->attentionIconName();
278}
279
280
281DBusImageVector StatusNotifierItemDBus::AttentionIconPixmap() const
282{
283 return DBusImageVector();
284}
285
286
287QString StatusNotifierItemDBus::AttentionMovieName() const
288{
289 return QString();
290}
291
292
293//ToolTip
294
295DBusToolTipStruct StatusNotifierItemDBus::ToolTip() const
296{
297 DBusToolTipStruct toolTip;
298 toolTip.icon = m_statusNotifierItem->toolTipIconName();
299 toolTip.image = DBusImageVector();
300 toolTip.title = m_statusNotifierItem->toolTipTitle();
301 toolTip.subTitle = m_statusNotifierItem->toolTipSubTitle();
302
303 return toolTip;
304}
305
306
307QString StatusNotifierItemDBus::IconThemePath() const
308{
309 return m_statusNotifierItem->iconThemePath();
310}
311
312
313//Menu
314
315QDBusObjectPath StatusNotifierItemDBus::Menu() const
316{
317 return QDBusObjectPath(m_statusNotifierItem->menuObjectPath());
318}
319
320
321//Interaction
322
323void StatusNotifierItemDBus::ContextMenu(int x, int y)
324{
325 if (!m_statusNotifierItem->trayMenu()) {
326 return;
327 }
328
329 //TODO: nicer placement, possible?
330 if (!m_statusNotifierItem->trayMenu()->isVisible()) {
331#ifdef HAVE_KDE
332 m_statusNotifierItem->trayMenu()->setWindowFlags(Qt::Window|Qt::FramelessWindowHint);
333#endif
334 m_statusNotifierItem->trayMenu()->popup(QPoint(x, y));
335#ifdef HAVE_KDE
336 KWindowSystem::setState(m_statusNotifierItem->trayMenu()->winId(), NET::SkipTaskbar|NET::SkipPager|NET::KeepAbove);
337 KWindowSystem::setType(m_statusNotifierItem->trayMenu()->winId(), NET::PopupMenu);
338 KWindowSystem::forceActiveWindow(m_statusNotifierItem->trayMenu()->winId());
339#endif
340 }
341 else {
342 m_statusNotifierItem->trayMenu()->hide();
343 }
344}
345
346
347void StatusNotifierItemDBus::Activate(int x, int y)
348{
349 m_statusNotifierItem->activated(QPoint(x, y));
350}
351
352
353void StatusNotifierItemDBus::SecondaryActivate(int x, int y)
354{
355 Q_UNUSED(x)
356 Q_UNUSED(y)
357 // emit m_statusNotifierItem->secondaryActivateRequested(QPoint(x,y));
358}
359
360
361void StatusNotifierItemDBus::Scroll(int delta, const QString &orientation)
362{
363 Q_UNUSED(delta)
364 Q_UNUSED(orientation)
365 // Qt::Orientation dir = (orientation.toLower() == "horizontal" ? Qt::Horizontal : Qt::Vertical);
366 // emit m_statusNotifierItem->scrollRequested(delta, dir);
367}
368