Refactor the system tray's context menu
[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 General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (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 "statusnotifieritemdbus.h"
23 #include "statusnotifieritem.h"
24 #include "qtui.h"
25
26 #include <QDBusConnection>
27 #include <QPixmap>
28 #include <QImage>
29 #include <QApplication>
30 #include <QMenu>
31 #include <QMovie>
32
33 #ifdef HAVE_KDE
34 #  include <KWindowInfo>
35 #  include <KWindowSystem>
36 #endif
37
38 #include "statusnotifierwatcher.h"
39 #include "statusnotifieritemadaptor.h"
40
41 // Marshall the ImageStruct data into a D-BUS argument
42 const QDBusArgument &operator<<(QDBusArgument &argument, const DBusImageStruct &icon)
43 {
44     argument.beginStructure();
45     argument << icon.width;
46     argument << icon.height;
47     argument << icon.data;
48     argument.endStructure();
49     return argument;
50 }
51
52 // Retrieve the ImageStruct data from the D-BUS argument
53 const QDBusArgument &operator>>(const QDBusArgument &argument, DBusImageStruct &icon)
54 {
55     qint32 width;
56     qint32 height;
57     QByteArray data;
58
59     argument.beginStructure();
60     argument >> width;
61     argument >> height;
62     argument >> data;
63     argument.endStructure();
64
65     icon.width = width;
66     icon.height = height;
67     icon.data = data;
68
69     return argument;
70 }
71
72
73 // Marshall the ImageVector data into a D-BUS argument
74 const QDBusArgument &operator<<(QDBusArgument &argument, const DBusImageVector &iconVector)
75 {
76     argument.beginArray(qMetaTypeId<DBusImageStruct>());
77     for (int i=0; i<iconVector.size(); ++i) {
78         argument << iconVector[i];
79     }
80     argument.endArray();
81     return argument;
82 }
83
84 // Retrieve the ImageVector data from the D-BUS argument
85 const QDBusArgument &operator>>(const QDBusArgument &argument, DBusImageVector &iconVector)
86 {
87     argument.beginArray();
88     iconVector.clear();
89
90     while ( !argument.atEnd() ) {
91        DBusImageStruct element;
92        argument >> element;
93        iconVector.append(element);
94     }
95
96     argument.endArray();
97
98
99     return argument;
100 }
101
102 // Marshall the ToolTipStruct data into a D-BUS argument
103 const QDBusArgument &operator<<(QDBusArgument &argument, const DBusToolTipStruct &toolTip)
104 {
105     argument.beginStructure();
106     argument << toolTip.icon;
107     argument << toolTip.image;
108     argument << toolTip.title;
109     argument << toolTip.subTitle;
110     argument.endStructure();
111     return argument;
112 }
113
114 // Retrieve the ToolTipStruct data from the D-BUS argument
115 const QDBusArgument &operator>>(const QDBusArgument &argument, DBusToolTipStruct &toolTip)
116 {
117     QString icon;
118     DBusImageVector image;
119     QString title;
120     QString subTitle;
121
122     argument.beginStructure();
123     argument >> icon;
124     argument >> image;
125     argument >> title;
126     argument >> subTitle;
127     argument.endStructure();
128
129     toolTip.icon = icon;
130     toolTip.image = image;
131     toolTip.title = title;
132     toolTip.subTitle = subTitle;
133
134     return argument;
135 }
136
137
138 int StatusNotifierItemDBus::s_serviceCount = 0;
139
140 StatusNotifierItemDBus::StatusNotifierItemDBus(StatusNotifierItem *parent)
141   : QObject(parent),
142     m_statusNotifierItem(parent),
143     m_service(QString("org.kde.StatusNotifierItem-%1-%2")
144                       .arg(QCoreApplication::applicationPid())
145                       .arg(++s_serviceCount)),
146     m_dbus(QDBusConnection::connectToBus(QDBusConnection::SessionBus, m_service))
147 {
148    new StatusNotifierItemAdaptor(this);
149    qDebug() << "service is" << m_service;
150    m_dbus.registerService(m_service);
151    m_dbus.registerObject("/StatusNotifierItem", this);
152 }
153
154 StatusNotifierItemDBus::~StatusNotifierItemDBus()
155 {
156     m_dbus.unregisterService(m_service);
157 }
158
159 QString StatusNotifierItemDBus::service() const
160 {
161     return m_service;
162 }
163
164 //DBUS slots
165 //Values and calls have been adapted to Quassel
166
167 QString StatusNotifierItemDBus::Category() const
168 {
169     return QString("Communications"); // no need to make this configurable for Quassel
170 }
171
172 QString StatusNotifierItemDBus::Title() const
173 {
174     return m_statusNotifierItem->title();
175 }
176
177 QString StatusNotifierItemDBus::Id() const
178 {
179     return QString("QuasselIRC");
180 }
181
182 QString StatusNotifierItemDBus::Status() const
183  {
184     return m_statusNotifierItem->metaObject()->enumerator(m_statusNotifierItem->metaObject()->indexOfEnumerator("State")).valueToKey(m_statusNotifierItem->state());
185 }
186
187 int StatusNotifierItemDBus::WindowId() const
188 {
189     return (int)QtUi::mainWindow()->winId();
190 }
191
192
193 //Icon
194 //We don't need to support serialized icon data in Quassel
195
196 QString StatusNotifierItemDBus::IconName() const
197 {
198     return m_statusNotifierItem->iconName();
199 }
200
201 DBusImageVector StatusNotifierItemDBus::IconPixmap() const
202 {
203     return DBusImageVector();
204 }
205
206 QString StatusNotifierItemDBus::OverlayIconName() const
207 {
208     return QString();
209 }
210
211 DBusImageVector StatusNotifierItemDBus::OverlayIconPixmap() const
212 {
213     return DBusImageVector();
214 }
215
216 //Requesting attention icon and movie
217
218 QString StatusNotifierItemDBus::AttentionIconName() const
219 {
220     return m_statusNotifierItem->attentionIconName();
221 }
222
223 DBusImageVector StatusNotifierItemDBus::AttentionIconPixmap() const
224 {
225     return DBusImageVector();
226 }
227
228 QString StatusNotifierItemDBus::AttentionMovieName() const
229 {
230     return QString();
231 }
232
233
234 //ToolTip
235
236 DBusToolTipStruct StatusNotifierItemDBus::ToolTip() const
237 {
238     DBusToolTipStruct toolTip;
239     toolTip.icon = m_statusNotifierItem->toolTipIconName();
240     toolTip.image = DBusImageVector();
241     toolTip.title = m_statusNotifierItem->toolTipTitle();
242     toolTip.subTitle = m_statusNotifierItem->toolTipSubTitle();
243
244     return toolTip;
245 }
246
247 //Interaction
248
249 void StatusNotifierItemDBus::ContextMenu(int x, int y)
250 {
251     if (!m_statusNotifierItem->trayMenu()) {
252         return;
253     }
254
255     //TODO: nicer placement, possible?
256     if (!m_statusNotifierItem->trayMenu()->isVisible()) {
257 #ifdef HAVE_KDE
258         m_statusNotifierItem->trayMenu()->setWindowFlags(Qt::Window|Qt::FramelessWindowHint);
259 #endif
260         m_statusNotifierItem->trayMenu()->popup(QPoint(x,y));
261 #ifdef HAVE_KDE
262         KWindowSystem::setState(m_statusNotifierItem->trayMenu()->winId(), NET::SkipTaskbar|NET::SkipPager|NET::KeepAbove);
263         KWindowSystem::setType(m_statusNotifierItem->trayMenu()->winId(), NET::PopupMenu);
264         KWindowSystem::forceActiveWindow(m_statusNotifierItem->trayMenu()->winId());
265 #endif
266     } else {
267         m_statusNotifierItem->trayMenu()->hide();
268     }
269 }
270
271 void StatusNotifierItemDBus::Activate(int x, int y)
272 {
273     m_statusNotifierItem->activated(QPoint(x,y));
274 }
275
276 void StatusNotifierItemDBus::SecondaryActivate(int x, int y)
277 {
278     Q_UNUSED(x)
279     Q_UNUSED(y)
280     // emit m_statusNotifierItem->secondaryActivateRequested(QPoint(x,y));
281 }
282
283 void StatusNotifierItemDBus::Scroll(int delta, const QString &orientation)
284 {
285     Q_UNUSED(delta)
286     Q_UNUSED(orientation)
287     // Qt::Orientation dir = (orientation.toLower() == "horizontal" ? Qt::Horizontal : Qt::Vertical);
288     // emit m_statusNotifierItem->scrollRequested(delta, dir);
289 }