From a3a2e7e57e29c35127be7776548a8a0f07a0efee Mon Sep 17 00:00:00 2001 From: Harald Fernengel Date: Wed, 24 Feb 2010 11:42:07 +0100 Subject: Initial version of Qt for Maemo 5 homescreen widget loader + example --- README | 42 +++ debian/changelog | 12 + debian/compat | 1 + debian/control | 38 ++ debian/qt4-maemo5-homescreen-example.install | 3 + debian/qt4-maemo5-homescreen-loader.install | 1 + debian/rules | 43 +++ .../qmaemo5homescreenadaptor.cpp | 287 +++++++++++++++ .../qmaemo5homescreenadaptor.h | 90 +++++ .../qmaemo5homescreenadaptor.pri | 4 + qt-homescreen-example/main.cpp | 59 +++ .../qt-homescreen-example.desktop | 9 + qt-homescreen-example/qt-homescreen-example.pro | 12 + qt-homescreen-example/testwidget.h | 90 +++++ qt4-maemo5-homescreen.pro | 2 + qtpluginloader/hd-plugin-loader-qt.c | 394 +++++++++++++++++++++ qtpluginloader/hd-plugin-loader-qt.h | 104 ++++++ qtpluginloader/qtpluginloader.pro | 13 + 18 files changed, 1204 insertions(+) create mode 100644 README create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/qt4-maemo5-homescreen-example.install create mode 100644 debian/qt4-maemo5-homescreen-loader.install create mode 100755 debian/rules create mode 100644 qmaemo5homescreenadaptor/qmaemo5homescreenadaptor.cpp create mode 100644 qmaemo5homescreenadaptor/qmaemo5homescreenadaptor.h create mode 100644 qmaemo5homescreenadaptor/qmaemo5homescreenadaptor.pri create mode 100644 qt-homescreen-example/main.cpp create mode 100644 qt-homescreen-example/qt-homescreen-example.desktop create mode 100644 qt-homescreen-example/qt-homescreen-example.pro create mode 100644 qt-homescreen-example/testwidget.h create mode 100644 qt4-maemo5-homescreen.pro create mode 100644 qtpluginloader/hd-plugin-loader-qt.c create mode 100644 qtpluginloader/hd-plugin-loader-qt.h create mode 100644 qtpluginloader/qtpluginloader.pro diff --git a/README b/README new file mode 100644 index 0000000..e4502dc --- /dev/null +++ b/README @@ -0,0 +1,42 @@ +This example shows how to create desktop widgets with Qt for Maemo 5. + +Desktop widgets require a two step approach. First, a special loader is +required in order to load Qt based home screen widgets. This loader only +has to be installed once, and usually, the Debian packaging system should +be used to make sure it is installed. + +In your home screen widget's Debian package, make sure you depend on the +package qt4-maemo5-homescreen-loader. An example "Depends" line could look like: + +Depends: libqt4-maemo5-core (>= 4.6.1), libqt4-maemo5-gui (>= 4.6.1), qt4-maemo5-homescreen-loader + +The source code for the special Qt home screen loader can be found in the +qtpluginloader directory of this package. + + +In order to flag a toplevel widget as home screen widgets, some special +X11 attributes must be set. The QMaemo5HomescreenAdaptor class handles all +the special behavior, and also enables home screen applets to have their +own settings dialog. + +In order to use the QMaemo5HomscreenAdaptor class, add the qmaemo5homescreenadaptor.cpp and +qmaemo5homescreenadaptor.h files to your project. For qmake based projects, you can also +include the qmaemo5homescreenadaptor.pri file from your project path, e.g. with + +include (/path/to/adaptor/qmaemo5homescreenadaptor.pri) + +Please refer to qmaemo5homescreenadaptor.cpp for documentation on how to use the class. + +The directory qt-homescreen-example contains a small example on how to make a +semi-transparent home screen widget that contains a settings dialog. Note that both +the resulting Qt binary and the corresponding desktop file need to be installed, +as outlined in the Maemo 5 Developer Guide: + + http://wiki.maemo.org/Documentation/Maemo_5_Developer_Guide/Application_Development/Writing_Desktop_Widgets + +Note that the following line must be present in the desktop file in order for +the special Qt plugin loader to recognize the home screen widget: + +Type=qt + +Please refer to qt-homescreen-example for an example desktop file. diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..ce70308 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,12 @@ +qt4-maemo5-homescreen (4.6.2~git20100224-4maemo1) unstable; urgency=low + + * Fix dependencies + + -- Qt Development Frameworks Wed, 24 Feb 2010 14:29:01 +0200 + +qt4-maemo5-homescreen (4.6.2~git20100223-4maemo1) unstable; urgency=low + + * Initial package + + -- Qt Development Frameworks Tue, 23 Feb 2010 14:29:01 +0200 + diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +4 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..ffe525d --- /dev/null +++ b/debian/control @@ -0,0 +1,38 @@ +Source: qt4-maemo5-homescreen +Section: libs +Priority: optional +Maintainer: Qt Development Frameworks +Uploaders: Harald Fernengel +Build-Depends: libqt4-maemo5-dev, libhildon1-dev, libhildondesktop1-dev +Standards-Version: 3.7.3 + +Package: qt4-maemo5-homescreen-loader +Architecture: any +Section: devel +Depends: libhildondesktop1 +Description: Qt 4 homescreen widget loader + Qt is a cross-platform C++ application framework. Qt's primary feature + is its rich set of widgets that provide standard GUI functionality. + . + This package provides a loader for loading Qt homescreen widgets + +Package: qt4-maemo5-homescreen-loader-dbg +Priority: extra +Architecture: any +Section: devel +Depends: qt4-maemo5-homescreen-loader +Description: Qt 4 library debugging symbols + Qt is a cross-platform C++ application framework. Qt's primary feature + is its rich set of widgets that provide standard GUI functionality. + . + This packages contains the debugging symbols for the Qt 4 homescreen loader + +Package: qt4-maemo5-homescreen-example +Architecture: any +Section: devel +Depends: libqt4-maemo5-core (>= 4.6.1), libqt4-maemo5-gui (>= 4.6.1), qt4-maemo5-homescreen-loader +Description: Qt 4 Declarative development files + Qt is a cross-platform C++ application framework. Qt's primary feature + is its rich set of widgets that provide standard GUI functionality. + . + This package contains an example homescreen widget done with Qt 4 diff --git a/debian/qt4-maemo5-homescreen-example.install b/debian/qt4-maemo5-homescreen-example.install new file mode 100644 index 0000000..ce57662 --- /dev/null +++ b/debian/qt4-maemo5-homescreen-example.install @@ -0,0 +1,3 @@ +/usr/lib/hildon-desktop/qt-homescreen-example +/usr/share/applications/hildon-home/qt-homescreen-example.desktop + diff --git a/debian/qt4-maemo5-homescreen-loader.install b/debian/qt4-maemo5-homescreen-loader.install new file mode 100644 index 0000000..2cfcfde --- /dev/null +++ b/debian/qt4-maemo5-homescreen-loader.install @@ -0,0 +1 @@ +/usr/lib/hildon-desktop/loaders/libqtpluginloader.so diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..9389de5 --- /dev/null +++ b/debian/rules @@ -0,0 +1,43 @@ +#!/usr/bin/make -f + +export DH_VERBOSE=1 + +# Only present in official source package +#QTVERSION := $(shell ls changes-* | cut -f2 -d '-') +CURRENTVERSION := $(shell head -1 debian/changelog | sed 's/[^(]*(\([^)]*\)).*/\1/') + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/makefile.mk +include /usr/share/cdbs/1/rules/utils.mk + +# Find out how many parallel threads to run +comma := , +TMP_BUILD_OPTS = $(subst $(comma), ,$(DEB_BUILD_OPTIONS)) +ifneq (,$(filter parallel=%,$(TMP_BUILD_OPTS))) + NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(TMP_BUILD_OPTS))) + PARALLEL_MAKEFLAGS += -j$(NUMJOBS) +endif + +DEB_MAKE_INVOKE := $(MAKE) $(PARALLEL_MAKEFLAGS) +DEB_MAKE_BUILD_TARGET := all +DEB_MAKE_INSTALL_TARGET := INSTALL_ROOT=$(DEB_DESTDIR) install +DEB_DH_INSTALL_SOURCEDIR := debian/tmp +DEB_DH_ALWAYS_EXCLUDE := .git + +# Ensure the *.debug files aren't included in any package other than libqt4-maemo5-dbg +DEB_DH_INSTALL_ARGS := --exclude=.debug + +DEB_MAKE_CLEAN_TARGET := distclean + +# Shlibs of the current upstream version +DEB_DH_MAKESHLIBS_ARGS_ALL := -V + +DEB_DH_STRIP_ARGS := --dbg-package=qt4-maemo5-homescreen-loader +DEB_DH_SHLIBDEPS_ARGS_ALL := --exclude=.debug + +# Only present in official source package +#DEB_INSTALL_CHANGELOGS_ALL := changes-$(QTVERSION) + +common-configure-arch:: + /opt/qt4-maemo5/bin/qmake CONFIG+=separate_debug_info CONFIG+=separate_debug_info_nocopy QMAKE_CXXFLAGS+="-g" QMAKE_CFLAGS+="-g" + diff --git a/qmaemo5homescreenadaptor/qmaemo5homescreenadaptor.cpp b/qmaemo5homescreenadaptor/qmaemo5homescreenadaptor.cpp new file mode 100644 index 0000000..b473fea --- /dev/null +++ b/qmaemo5homescreenadaptor/qmaemo5homescreenadaptor.cpp @@ -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 + +#include +#include +#include + +#include +#include + +static QCoreApplication::EventFilter oldEventFilter; +static QList 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(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(&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(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/qmaemo5homescreenadaptor.h b/qmaemo5homescreenadaptor/qmaemo5homescreenadaptor.h new file mode 100644 index 0000000..68c4d5b --- /dev/null +++ b/qmaemo5homescreenadaptor/qmaemo5homescreenadaptor.h @@ -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 +#include + +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(parent()); } + + void updateStatus(); + + static bool applicationEventFilter(void *message, long *result); + + bool hasSettings; + QString appletId; + QSocketNotifier *socketNotifier; +}; + +#endif diff --git a/qmaemo5homescreenadaptor/qmaemo5homescreenadaptor.pri b/qmaemo5homescreenadaptor/qmaemo5homescreenadaptor.pri new file mode 100644 index 0000000..73d41c3 --- /dev/null +++ b/qmaemo5homescreenadaptor/qmaemo5homescreenadaptor.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/qmaemo5homescreenadaptor.h +SOURCES += $$PWD/qmaemo5homescreenadaptor.cpp + +INCLUDEPATH += $$PWD diff --git a/qt-homescreen-example/main.cpp b/qt-homescreen-example/main.cpp new file mode 100644 index 0000000..56d10b3 --- /dev/null +++ b/qt-homescreen-example/main.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** 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 "testwidget.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + TestWidget w; + QMaemo5HomescreenAdaptor *adaptor = new QMaemo5HomescreenAdaptor(&w); + adaptor->setSettingsAvailable(true); + QObject::connect(adaptor, SIGNAL(settingsRequested()), &w, SLOT(showSettingsDialog())); + w.show(); + + app.exec(); +} + diff --git a/qt-homescreen-example/qt-homescreen-example.desktop b/qt-homescreen-example/qt-homescreen-example.desktop new file mode 100644 index 0000000..7b2b52d --- /dev/null +++ b/qt-homescreen-example/qt-homescreen-example.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=Qt Desktop Example +Comment=An example home desktop item +Type=qt +X-Path=qt-homescreen-example +X-Multiple-Instances=false +X-home-applet-minwidth=100 +X-home-applet-minheight=72 +Name[en_US]=Example Qt Desktop Item diff --git a/qt-homescreen-example/qt-homescreen-example.pro b/qt-homescreen-example/qt-homescreen-example.pro new file mode 100644 index 0000000..3ef254f --- /dev/null +++ b/qt-homescreen-example/qt-homescreen-example.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +SOURCES += main.cpp +HEADERS += testwidget.h + +include(../qmaemo5homescreenadaptor/qmaemo5homescreenadaptor.pri) + +desktop.path = /usr/share/applications/hildon-home +desktop.files = qt-homescreen-example.desktop + +target.path = /usr/lib/hildon-desktop +INSTALLS += target desktop diff --git a/qt-homescreen-example/testwidget.h b/qt-homescreen-example/testwidget.h new file mode 100644 index 0000000..9aa5a78 --- /dev/null +++ b/qt-homescreen-example/testwidget.h @@ -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 TESTWIDGET_H +#define TESTWIDGET_H + +#include +#include +#include + +class TestWidget : public QLabel +{ + Q_OBJECT + +public: + TestWidget() + : QLabel(tr("Hello World")) + { + setAlignment(Qt::AlignCenter); + setAttribute(Qt::WA_TranslucentBackground); + } + + QSize sizeHint() const + { + return 2 * QLabel::sizeHint(); + } + +public slots: + void showSettingsDialog() + { + bool isOk; + QString newText = QInputDialog::getText(this, tr("New Text"), + tr("Please enter a new text:"), QLineEdit::Normal, + text(), &isOk); + if (isOk) + setText(newText); + } + +protected: + void paintEvent(QPaintEvent *event) + { + QPainter p(this); + p.setBrush(QColor(0, 0, 0, 128)); + p.setPen(Qt::NoPen); + p.drawRoundedRect(rect(), 25, 25); + p.end(); + + QLabel::paintEvent(event); + } +}; + +#endif diff --git a/qt4-maemo5-homescreen.pro b/qt4-maemo5-homescreen.pro new file mode 100644 index 0000000..3ecb1b4 --- /dev/null +++ b/qt4-maemo5-homescreen.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = qt-homescreen-example qtpluginloader diff --git a/qtpluginloader/hd-plugin-loader-qt.c b/qtpluginloader/hd-plugin-loader-qt.c new file mode 100644 index 0000000..912d6c2 --- /dev/null +++ b/qtpluginloader/hd-plugin-loader-qt.c @@ -0,0 +1,394 @@ +/**************************************************************************** +** +** 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 + +#include "hd-plugin-loader-qt.h" + +#include +#include +#include + +#ifndef HD_PLUGIN_MODULE_PATH +#define HD_PLUGIN_MODULE_PATH "/usr/lib/hildon-desktop" +#endif + +/* those come from hd-config.h */ +#define HD_PLUGIN_CONFIG_GROUP "Desktop Entry" +#define HD_PLUGIN_CONFIG_KEY_TYPE "Type" +#define HD_PLUGIN_CONFIG_KEY_PATH "X-Path" +#define HD_PLUGIN_CONFIG_KEY_TEXT_DOMAIN "X-Text-Domain" + +#define QT_ABSTRACT_HOME_ITEM_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), QT_TYPE_ABSTRACT_HOME_ITEM, QtAbstractHomeItemPrivate)) + +struct _QtAbstractHomeItemPrivate +{ + GIOChannel *gio_read; + + gchar realized; + gchar *executable_path; +}; + +G_DEFINE_TYPE (QtAbstractHomeItem, qt_abstract_home_item, HD_TYPE_HOME_PLUGIN_ITEM); + +static void +qt_abstract_home_item_init (QtAbstractHomeItem *object) +{ + object->priv = QT_ABSTRACT_HOME_ITEM_GET_PRIVATE (object); + + QtAbstractHomeItemPrivate *priv = object->priv; + priv->gio_read = NULL; + + priv->realized = FALSE; + priv->executable_path = 0; + +} + +static void +qt_abstract_home_item_finalize (GObject *object) +{ + QtAbstractHomeItemPrivate *priv = QT_ABSTRACT_HOME_ITEM (object)->priv; + + if (priv->gio_read) + { + g_io_channel_unref(priv->gio_read); + priv->gio_read = NULL; + } + + g_free (priv->executable_path); + + G_OBJECT_CLASS (qt_abstract_home_item_parent_class)->finalize (object); +} + +static gboolean +qt_abstract_home_item_gio_in (GIOChannel *gio, GIOCondition condition, gpointer data) +{ + /* + GIOStatus ret; + gchar *msg; + gsize len; + GError *err = NULL; */ + GdkEvent *gdk_delete_event; + QtAbstractHomeItem *object = data; + GtkWidget *widget = GTK_WIDGET(object); + + (void) gio; // unused + + if (condition & G_IO_HUP) { + /* send a delete event so that hildon-home get's notified that our item was closed */ + gdk_delete_event = gdk_event_new (GDK_DELETE); + gdk_delete_event->any.window = widget->window; + gdk_delete_event->any.send_event = TRUE; + gtk_main_do_event (gdk_delete_event); + gdk_event_free (gdk_delete_event); + + return FALSE; + } + + /* we are using the pipe only to check the life state of qt */ + /* + ret = g_io_channel_read_line (gio, &msg, &len, NULL, &err); + if (ret == G_IO_STATUS_ERROR) + g_critical ("Error reading: %s", err->message); + + g_warning ("Read %u bytes: %s", len, msg); + + g_free (msg); + */ + return TRUE; +} + +static GError* +qt_abstract_home_item_error_new (const char *literal) +{ + GError *error = g_error_new_literal (g_quark_from_static_string("qt-loader-execute"), + QT_LOADER_EXECUTE_ERROR, + literal); + return error; +} + +static GError* +qt_abstract_home_item_execute (QtAbstractHomeItem *object) +{ + int qtToGtkPipe[2]; + int ret; + QtAbstractHomeItemPrivate *priv = QT_ABSTRACT_HOME_ITEM (object)->priv; + + /* --- open the communication pipe */ + ret = pipe (qtToGtkPipe); + if (ret == -1) + return qt_abstract_home_item_error_new("Creating pipe failed."); + + /* --- Fork and exec the new application */ + pid_t pid = fork(); + if (pid < 0) { + return qt_abstract_home_item_error_new("Unable do fork new process."); + + } else if (pid) { + /* I am the original process */ + close( qtToGtkPipe[1] ); + + priv->gio_read = g_io_channel_unix_new (qtToGtkPipe[0]); + if (!priv->gio_read) + return qt_abstract_home_item_error_new("Cannot create new GIOChannel!"); + + if (!g_io_add_watch (priv->gio_read, G_IO_IN | G_IO_HUP, + qt_abstract_home_item_gio_in, object)) + return qt_abstract_home_item_error_new("Cannot add watch on GIOChannel!"); + + } else { + /* I am the forked process */ + char *appletId; + char writePipeStr[20]; + + close( qtToGtkPipe[0] ); + + appletId = hd_home_plugin_item_get_applet_id (HD_HOME_PLUGIN_ITEM (object)); + snprintf( writePipeStr, 19, "%d", qtToGtkPipe[1]); + + char *newargv[] = { priv->executable_path, + "-plugin-id", appletId, + "-write-pipe", writePipeStr, + NULL }; + + // note: old file descriptors are still open + execv(newargv[0], newargv); + + // we should not run through here... + g_free (appletId); + } + + return 0; +} + +static void +qt_abstract_home_item_realize (GtkWidget *widget) +{ + GdkDisplay *display; + QtAbstractHomeItem *item = QT_ABSTRACT_HOME_ITEM (widget); + QtAbstractHomeItemPrivate *priv = item->priv; + + GTK_WIDGET_CLASS (qt_abstract_home_item_parent_class)->realize (widget); + + /* Remove the applet id atom again. we have our own */ + display = gdk_drawable_get_display (widget->window); + XDeleteProperty (GDK_WINDOW_XDISPLAY (widget->window), + GDK_WINDOW_XID (widget->window), + gdk_x11_get_xatom_by_name_for_display (display, + "_HILDON_APPLET_ID")); + + if (!priv->realized) { + GError *error = NULL; + priv->realized = TRUE; + error = qt_abstract_home_item_execute (item); + if (error) { + g_warning ("%s", error->message); + g_error_free (error); + } + } +} + +static void +qt_abstract_home_item_show (GtkWidget *widget) +{ + /* Do not call the gtk show. keep the gtk window hidden */ + (void) widget; // unused +} + +static void +qt_abstract_home_item_class_init (QtAbstractHomeItemClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = qt_abstract_home_item_finalize; + + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + widget_class->realize = qt_abstract_home_item_realize; + widget_class->show = qt_abstract_home_item_show; + + g_type_class_add_private (klass, sizeof (QtAbstractHomeItemPrivate)); +} + +/* +static void +qt_abstract_home_item_class_finalize (QtAbstractHomeItemClass *klass) +{ +} +*/ + +// client event with hildon settings +// client notify event... + + +#define HD_PLUGIN_LOADER_QT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), HD_TYPE_PLUGIN_LOADER_QT, HDPluginLoaderQtPrivate)) + +G_DEFINE_TYPE (HDPluginLoaderQt, hd_plugin_loader_qt, HD_TYPE_PLUGIN_LOADER); + +struct _HDPluginLoaderQtPrivate +{ + GHashTable *registry; +}; + + +static GObject * +hd_plugin_loader_qt_load (HDPluginLoader *loader, + const gchar *plugin_id, + GKeyFile *keyfile, + GError **error) +{ + GObject *object = NULL; + + g_return_val_if_fail (loader, NULL); + + if (!keyfile) + { + g_set_error (error, + hd_plugin_loader_error_quark (), + HD_PLUGIN_LOADER_ERROR_KEYFILE, + "A keyfile required to load plugins"); + + return NULL; + } + + /* construct a new proxy object */ + object = g_object_new (QT_TYPE_ABSTRACT_HOME_ITEM, + "plugin-id", plugin_id, + NULL); + + /* --- get the executable path */ + { + QtAbstractHomeItemPrivate *priv = QT_ABSTRACT_HOME_ITEM (object)->priv; + GError *keyfile_error = NULL; + gchar *executable_file = NULL; + + executable_file = g_key_file_get_string (keyfile, + HD_PLUGIN_CONFIG_GROUP, + HD_PLUGIN_CONFIG_KEY_PATH, + &keyfile_error); + g_strstrip (executable_file); + + if (keyfile_error) + { + g_propagate_error (error, keyfile_error); + return NULL; + } + + if (g_path_is_absolute (executable_file)) + { + priv->executable_path = executable_file; + } + else + { + priv->executable_path = g_build_filename (HD_PLUGIN_MODULE_PATH, + executable_file, + NULL); + + g_free (executable_file); + } + } + + return object; +} + + static void +hd_plugin_loader_qt_finalize (GObject *loader) +{ + HDPluginLoaderQtPrivate *priv; + + g_return_if_fail (loader != NULL); + g_return_if_fail (HD_IS_PLUGIN_LOADER_QT (loader)); + + priv = HD_PLUGIN_LOADER_QT (loader)->priv; + + if (priv->registry != NULL) + { + g_hash_table_destroy (priv->registry); + priv->registry = NULL; + } + + G_OBJECT_CLASS (hd_plugin_loader_qt_parent_class)->finalize (loader); +} + +static void +hd_plugin_loader_qt_init (HDPluginLoaderQt *loader) +{ + loader->priv = HD_PLUGIN_LOADER_QT_GET_PRIVATE (loader); + + loader->priv->registry = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + NULL); +} + +static void +hd_plugin_loader_qt_class_init (HDPluginLoaderQtClass *class) +{ + GObjectClass *object_class; + HDPluginLoaderClass *loader_class; + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = hd_plugin_loader_qt_finalize; + + // widget_class = GTK_WIDGET_CLASS (class); + + loader_class = HD_PLUGIN_LOADER_CLASS (class); + loader_class->load = hd_plugin_loader_qt_load; + + g_type_class_add_private (object_class, sizeof (HDPluginLoaderQtPrivate)); +} + +G_MODULE_EXPORT gchar * +hd_plugin_loader_module_type (void) +{ + return "qt"; +} + +G_MODULE_EXPORT HDPluginLoader * +hd_plugin_loader_module_get_instance (void) +{ + return g_object_new (HD_TYPE_PLUGIN_LOADER_QT, NULL); +} + + + diff --git a/qtpluginloader/hd-plugin-loader-qt.h b/qtpluginloader/hd-plugin-loader-qt.h new file mode 100644 index 0000000..a0c4188 --- /dev/null +++ b/qtpluginloader/hd-plugin-loader-qt.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** 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 __HD_PLUGIN_LOADER_QT_H__ +#define __HD_PLUGIN_LOADER_QT_H__ + +#include + +G_BEGIN_DECLS + +#define QT_LOADER_EXECUTE_ERROR 1 + +#define QT_TYPE_ABSTRACT_HOME_ITEM (qt_abstract_home_item_get_type ()) +#define QT_ABSTRACT_HOME_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), QT_TYPE_ABSTRACT_HOME_ITEM, QtAbstractHomeItem)) +#define QT_ABSTRACT_HOME_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), QT_TYPE_ABSTRACT_HOME_ITEM, QtAbstractHomeItemClass)) +#define QT_IS_ABSTRACT_HOME_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), QT_TYPE_ABSTRACT_HOME_ITEM)) +#define QT_IS_ABSTRACT_HOME_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), QT_TYPE_ABSTRACT_HOME_ITEM)) +#define QT_ABSTRACT_HOME_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), QT_TYPE_ABSTRACT_HOME_ITEM, QtAbstractHomeItemClass)) + +typedef struct _QtAbstractHomeItem QtAbstractHomeItem; +typedef struct _QtAbstractHomeItemClass QtAbstractHomeItemClass; +typedef struct _QtAbstractHomeItemPrivate QtAbstractHomeItemPrivate; + +struct _QtAbstractHomeItem +{ + HDHomePluginItem parent; + + QtAbstractHomeItemPrivate *priv; +}; + +struct _QtAbstractHomeItemClass +{ + HDHomePluginItemClass parent; +}; + +GType qt_abstract_home_item_get_type (void); + + +typedef struct _HDPluginLoaderQt HDPluginLoaderQt; +typedef struct _HDPluginLoaderQtClass HDPluginLoaderQtClass; +typedef struct _HDPluginLoaderQtPrivate HDPluginLoaderQtPrivate; + +#define HD_TYPE_PLUGIN_LOADER_QT (hd_plugin_loader_qt_get_type ()) +#define HD_PLUGIN_LOADER_QT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), HD_TYPE_PLUGIN_LOADER_QT, HDPluginLoaderQt)) +#define HD_IS_PLUGIN_LOADER_QT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), HD_TYPE_PLUGIN_LOADER_QT)) +#define HD_PLUGIN_LOADER_QT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), HD_TYPE_PLUGIN_LOADER_QT_CLASS, HDPluginLoaderQtClass)) +#define HD_IS_PLUGIN_LOADER_QT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), HD_TYPE_PLUGIN_LOADER_QT_CLASS)) +#define HD_PLUGIN_LOADER_QT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), HD_TYPE_PLUGIN_LOADER_QT, HDPluginLoaderQtClass)) + +struct _HDPluginLoaderQt +{ + HDPluginLoader parent; + + HDPluginLoaderQtPrivate *priv; +}; + +struct _HDPluginLoaderQtClass +{ + HDPluginLoaderClass parent_class; +}; + +GType hd_plugin_loader_qt_get_type (void); + +G_END_DECLS + +#endif /* __HD_PLUGIN_LOADER_QT_H__ */ diff --git a/qtpluginloader/qtpluginloader.pro b/qtpluginloader/qtpluginloader.pro new file mode 100644 index 0000000..0398280 --- /dev/null +++ b/qtpluginloader/qtpluginloader.pro @@ -0,0 +1,13 @@ +TARGET = qtpluginloader + +TEMPLATE = lib +CONFIG += plugin +SOURCES = hd-plugin-loader-qt.c +HEADERS = hd-plugin-loader-qt.h + +CONFIG += link_pkgconfig +PKGCONFIG += hildon-1 libhildondesktop-1 + +# install +target.path = /usr/lib/hildon-desktop/loaders +INSTALLS += target -- cgit v1.2.3