Basic StatusNotifierItem support
authorManuel Nickschas <sputnick@quassel-irc.org>
Tue, 16 Feb 2010 15:58:24 +0000 (16:58 +0100)
committerManuel Nickschas <sputnick@quassel-irc.org>
Tue, 16 Feb 2010 15:58:24 +0000 (16:58 +0100)
This implements the new dbus spec that replaces the old systray:
<http://www.notmart.org/misc/statusnotifieritem/>

Until the spec has been ratified by freedesktop.org (which should happen soon), we're
using the org.kde namespace to get it working in newish (>= 4.4) KDE versions at least.
In order to support this even without KDE integration, we've taken a bunch of code
from KDE's implementation (written by Marco Martin), only using the parts that are
relevant for Quassel, and adapting them to our needs.

In case no DBus support is present, or noone listens for the service, we fall back
to the classical tray icon.

Various bits and pieces are still missing, e.g. tooltips, and the context menu
isn't working yet if Qt doesn't support QSystemTrayIcon (but you'll get the dbus
item if there's a service listening even without tray icon support in Qt).

interfaces/org.kde.StatusNotifierItem.xml [new file with mode: 0644]
interfaces/org.kde.StatusNotifierWatcher.xml [new file with mode: 0644]
src/qtui/CMakeLists.txt
src/qtui/mainwin.cpp
src/qtui/statusnotifieritem.cpp [new file with mode: 0644]
src/qtui/statusnotifieritem.h [new file with mode: 0644]
src/qtui/statusnotifieritemdbus.cpp [new file with mode: 0644]
src/qtui/statusnotifieritemdbus.h [new file with mode: 0644]

diff --git a/interfaces/org.kde.StatusNotifierItem.xml b/interfaces/org.kde.StatusNotifierItem.xml
new file mode 100644 (file)
index 0000000..7c3acd5
--- /dev/null
@@ -0,0 +1,91 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+  <interface name="org.kde.StatusNotifierItem">
+
+    <property name="Category" type="s" access="read"/>
+    <property name="Id" type="s" access="read"/>
+    <property name="Title" type="s" access="read"/>
+    <property name="Status" type="s" access="read"/>
+    <property name="WindowId" type="i" access="read"/>
+
+
+    <!-- main icon -->
+    <!-- names are preferred over pixmaps -->
+    <property name="IconName" type="s" access="read"/>
+
+    <!--struct containing width, height and image data-->
+    <property name="IconPixmap" type="(iiay)" access="read">
+      <annotation name="com.trolltech.QtDBus.QtTypeName" value="DBusImageVector"/>
+    </property>
+
+    <property name="OverlayIconName" type="s" access="read"/>
+
+    <property name="OverlayIconPixmap" type="(iiay)" access="read">
+      <annotation name="com.trolltech.QtDBus.QtTypeName" value="DBusImageVector"/>
+    </property>
+
+
+    <!-- Requesting attention icon -->
+    <property name="AttentionIconName" type="s" access="read"/>
+
+    <!--same definition as image-->
+    <property name="AttentionIconPixmap" type="(iiay)" access="read">
+      <annotation name="com.trolltech.QtDBus.QtTypeName" value="DBusImageVector"/>
+    </property>
+
+    <property name="AttentionMovieName" type="s" access="read"/>
+
+
+
+    <!-- tooltip data -->
+
+    <!--(iiay) is an image-->
+    <property name="ToolTip" type="(s(iiay)ss)" access="read">
+      <annotation name="com.trolltech.QtDBus.QtTypeName" value="DBusToolTipStruct"/>
+    </property>
+
+
+    <!-- interaction: the systemtray wants the application to do something -->
+    <method name="ContextMenu">
+        <!-- we're passing the coordinates of the icon, so the app knows where to put the popup window -->
+        <arg name="x" type="i" direction="in"/>
+        <arg name="y" type="i" direction="in"/>
+    </method>
+
+    <method name="Activate">
+        <arg name="x" type="i" direction="in"/>
+        <arg name="y" type="i" direction="in"/>
+    </method>
+
+    <method name="SecondaryActivate">
+        <arg name="x" type="i" direction="in"/>
+        <arg name="y" type="i" direction="in"/>
+    </method>
+
+    <method name="Scroll">
+      <arg name="delta" type="i" direction="in"/>
+      <arg name="orientation" type="s" direction="in"/>
+    </method>
+
+    <!-- Signals: the client wants to change something in the status-->
+    <signal name="NewTitle">
+    </signal>
+
+    <signal name="NewIcon">
+    </signal>
+
+    <signal name="NewAttentionIcon">
+    </signal>
+
+    <signal name="NewOverlayIcon">
+    </signal>
+
+    <signal name="NewToolTip">
+    </signal>
+
+    <signal name="NewStatus">
+      <arg name="status" type="s"/>
+    </signal>
+
+  </interface>
+</node>
diff --git a/interfaces/org.kde.StatusNotifierWatcher.xml b/interfaces/org.kde.StatusNotifierWatcher.xml
new file mode 100644 (file)
index 0000000..5e043dc
--- /dev/null
@@ -0,0 +1,39 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+  <interface name="org.kde.StatusNotifierWatcher">
+
+    <!-- methods -->
+    <method name="RegisterStatusNotifierItem">
+       <arg name="service" type="s" direction="in"/>
+    </method>
+
+    <method name="RegisterStatusNotifierHost">
+       <arg name="service" type="s" direction="in"/>
+    </method>
+
+
+    <!-- properties -->
+
+    <property name="RegisteredStatusNotifierItems" type="as" access="read">
+       <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QStringList"/>
+    </property>
+
+    <property name="IsStatusNotifierHostRegistered" type="b" access="read"/>
+
+    <property name="ProtocolVersion" type="i" access="read"/>
+
+
+    <!-- signals -->
+
+    <signal name="StatusNotifierItemRegistered">
+        <arg type="s"/>
+    </signal>
+
+    <signal name="StatusNotifierItemUnregistered">
+        <arg type="s"/>
+    </signal>
+
+    <signal name="StatusNotifierHostRegistered">
+    </signal>
+  </interface>
+</node>
index 920fe2c..4b76e97 100644 (file)
@@ -154,6 +154,14 @@ else(HAVE_KDE)
   endif(HAVE_PHONON)
 endif(HAVE_KDE)
 
+if(HAVE_DBUS)
+  set(SOURCES ${SOURCES} statusnotifieritem.cpp statusnotifieritemdbus.cpp)
+  set(MOC_HDRS ${MOC_HDRS} statusnotifieritem.h statusnotifieritemdbus.h)
+  set(FORMS ${FORMS})
+  qt4_add_dbus_interface(DBUS ../../interfaces/org.kde.StatusNotifierWatcher.xml statusnotifierwatcher)
+  qt4_add_dbus_adaptor(DBUS ../../interfaces/org.kde.StatusNotifierItem.xml statusnotifieritemdbus.h StatusNotifierItemDBus)  
+endif(HAVE_DBUS)
+
 if(HAVE_SSL)
   set(SOURCES ${SOURCES} sslinfodlg.cpp)
   set(MOC_HDRS ${MOC_HDRS} sslinfodlg.h)
index ea361d9..b2f1841 100644 (file)
@@ -79,6 +79,7 @@
 #include "qtuistyle.h"
 #include "settingsdlg.h"
 #include "settingspagedlg.h"
+#include "statusnotifieritem.h"
 #include "toolbaractionprovider.h"
 #include "topicwidget.h"
 #include "verticaldock.h"
@@ -676,7 +677,9 @@ void MainWin::saveStatusBarStatus(bool enabled) {
 }
 
 void MainWin::setupSystray() {
-#ifndef QT_NO_SYSTEMTRAYICON
+#ifdef HAVE_DBUS
+  _systemTray = new StatusNotifierItem(this);
+#elif !defined QT_NO_SYSTEMTRAYICON
   _systemTray = new LegacySystemTray(this);
 #else
   _systemTray = new SystemTray(this); // dummy
diff --git a/src/qtui/statusnotifieritem.cpp b/src/qtui/statusnotifieritem.cpp
new file mode 100644 (file)
index 0000000..da15475
--- /dev/null
@@ -0,0 +1,177 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2010 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This contains code from KStatusNotifierItem, part of the KDE libs     *
+ *   Copyright (C) 2009 Marco Martin <notmart@gmail.com>                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifdef HAVE_DBUS
+
+#include "statusnotifieritem.h"
+#include "statusnotifieritemdbus.h"
+
+#include <QMenu>
+#include <QMouseEvent>
+
+const int StatusNotifierItem::_protocolVersion = 0;
+
+StatusNotifierItem::StatusNotifierItem(QWidget *parent)
+  : StatusNotifierItemParent(parent),
+  _statusNotifierItemDBus(0),
+  _statusNotifierWatcher(0)
+{
+
+}
+
+StatusNotifierItem::~StatusNotifierItem() {
+  delete _statusNotifierWatcher;
+
+}
+
+void StatusNotifierItem::init() {
+// workaround until we handle the tray menu more sanely
+#ifdef QT_NO_SYSTEMTRAYICON
+  setTrayMenu(new QMenu(associatedWidget()));
+#endif
+
+  trayMenu()->installEventFilter(this);
+
+  qDBusRegisterMetaType<DBusImageStruct>();
+  qDBusRegisterMetaType<DBusImageVector>();
+  qDBusRegisterMetaType<DBusToolTipStruct>();
+
+  _statusNotifierItemDBus = new StatusNotifierItemDBus(this);
+
+  connect(QDBusConnection::sessionBus().interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)),
+                                                     SLOT(serviceChange(QString,QString,QString)));
+
+  setMode(StatusNotifier);
+
+  StatusNotifierItemParent::init();
+}
+
+void StatusNotifierItem::registerToDaemon() {
+  if(!_statusNotifierWatcher) {
+    QString interface("org.kde.StatusNotifierWatcher");
+    _statusNotifierWatcher = new org::kde::StatusNotifierWatcher(interface, "/StatusNotifierWatcher",
+                                                                 QDBusConnection::sessionBus());
+  }
+  if(_statusNotifierWatcher->isValid()
+    && _statusNotifierWatcher->property("ProtocolVersion").toInt() == _protocolVersion) {
+
+    _statusNotifierWatcher->RegisterStatusNotifierItem(_statusNotifierItemDBus->service());
+
+  } else {
+    qDebug() << "StatusNotifierWatcher not reachable!";
+    setMode(Legacy);
+  }
+}
+
+// FIXME remove deprecated slot with Qt 4.6
+void StatusNotifierItem::serviceChange(const QString& name, const QString& oldOwner, const QString& newOwner) {
+  bool legacy = false;
+  if(name == "org.kde.StatusNotifierWatcher") {
+    if(newOwner.isEmpty()) {
+      //unregistered
+      //qDebug() << "Connection to the StatusNotifierWatcher lost";
+      legacy = true;
+    } else if(oldOwner.isEmpty()) {
+      //registered
+      legacy = false;
+    }
+  } else if(name.startsWith(QLatin1String("org.kde.StatusNotifierHost-"))) {
+    if(newOwner.isEmpty() && (!_statusNotifierWatcher ||
+                              !_statusNotifierWatcher->property("IsStatusNotifierHostRegistered").toBool())) {
+      //qDebug() << "Connection to the last StatusNotifierHost lost";
+      legacy = true;
+    } else if(oldOwner.isEmpty()) {
+      //qDebug() << "New StatusNotifierHost";
+      legacy = false;
+    }
+  } else {
+    return;
+  }
+
+  // qDebug() << "Service " << name << "status change, old owner:" << oldOwner << "new:" << newOwner;
+
+  if(legacy == (mode() == Legacy)) {
+    return;
+  }
+
+  if(legacy) {
+    //unregistered
+    setMode(Legacy);
+  } else {
+    //registered
+    setMode(StatusNotifier);
+  }
+}
+
+void StatusNotifierItem::setMode(Mode mode_) {
+  StatusNotifierItemParent::setMode(mode_);
+
+  if(mode() == StatusNotifier) {
+    registerToDaemon();
+  }
+}
+
+void StatusNotifierItem::setState(State state_) {
+  StatusNotifierItemParent::setState(state_);
+
+  emit _statusNotifierItemDBus->NewStatus(metaObject()->enumerator(metaObject()->indexOfEnumerator("State")).valueToKey(state()));
+  emit _statusNotifierItemDBus->NewIcon();
+}
+
+QString StatusNotifierItem::title() const {
+  return QString("Quassel IRC");
+}
+
+QString StatusNotifierItem::iconName() const {
+  if(state() == Passive)
+    return QString("quassel_inactive");
+  else
+    return QString("quassel");
+}
+
+QString StatusNotifierItem::attentionIconName() const {
+  return QString("quassel_message");
+}
+
+QString StatusNotifierItem::toolTipIconName() const {
+  return QString("quassel");
+}
+
+void StatusNotifierItem::activated(const QPoint &pos) {
+  Q_UNUSED(pos)
+  activate(Trigger);
+}
+
+bool StatusNotifierItem::eventFilter(QObject *watched, QEvent *event) {
+  if(mode() == StatusNotifier) {
+    //FIXME: ugly ugly workaround to weird QMenu's focus problems
+    if(watched == trayMenu() &&
+       (event->type() == QEvent::WindowDeactivate || (event->type() == QEvent::MouseButtonRelease && static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton))) {
+      // put at the back of event queue to let the action activate anyways
+      QTimer::singleShot(0, trayMenu(), SLOT(hide()));
+    }
+  }
+  return StatusNotifierItemParent::eventFilter(watched, event);
+}
+
+#endif
diff --git a/src/qtui/statusnotifieritem.h b/src/qtui/statusnotifieritem.h
new file mode 100644 (file)
index 0000000..2efbefd
--- /dev/null
@@ -0,0 +1,79 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2010 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This contains code from KStatusNotifierItem, part of the KDE libs     *
+ *   Copyright (C) 2009 Marco Martin <notmart@gmail.com>                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef STATUSNOTIFIERITEM_H_
+#define STATUSNOTIFIERITEM_H_
+
+#ifdef HAVE_DBUS
+
+#include "systemtray.h"
+#include "statusnotifierwatcher.h"
+
+#ifdef QT_NO_SYSTEMTRAYICON
+#  define StatusNotifierItemParent SystemTray
+#else
+#  define StatusNotifierItemParent LegacySystemTray
+#  include "legacysystemtray.h"
+#endif
+
+class StatusNotifierItemDBus;
+
+class StatusNotifierItem : public StatusNotifierItemParent {
+  Q_OBJECT
+
+public:
+  explicit StatusNotifierItem(QWidget *parent);
+  virtual ~StatusNotifierItem();
+
+public slots:
+  virtual void setState(State state);
+
+protected:
+  virtual void init();
+  virtual void setMode(Mode mode);
+
+  QString title() const;
+  QString iconName() const;
+  QString attentionIconName() const;
+  QString toolTipIconName() const;
+
+  virtual bool eventFilter(QObject *watched, QEvent *event);
+
+private slots:
+  void activated(const QPoint &pos);
+  void serviceChange(const QString& name, const QString& oldOwner, const QString& newOwner);
+
+private:
+  void registerToDaemon();
+
+  static const int _protocolVersion;
+  StatusNotifierItemDBus *_statusNotifierItemDBus;
+
+  org::kde::StatusNotifierWatcher *_statusNotifierWatcher;
+  //org::freedesktop::Notifications *_notificationsClient;
+
+  friend class StatusNotifierItemDBus;
+};
+
+#endif /* HAVE_DBUS */
+#endif /* STATUSNOTIFIERITEM_H_ */
diff --git a/src/qtui/statusnotifieritemdbus.cpp b/src/qtui/statusnotifieritemdbus.cpp
new file mode 100644 (file)
index 0000000..db93d5c
--- /dev/null
@@ -0,0 +1,287 @@
+/***************************************************************************
+ *   The original file is part of the KDE libraries                        *
+ *   Copyright (C) 2009 by Marco Martin <notmart@gmail.com>                *
+ *   Quasselfied 2010 by Manuel Nickschas <sputnick@quassel-irc.org>       *
+ *                                                                         *
+ *   This file is free software; you can redistribute it and/or modify     *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#include "statusnotifieritemdbus.h"
+#include "statusnotifieritem.h"
+#include "qtui.h"
+
+#include <QDBusConnection>
+#include <QPixmap>
+#include <QImage>
+#include <QApplication>
+#include <QMenu>
+#include <QMovie>
+
+#ifdef HAVE_KDE
+#  include <KWindowInfo>
+#  include <KWindowSystem>
+#endif
+
+#include "statusnotifierwatcher.h"
+#include "statusnotifieritemadaptor.h"
+
+// Marshall the ImageStruct data into a D-BUS argument
+const QDBusArgument &operator<<(QDBusArgument &argument, const DBusImageStruct &icon)
+{
+    argument.beginStructure();
+    argument << icon.width;
+    argument << icon.height;
+    argument << icon.data;
+    argument.endStructure();
+    return argument;
+}
+
+// Retrieve the ImageStruct data from the D-BUS argument
+const QDBusArgument &operator>>(const QDBusArgument &argument, DBusImageStruct &icon)
+{
+    qint32 width;
+    qint32 height;
+    QByteArray data;
+
+    argument.beginStructure();
+    argument >> width;
+    argument >> height;
+    argument >> data;
+    argument.endStructure();
+
+    icon.width = width;
+    icon.height = height;
+    icon.data = data;
+
+    return argument;
+}
+
+
+// Marshall the ImageVector data into a D-BUS argument
+const QDBusArgument &operator<<(QDBusArgument &argument, const DBusImageVector &iconVector)
+{
+    argument.beginArray(qMetaTypeId<DBusImageStruct>());
+    for (int i=0; i<iconVector.size(); ++i) {
+        argument << iconVector[i];
+    }
+    argument.endArray();
+    return argument;
+}
+
+// Retrieve the ImageVector data from the D-BUS argument
+const QDBusArgument &operator>>(const QDBusArgument &argument, DBusImageVector &iconVector)
+{
+    argument.beginArray();
+    iconVector.clear();
+
+    while ( !argument.atEnd() ) {
+       DBusImageStruct element;
+       argument >> element;
+       iconVector.append(element);
+    }
+
+    argument.endArray();
+
+
+    return argument;
+}
+
+// Marshall the ToolTipStruct data into a D-BUS argument
+const QDBusArgument &operator<<(QDBusArgument &argument, const DBusToolTipStruct &toolTip)
+{
+    argument.beginStructure();
+    argument << toolTip.icon;
+    argument << toolTip.image;
+    argument << toolTip.title;
+    argument << toolTip.subTitle;
+    argument.endStructure();
+    return argument;
+}
+
+// Retrieve the ToolTipStruct data from the D-BUS argument
+const QDBusArgument &operator>>(const QDBusArgument &argument, DBusToolTipStruct &toolTip)
+{
+    QString icon;
+    DBusImageVector image;
+    QString title;
+    QString subTitle;
+
+    argument.beginStructure();
+    argument >> icon;
+    argument >> image;
+    argument >> title;
+    argument >> subTitle;
+    argument.endStructure();
+
+    toolTip.icon = icon;
+    toolTip.image = image;
+    toolTip.title = title;
+    toolTip.subTitle = subTitle;
+
+    return argument;
+}
+
+
+int StatusNotifierItemDBus::s_serviceCount = 0;
+
+StatusNotifierItemDBus::StatusNotifierItemDBus(StatusNotifierItem *parent)
+  : QObject(parent),
+    m_statusNotifierItem(parent),
+    m_service(QString("org.kde.StatusNotifierItem-%1-%2")
+                      .arg(QCoreApplication::applicationPid())
+                      .arg(++s_serviceCount)),
+    m_dbus(QDBusConnection::connectToBus(QDBusConnection::SessionBus, m_service))
+{
+   new StatusNotifierItemAdaptor(this);
+   qDebug() << "service is" << m_service;
+   m_dbus.registerService(m_service);
+   m_dbus.registerObject("/StatusNotifierItem", this);
+}
+
+StatusNotifierItemDBus::~StatusNotifierItemDBus()
+{
+    m_dbus.unregisterService(m_service);
+}
+
+QString StatusNotifierItemDBus::service() const
+{
+    return m_service;
+}
+
+//DBUS slots
+//Values and calls have been adapted to Quassel
+
+QString StatusNotifierItemDBus::Category() const
+{
+    return QString("Communications"); // no need to make this configurable for Quassel
+}
+
+QString StatusNotifierItemDBus::Title() const
+{
+    return m_statusNotifierItem->title();
+}
+
+QString StatusNotifierItemDBus::Id() const
+{
+    return QString("QuasselIRC");
+}
+
+QString StatusNotifierItemDBus::Status() const
+ {
+    return m_statusNotifierItem->metaObject()->enumerator(m_statusNotifierItem->metaObject()->indexOfEnumerator("State")).valueToKey(m_statusNotifierItem->state());
+}
+
+int StatusNotifierItemDBus::WindowId() const
+{
+    return (int)QtUi::mainWindow()->winId();
+}
+
+
+//Icon
+//We don't need to support serialized icon data in Quassel
+
+QString StatusNotifierItemDBus::IconName() const
+{
+    return m_statusNotifierItem->iconName();
+}
+
+DBusImageVector StatusNotifierItemDBus::IconPixmap() const
+{
+    return DBusImageVector();
+}
+
+QString StatusNotifierItemDBus::OverlayIconName() const
+{
+    return QString();
+}
+
+DBusImageVector StatusNotifierItemDBus::OverlayIconPixmap() const
+{
+    return DBusImageVector();
+}
+
+//Requesting attention icon and movie
+
+QString StatusNotifierItemDBus::AttentionIconName() const
+{
+    return m_statusNotifierItem->attentionIconName();
+}
+
+DBusImageVector StatusNotifierItemDBus::AttentionIconPixmap() const
+{
+    return DBusImageVector();
+}
+
+QString StatusNotifierItemDBus::AttentionMovieName() const
+{
+    return QString();
+}
+
+
+//ToolTip
+
+DBusToolTipStruct StatusNotifierItemDBus::ToolTip() const
+{
+    DBusToolTipStruct toolTip;
+    toolTip.icon = m_statusNotifierItem->toolTipIconName();
+    toolTip.image = DBusImageVector();
+    toolTip.title = m_statusNotifierItem->toolTipTitle();
+    toolTip.subTitle = m_statusNotifierItem->toolTipSubTitle();
+
+    return toolTip;
+}
+
+//Interaction
+
+void StatusNotifierItemDBus::ContextMenu(int x, int y)
+{
+    if (!m_statusNotifierItem->trayMenu()) {
+        return;
+    }
+
+    //TODO: nicer placement, possible?
+    if (!m_statusNotifierItem->trayMenu()->isVisible()) {
+        m_statusNotifierItem->trayMenu()->setWindowFlags(Qt::Window|Qt::FramelessWindowHint);
+        m_statusNotifierItem->trayMenu()->popup(QPoint(x,y));
+#ifdef HAVE_KDE
+        KWindowSystem::setState(m_statusNotifierItem->trayMenu()->winId(), NET::SkipTaskbar|NET::SkipPager|NET::KeepAbove);
+        KWindowSystem::setType(m_statusNotifierItem->trayMenu()->winId(), NET::PopupMenu);
+        KWindowSystem::forceActiveWindow(m_statusNotifierItem->trayMenu()->winId());
+#endif
+    } else {
+        m_statusNotifierItem->trayMenu()->hide();
+    }
+}
+
+void StatusNotifierItemDBus::Activate(int x, int y)
+{
+    m_statusNotifierItem->activated(QPoint(x,y));
+}
+
+void StatusNotifierItemDBus::SecondaryActivate(int x, int y)
+{
+    Q_UNUSED(x)
+    Q_UNUSED(y)
+    // emit m_statusNotifierItem->secondaryActivateRequested(QPoint(x,y));
+}
+
+void StatusNotifierItemDBus::Scroll(int delta, const QString &orientation)
+{
+    Q_UNUSED(delta)
+    Q_UNUSED(orientation)
+    // Qt::Orientation dir = (orientation.toLower() == "horizontal" ? Qt::Horizontal : Qt::Vertical);
+    // emit m_statusNotifierItem->scrollRequested(delta, dir);
+}
diff --git a/src/qtui/statusnotifieritemdbus.h b/src/qtui/statusnotifieritemdbus.h
new file mode 100644 (file)
index 0000000..670a7c7
--- /dev/null
@@ -0,0 +1,225 @@
+/***************************************************************************
+ *   The original file is part of the KDE libraries                        *
+ *   Copyright (C) 2009 by Marco Martin <notmart@gmail.com>                *
+ *   Quasselfied 2010 by Manuel Nickschas <sputnick@quassel-irc.org>       *
+ *                                                                         *
+ *   This file is free software; you can redistribute it and/or modify     *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef STATUSNOTIFIERITEMDBUS_H_
+#define STATUSNOTIFIERITEMDBUS_H_
+
+#include <QObject>
+#include <QString>
+#include <QDBusArgument>
+#include <QDBusConnection>
+#include <QPixmap>
+
+//Custom message type for DBus
+struct DBusImageStruct {
+    int width;
+    int height;
+    QByteArray data;
+};
+
+typedef QVector<DBusImageStruct> DBusImageVector;
+
+struct DBusToolTipStruct {
+    QString icon;
+    DBusImageVector image;
+    QString title;
+    QString subTitle;
+};
+
+class StatusNotifierItem;
+
+class StatusNotifierItemDBus : public QObject
+{
+    Q_OBJECT
+
+    Q_PROPERTY(QString Category READ Category)
+    Q_PROPERTY(QString Id READ Id)
+    Q_PROPERTY(QString Title READ Title)
+    Q_PROPERTY(QString Status READ Status)
+    Q_PROPERTY(int WindowId READ WindowId)
+    Q_PROPERTY(QString IconName READ IconName)
+    Q_PROPERTY(DBusImageVector IconPixmap READ IconPixmap)
+    Q_PROPERTY(QString OverlayIconName READ OverlayIconName)
+    Q_PROPERTY(DBusImageVector OverlayIconPixmap READ OverlayIconPixmap)
+    Q_PROPERTY(QString AttentionIconName READ AttentionIconName)
+    Q_PROPERTY(DBusImageVector AttentionIconPixmap READ AttentionIconPixmap)
+    Q_PROPERTY(QString AttentionMovieName READ AttentionMovieName)
+    Q_PROPERTY(DBusToolTipStruct ToolTip READ ToolTip)
+
+    friend class StatusNotifierItem;
+public:
+    StatusNotifierItemDBus(StatusNotifierItem *parent);
+    ~StatusNotifierItemDBus();
+
+    /**
+     * @return the service this object is registered on the bus under
+     */
+    QString service() const;
+
+    /**
+     * @return the category of the application associated to this item
+     * @see Category
+     */
+    QString Category() const;
+
+    /**
+     * @return the id of this item
+     */
+    QString Id() const;
+
+    /**
+     * @return the title of this item
+     */
+    QString Title() const;
+
+    /**
+     * @return The status of this item
+     * @see Status
+     */
+    QString Status() const;
+
+    /**
+     * @return The id of the main window of the application that controls the item
+     */
+    int WindowId() const;
+
+    /**
+     * @return the name of the main icon to be displayed
+     * if image() is not empty this will always return an empty string
+     */
+    QString IconName() const;
+
+    /**
+     * @return a serialization of the icon data
+     */
+    DBusImageVector IconPixmap() const;
+
+    /**
+     * @return the name of the overlay of the main icon to be displayed
+     * if image() is not empty this will always return an empty string
+     */
+    QString OverlayIconName() const;
+
+    /**
+     * @return a serialization of the icon data
+     */
+    DBusImageVector OverlayIconPixmap() const;
+
+    /**
+     * @return the name of the icon to be displayed when the application
+     * is requesting the user's attention
+     * if attentionImage() is not empty this will always return an empty string
+     */
+    QString AttentionIconName() const;
+
+    /**
+     * @return a serialization of the requesting attention icon data
+     */
+    DBusImageVector AttentionIconPixmap() const;
+
+    /**
+     * @return the name of the attention movie
+     */
+    QString AttentionMovieName() const;
+
+    /**
+     * all the data needed for a tooltip
+     */
+    DBusToolTipStruct ToolTip() const;
+
+
+public Q_SLOTS:
+    //interaction
+    /**
+     * Shows the context menu associated to this item
+     * at the desired screen position
+     */
+    void ContextMenu(int x, int y);
+
+    /**
+     * Shows the main widget and try to position it on top
+     * of the other windows, if the widget is already visible, hide it.
+     */
+    void Activate(int x, int y);
+
+    /**
+     * The user activated the item in an alternate way (for instance with middle mouse button, this depends from the systray implementation)
+     */
+    void SecondaryActivate(int x, int y);
+
+    /**
+     * Inform this item that the mouse wheel was used on its representation
+     */
+    void Scroll(int delta, const QString &orientation);
+
+Q_SIGNALS:
+    /**
+     * Inform the systemtray that the own main icon has been changed,
+     * so should be reloaded
+     */
+    void NewIcon();
+
+    /**
+     * Inform the systemtray that there is a new icon to be used as overlay
+     */
+    void NewOverlayIcon();
+
+    /**
+     * Inform the systemtray that the requesting attention icon
+     * has been changed, so should be reloaded
+     */
+    void NewAttentionIcon();
+
+    /**
+     * Inform the systemtray that something in the tooltip has been changed
+     */
+    void NewToolTip();
+
+    /**
+     * Signal the new status when it has been changed
+     * @see Status
+     */
+    void NewStatus(const QString &status);
+
+private:
+    StatusNotifierItem *m_statusNotifierItem;
+    QString m_service;
+    QDBusConnection m_dbus;
+    static int s_serviceCount;
+};
+
+
+const QDBusArgument &operator<<(QDBusArgument &argument, const DBusImageStruct &icon);
+const QDBusArgument &operator>>(const QDBusArgument &argument, DBusImageStruct &icon);
+
+Q_DECLARE_METATYPE(DBusImageStruct)
+
+const QDBusArgument &operator<<(QDBusArgument &argument, const DBusImageVector &iconVector);
+const QDBusArgument &operator>>(const QDBusArgument &argument, DBusImageVector &iconVector);
+
+Q_DECLARE_METATYPE(DBusImageVector)
+
+const QDBusArgument &operator<<(QDBusArgument &argument, const DBusToolTipStruct &toolTip);
+const QDBusArgument &operator>>(const QDBusArgument &argument, DBusToolTipStruct &toolTip);
+
+Q_DECLARE_METATYPE(DBusToolTipStruct)
+
+#endif