REquired infrastructure for Qt desktop plugin.
authorMax Lapan <max.lapan@gmail.com>
Sun, 7 Mar 2010 16:38:46 +0000 (19:38 +0300)
committerMax Lapan <max.lapan@gmail.com>
Sun, 7 Mar 2010 16:38:46 +0000 (19:38 +0300)
README
main.cpp [new file with mode: 0644]
mainwidget.hpp [new file with mode: 0644]
qmaemo5homescreenadaptor.cpp [new file with mode: 0644]
qmaemo5homescreenadaptor.h [new file with mode: 0644]
yandex-traffic-widget.desktop [new file with mode: 0644]
yandex-traffic-widget.pro [new file with mode: 0644]

diff --git a/README b/README
index e69de29..39e564d 100644 (file)
--- a/README
+++ b/README
@@ -0,0 +1,7 @@
+Desktop widget for maemo which displays traffic information from Yandex.Maps.
+
+Source code of this program can be distributed according to GPL license.
+
+All bug repots, patches, donations, etc could be sent to max.lapan@gmail.com
+
+Copyright (c) 2009, Max Lapan <max.lapan@gmail.com>
\ No newline at end of file
diff --git a/main.cpp b/main.cpp
new file mode 100644 (file)
index 0000000..075f0f7
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,18 @@
+#include "qmaemo5homescreenadaptor.h"
+#include "mainwidget.hpp"
+
+
+int main(int argc, char *argv[])
+{
+    QApplication::setGraphicsSystem ("native");
+    QApplication app (argc, argv);
+    MainWidget w;
+    QMaemo5HomescreenAdaptor *adaptor = new QMaemo5HomescreenAdaptor (&w);
+
+    adaptor->setSettingsAvailable (true);
+    
+    w.show ();
+
+    return app.exec ();
+}
+
diff --git a/mainwidget.hpp b/mainwidget.hpp
new file mode 100644 (file)
index 0000000..5298de5
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __MAINWIDGET_H__
+#define __MAINWIDGET_H__
+
+#include <QtGui>
+
+class MainWidget : public QLabel
+{
+    Q_OBJECT
+public:
+    MainWidget ()
+        : QLabel (tr ("Hello, World"))
+    {
+        setAlignment(Qt::AlignCenter);
+        setAttribute(Qt::WA_TranslucentBackground);
+    }
+
+    QSize sizeHint() const
+    {
+        return 2 * QLabel::sizeHint();
+    }
+};
+
+#endif /* __MAINWIDGET_H__ */
diff --git a/qmaemo5homescreenadaptor.cpp b/qmaemo5homescreenadaptor.cpp
new file mode 100644 (file)
index 0000000..b473fea
--- /dev/null
@@ -0,0 +1,287 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmaemo5homescreenadaptor.h"
+
+#include <QtCore/qsocketnotifier.h>
+
+#include <QtGui/qapplication.h>
+#include <QtGui/qx11info_x11.h>
+#include <QtGui/qwidget.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+static QCoreApplication::EventFilter oldEventFilter;
+static QList<QMaemo5HomescreenAdaptor *> allDesktopItems;
+
+static Atom atomByName(const char *name)
+{
+    Atom atom = XInternAtom(QX11Info::display(), name, False);
+    if (!atom)
+        qWarning("Unable to obtain %s atom. This class requires a running Hildon session.", name);
+
+    return atom;
+}
+
+enum HomescreenAtoms
+{
+    HildonAppletId               = 0,
+    NetWmWindowType              = 1,
+    Utf8String                   = 2,
+    HildonTypeHomeApplet         = 3,
+    HildonAppletSettings         = 4,
+    HildonAppletShowSettings     = 5,
+    HildonAppletOnCurrentDesktop = 6,
+    EnumCount                    = 7
+};
+
+static Atom hsAtoms[EnumCount] = { 0, 0, 0, 0, 0, 0, 0 };
+
+static void initAtoms()
+{
+    hsAtoms[HildonAppletId] = atomByName("_HILDON_APPLET_ID");
+    hsAtoms[NetWmWindowType] = atomByName("_NET_WM_WINDOW_TYPE");
+    hsAtoms[Utf8String] = atomByName("UTF8_STRING");
+    hsAtoms[HildonTypeHomeApplet] = atomByName("_HILDON_WM_WINDOW_TYPE_HOME_APPLET");
+    hsAtoms[HildonAppletSettings] = atomByName("_HILDON_APPLET_SETTINGS");
+    hsAtoms[HildonAppletShowSettings] = atomByName("_HILDON_APPLET_SHOW_SETTINGS");
+    hsAtoms[HildonAppletOnCurrentDesktop] = atomByName("_HILDON_APPLET_ON_CURRENT_DESKTOP");
+}
+
+/*! \class QMaemo5HomescreenAdaptor
+
+    \brief The QMaemo5HomescreenAdaptor flags a top-level QWidget as homescreen widget
+
+    QMaemo5HomescreenAdaptor is used in conjunction with the Qt for Maemo homescreen
+    loader. It evaluates the two command line arguments "-plugin-id" and "-write-pipe"
+    to set up a Qt top-level widget as Maemo 5 homescreen widget.
+
+    Note: By default, the widget will have a black background. In order to make the
+    widget transparent, set the Qt::WA_TranslucentBackground widget attribute.
+
+    Example:
+
+    \code
+    QLabel *label = new QLabel("Hello Homescreen");
+    new QMaemo5HomescreenAdaptor(label);
+    label->show();
+    \endcode
+
+    Maemo 5 supports homescreen widgets with settings dialogs. To use it, set
+    the settingsAvailable() property and show a settings dialog when the
+    settingsRequested() signal is emitted.
+
+    Maemo 5 supports more than one homescreen. In order to determine whether
+    the homescreen widget is on the currently visible homescreen, connect to
+    the homescreenChanged() signal.
+*/
+
+/*! \property QMaemo5HomescreenAdaptor::settingsAvailable
+
+    Set this property to true if the widget can make use of a settings dialog,
+    otherwise to false. When this property is set to true, the Maemo 5 homescreen
+    renders a small settings icon on top of the homescreen widget when the
+    user enters the desktop menu. When the user clicks that settings icon, the
+    settingsRequested() signal is emitted.
+
+    The default is false.
+
+    \sa settingsRequested()
+ */
+
+/*! \fn void settingsRequested()
+
+    This signal is emitted every time the homescreen widget's settings icon is
+    invoked by the user. Note that this icon is only visible when the settingsAvailable()
+    property is set.
+
+    \sa settingsAvailable()
+ */
+
+/*! \fn void homescreenChanged(bool isOnCurrentHomescreen)
+
+    This is signal is emitted when current homescreen changes and the homescreen
+    widget becomes visible or invisible. The \a isOnCurrentHomescreen argument
+    indicates whether the homescreen widget is on the current homescreen or not.
+
+    This signal can be used to start/stop background processing in order to save
+    battery life.
+ */
+
+/*!
+    Constructs a new QMaemo5HomescreenAdaptor for the given \a widget.
+
+    Note: The widget must be a top-level widget, and must not be reparented
+    during the lifetime of this adaptor.
+
+    Note: \a widget is also the parent of this class, if the widget is destroyed,
+    so is this adaptor.
+ */
+QMaemo5HomescreenAdaptor::QMaemo5HomescreenAdaptor(QWidget *widget)
+    : QObject(widget),
+      hasSettings(false)
+{
+    Q_ASSERT(widget->isWindow());
+
+    if (!hsAtoms[0])
+        initAtoms();
+
+    Display *display = QX11Info::display();
+
+    const QStringList args = QApplication::arguments();
+
+    // parse the command line arguments.
+    int idx;
+    if ((idx = args.indexOf(QLatin1String("-plugin-id"))) != -1) {
+        appletId = args.value(idx + 1);
+        const QByteArray pluginId = appletId.toUtf8();
+        if (!pluginId.isEmpty()) {
+            XChangeProperty(display,
+                    widget->winId(),
+                    hsAtoms[HildonAppletId],
+                    hsAtoms[Utf8String], 8, PropModeReplace,
+                    reinterpret_cast<const unsigned char *>(pluginId.constData()),
+                    pluginId.length());
+        }
+    }
+    if ((idx = args.indexOf(QLatin1String("-write-pipe"))) != -1) {
+        bool ok;
+        int sockId = args.value(idx + 1).toInt(&ok);
+        if (ok) {
+            socketNotifier = new QSocketNotifier(sockId, QSocketNotifier::Exception, this);
+            connect(socketNotifier, SIGNAL(activated(int)), this, SLOT(socketException()));
+        }
+    }
+
+    // set the X11 atoms to flag our widget as homescreen widget
+    if (!appletId.isEmpty()) {
+        XChangeProperty(display,
+                widget->winId(),
+                hsAtoms[NetWmWindowType],
+                XA_ATOM, 32, PropModeReplace,
+                reinterpret_cast<const unsigned char *>(&hsAtoms[HildonTypeHomeApplet]),
+                1);
+
+        updateStatus();
+
+        // --- make this window a child of root
+        XSetTransientForHint(display, widget->winId(),
+                             RootWindow(display, widget->x11Info().screen()));
+
+        // --- add an x11 event filter
+        if (!oldEventFilter)
+            oldEventFilter = QCoreApplication::instance()->setEventFilter(applicationEventFilter);
+
+        allDesktopItems.append(this);
+    }
+}
+
+QMaemo5HomescreenAdaptor::~QMaemo5HomescreenAdaptor()
+{
+    allDesktopItems.removeOne(this);
+}
+
+/*! \internal */
+void QMaemo5HomescreenAdaptor::updateStatus()
+{
+    if (appletId.isEmpty())
+        return;
+
+    Display *display = QX11Info::display();
+
+    // Set or remove settings property
+    if (hasSettings)
+        XChangeProperty(display,
+                appletWidget()->winId(),
+                hsAtoms[HildonAppletSettings],
+                XA_CARDINAL, 32, PropModeReplace,
+                (const unsigned char *) &(hasSettings), 1);
+    else
+        XDeleteProperty(display,
+                appletWidget()->winId(),
+                hsAtoms[HildonAppletSettings]);
+}
+
+/*! \internal */
+void QMaemo5HomescreenAdaptor::socketException()
+{
+    socketNotifier->setEnabled(false);
+    appletWidget()->close();
+}
+
+/*! \internal */
+bool QMaemo5HomescreenAdaptor::applicationEventFilter(void *message, long *result)
+{
+    bool retval = false;
+
+    if (oldEventFilter)
+        retval = oldEventFilter(message, result);
+
+    if (allDesktopItems.isEmpty())
+        return retval;
+
+    XEvent *ev = reinterpret_cast<XEvent *>(message);
+
+    if (ev->type == ClientMessage) {
+        XClientMessageEvent *cm = (XClientMessageEvent *)message;
+        if (cm->message_type == hsAtoms[HildonAppletShowSettings]) {
+            for (int i = 0; i < allDesktopItems.count(); ++i) {
+                if (allDesktopItems.at(i)->appletWidget()->winId() == ev->xproperty.window) {
+                    emit allDesktopItems.at(i)->settingsRequested();
+                    retval = true;
+                }
+            }
+        }
+    } else if (ev->type == PropertyNotify) {
+        if (ev->xproperty.atom == hsAtoms[HildonAppletOnCurrentDesktop]) {
+            for (int i = 0; i < allDesktopItems.count(); ++i) {
+                if (allDesktopItems.at(i)->appletWidget()->winId() == ev->xproperty.window) {
+                    emit allDesktopItems.at(i)->homescreenChanged(ev->xproperty.window == 0);
+                    retval = true;
+                }
+            }
+        }
+    }
+
+    return retval;
+}
+
diff --git a/qmaemo5homescreenadaptor.h b/qmaemo5homescreenadaptor.h
new file mode 100644 (file)
index 0000000..68c4d5b
--- /dev/null
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMAEMO5HOMESCREENADAPTOR_H
+#define QMAEMO5HOMESCREENADAPTOR_H
+
+#include <QtCore/qobject.h>
+#include <QtGui/qwidget.h>
+
+class QWidget;
+class QSocketNotifier;
+
+class QMaemo5HomescreenAdaptor : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(bool settingsAvailable READ settingsAvailable WRITE setSettingsAvailable)
+
+public:
+    QMaemo5HomescreenAdaptor(QWidget *widget);
+    ~QMaemo5HomescreenAdaptor();
+
+    inline void setSettingsAvailable(bool available)
+    {
+        hasSettings = available;
+        updateStatus();
+    }
+
+    inline bool settingsAvailable() const
+    {
+        return hasSettings;
+    }
+
+Q_SIGNALS:
+    void settingsRequested();
+    void homescreenChanged(bool isOnCurrentHomescreen);
+
+private Q_SLOTS:
+    void socketException();
+
+private:
+    inline QWidget *appletWidget() const { return static_cast<QWidget *>(parent()); }
+
+    void updateStatus();
+
+    static bool applicationEventFilter(void *message, long *result);
+
+    bool hasSettings;
+    QString appletId;
+    QSocketNotifier *socketNotifier;
+};
+
+#endif
diff --git a/yandex-traffic-widget.desktop b/yandex-traffic-widget.desktop
new file mode 100644 (file)
index 0000000..9120f05
--- /dev/null
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=Yandex.Traffic
+Comment=Widget wich displays Yandex.Traffic information
+Type=qt
+X-Path=yandex-traffic-widget
+X-Multiple-Instances=false
+X-home-applet-minwidth=100
+X-home-applet-minheight=72
+Name[en_US]=Yandex.Traffic widget
diff --git a/yandex-traffic-widget.pro b/yandex-traffic-widget.pro
new file mode 100644 (file)
index 0000000..9a239ea
--- /dev/null
@@ -0,0 +1,13 @@
+TEMPLATE = app
+
+SOURCES += qmaemo5homescreenadaptor.cpp
+HEADERS += qmaemo5homescreenadaptor.h
+
+SOURCES += main.cpp
+HEADERS += mainwidget.hpp
+
+desktop.path = /usr/share/applications/hildon-home
+desktop.files = yandex-traffic-widget.desktop
+
+target.path = /usr/lib/hildon-desktop
+INSTALLS += target desktop