1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the examples of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qmaemo5homescreenadaptor.h"
44 #include <QtCore/qsocketnotifier.h>
46 #include <QtGui/qapplication.h>
47 #include <QtGui/qx11info_x11.h>
48 #include <QtGui/qwidget.h>
51 #include <X11/Xatom.h>
53 static QCoreApplication::EventFilter oldEventFilter;
54 static QList<QMaemo5HomescreenAdaptor *> allDesktopItems;
56 static Atom atomByName(const char *name)
58 Atom atom = XInternAtom(QX11Info::display(), name, False);
60 qWarning("Unable to obtain %s atom. This class requires a running Hildon session.", name);
70 HildonTypeHomeApplet = 3,
71 HildonAppletSettings = 4,
72 HildonAppletShowSettings = 5,
73 HildonAppletOnCurrentDesktop = 6,
77 static Atom hsAtoms[EnumCount] = { 0, 0, 0, 0, 0, 0, 0 };
79 static void initAtoms()
81 hsAtoms[HildonAppletId] = atomByName("_HILDON_APPLET_ID");
82 hsAtoms[NetWmWindowType] = atomByName("_NET_WM_WINDOW_TYPE");
83 hsAtoms[Utf8String] = atomByName("UTF8_STRING");
84 hsAtoms[HildonTypeHomeApplet] = atomByName("_HILDON_WM_WINDOW_TYPE_HOME_APPLET");
85 hsAtoms[HildonAppletSettings] = atomByName("_HILDON_APPLET_SETTINGS");
86 hsAtoms[HildonAppletShowSettings] = atomByName("_HILDON_APPLET_SHOW_SETTINGS");
87 hsAtoms[HildonAppletOnCurrentDesktop] = atomByName("_HILDON_APPLET_ON_CURRENT_DESKTOP");
90 /*! \class QMaemo5HomescreenAdaptor
92 \brief The QMaemo5HomescreenAdaptor flags a top-level QWidget as homescreen widget
94 QMaemo5HomescreenAdaptor is used in conjunction with the Qt for Maemo homescreen
95 loader. It evaluates the two command line arguments "-plugin-id" and "-write-pipe"
96 to set up a Qt top-level widget as Maemo 5 homescreen widget.
98 Note: By default, the widget will have a black background. In order to make the
99 widget transparent, set the Qt::WA_TranslucentBackground widget attribute.
104 QLabel *label = new QLabel("Hello Homescreen");
105 new QMaemo5HomescreenAdaptor(label);
109 Maemo 5 supports homescreen widgets with settings dialogs. To use it, set
110 the settingsAvailable() property and show a settings dialog when the
111 settingsRequested() signal is emitted.
113 Maemo 5 supports more than one homescreen. In order to determine whether
114 the homescreen widget is on the currently visible homescreen, connect to
115 the homescreenChanged() signal.
118 /*! \property QMaemo5HomescreenAdaptor::settingsAvailable
120 Set this property to true if the widget can make use of a settings dialog,
121 otherwise to false. When this property is set to true, the Maemo 5 homescreen
122 renders a small settings icon on top of the homescreen widget when the
123 user enters the desktop menu. When the user clicks that settings icon, the
124 settingsRequested() signal is emitted.
126 The default is false.
128 \sa settingsRequested()
131 /*! \fn void settingsRequested()
133 This signal is emitted every time the homescreen widget's settings icon is
134 invoked by the user. Note that this icon is only visible when the settingsAvailable()
137 \sa settingsAvailable()
140 /*! \fn void homescreenChanged(bool isOnCurrentHomescreen)
142 This is signal is emitted when current homescreen changes and the homescreen
143 widget becomes visible or invisible. The \a isOnCurrentHomescreen argument
144 indicates whether the homescreen widget is on the current homescreen or not.
146 This signal can be used to start/stop background processing in order to save
151 Constructs a new QMaemo5HomescreenAdaptor for the given \a widget.
153 Note: The widget must be a top-level widget, and must not be reparented
154 during the lifetime of this adaptor.
156 Note: \a widget is also the parent of this class, if the widget is destroyed,
159 QMaemo5HomescreenAdaptor::QMaemo5HomescreenAdaptor(QWidget *widget)
163 Q_ASSERT(widget->isWindow());
168 Display *display = QX11Info::display();
170 const QStringList args = QApplication::arguments();
172 // parse the command line arguments.
174 if ((idx = args.indexOf(QLatin1String("-plugin-id"))) != -1) {
175 appletId = args.value(idx + 1);
176 const QByteArray pluginId = appletId.toUtf8();
177 if (!pluginId.isEmpty()) {
178 XChangeProperty(display,
180 hsAtoms[HildonAppletId],
181 hsAtoms[Utf8String], 8, PropModeReplace,
182 reinterpret_cast<const unsigned char *>(pluginId.constData()),
186 if ((idx = args.indexOf(QLatin1String("-write-pipe"))) != -1) {
188 int sockId = args.value(idx + 1).toInt(&ok);
190 socketNotifier = new QSocketNotifier(sockId, QSocketNotifier::Exception, this);
191 connect(socketNotifier, SIGNAL(activated(int)), this, SLOT(socketException()));
195 // set the X11 atoms to flag our widget as homescreen widget
196 if (!appletId.isEmpty()) {
197 XChangeProperty(display,
199 hsAtoms[NetWmWindowType],
200 XA_ATOM, 32, PropModeReplace,
201 reinterpret_cast<const unsigned char *>(&hsAtoms[HildonTypeHomeApplet]),
206 // --- make this window a child of root
207 XSetTransientForHint(display, widget->winId(),
208 RootWindow(display, widget->x11Info().screen()));
210 // --- add an x11 event filter
212 oldEventFilter = QCoreApplication::instance()->setEventFilter(applicationEventFilter);
214 allDesktopItems.append(this);
218 QMaemo5HomescreenAdaptor::~QMaemo5HomescreenAdaptor()
220 allDesktopItems.removeOne(this);
224 void QMaemo5HomescreenAdaptor::updateStatus()
226 if (appletId.isEmpty())
229 Display *display = QX11Info::display();
231 // Set or remove settings property
233 XChangeProperty(display,
234 appletWidget()->winId(),
235 hsAtoms[HildonAppletSettings],
236 XA_CARDINAL, 32, PropModeReplace,
237 (const unsigned char *) &(hasSettings), 1);
239 XDeleteProperty(display,
240 appletWidget()->winId(),
241 hsAtoms[HildonAppletSettings]);
245 void QMaemo5HomescreenAdaptor::socketException()
247 socketNotifier->setEnabled(false);
248 appletWidget()->close();
252 bool QMaemo5HomescreenAdaptor::applicationEventFilter(void *message, long *result)
257 retval = oldEventFilter(message, result);
259 if (allDesktopItems.isEmpty())
262 XEvent *ev = reinterpret_cast<XEvent *>(message);
264 if (ev->type == ClientMessage) {
265 XClientMessageEvent *cm = (XClientMessageEvent *)message;
266 if (cm->message_type == hsAtoms[HildonAppletShowSettings]) {
267 for (int i = 0; i < allDesktopItems.count(); ++i) {
268 if (allDesktopItems.at(i)->appletWidget()->winId() == ev->xproperty.window) {
269 emit allDesktopItems.at(i)->settingsRequested();
274 } else if (ev->type == PropertyNotify) {
275 if (ev->xproperty.atom == hsAtoms[HildonAppletOnCurrentDesktop]) {
276 for (int i = 0; i < allDesktopItems.count(); ++i) {
277 if (allDesktopItems.at(i)->appletWidget()->winId() == ev->xproperty.window) {
278 emit allDesktopItems.at(i)->homescreenChanged(ev->xproperty.window == 0);