[meego-commits] 9339: Changes to devel:qt-mtf/meegotouch-feedbackreactionmaps
araujo
no_reply at build.meego.com
Tue Nov 9 15:39:03 UTC 2010
Hi,
I have made the following changes to meegotouch-feedbackreactionmaps in project devel:qt-mtf. Please review and accept ASAP.
Thank You,
araujo
[This message was auto-generated]
---
Request #9339:
submit: home:araujo:branches:devel:qt-mtf/meegotouch-feedbackreactionmaps(r2)(cleanup) -> devel:qt-mtf/meegotouch-feedbackreactionmaps
Message:
Update to release tag 0.14.1-3
State: new 2010-11-09T07:39:02 araujo
Comment: None
changes files:
--------------
--- meegotouch-feedbackreactionmaps.changes
+++ meegotouch-feedbackreactionmaps.changes
@@ -0,0 +1,3 @@
+* Fri Nov 5 2010 Luis Araujo <luis.araujo at collabora.co.uk> - 0.14.1.3
+- Update to release tag 0.14.1-3
+
@@ -3 +6 @@
- and the build is actually broken (fixed in newer version).
+ and the build is actually broken (fixed in newer version).
@@ -12 +15 @@
-* Wed Sep 08 2010 Kaitlin Rupert <kaitlin.rupert at intel.com> - 0.14.0.5
+* Wed Sep 8 2010 Kaitlin Rupert <kaitlin.rupert at intel.com> - 0.14.0.5
@@ -17 +20 @@
- Change mkspec install location, qmake-qt4 to qmake, add xi, xext
+ Change mkspec install location, qmake-qt4 to qmake, add xi, xext
@@ -19 +22 @@
-* Thu Jul 08 2010 Kaitlin Rupert <kaitlin.rupert at intel.com> - 0.14.0.1
+* Thu Jul 8 2010 Kaitlin Rupert <kaitlin.rupert at intel.com> - 0.14.0.1
old:
----
meegotouch-feedbackreactionmaps-0.14.0.5.tar.bz2
new:
----
meegotouch-feedbackreactionmaps-0.14.1.3.tar.bz2
spec files:
-----------
--- meegotouch-feedbackreactionmaps.spec
+++ meegotouch-feedbackreactionmaps.spec
@@ -7,7 +7,7 @@
Name: meegotouch-feedbackreactionmaps
Summary: MeeGo Touch Feedback ReactionMaps Plugin
-Version: 0.14.0.5
+Version: 0.14.1.3
Release: 1
Group: System/Libraries
License: LGPLv2.1
@@ -119,4 +119,3 @@
%{_libdir}/*.so
%{_libdir}/pkgconfig/meegotouch-feedbackreactionmaps.pc
# << files devel
-
other changes:
--------------
++++++ meegotouch-feedbackreactionmaps-0.14.0.5.tar.bz2 -> meegotouch-feedbackreactionmaps-0.14.1.3.tar.bz2
--- debian/api
+++ debian/api
@@ -1,7 +1,7 @@
interface: libmeegoreactionmap
type: library
-scope: Platform
-state: unstable
+scope: Platform
+state: stable
libs-pkg: libmeegoreactionmap0
dev-pkg: libmeegoreactionmap-dev
--- debian/changelog
+++ debian/changelog
@@ -1,3 +1,31 @@
+meegofeedback-reactionmaps (0.14.1-3) unstable; urgency=low
+
+ * Fixes: NB#199731 - COREWEB: /usr/bin/meegofeedbackd '_Unwind_VRS_Pop...
+ * Changed testrunner dependency to testrunner-lite
+
+ -- Antti Pulakka <ext-antti.j.pulakka at nokia.com> Fri, 22 Oct 2010 15:47:58 +0200
+
+meegofeedback-reactionmaps (0.14.1-2) unstable; urgency=low
+
+ * Updated debian dependencies
+
+ -- Antti Pulakka <ext-antti.j.pulakka at nokia.com> Mon, 11 Oct 2010 15:25:51 +0200
+
+meegofeedback-reactionmaps (0.14.1-1) unstable; urgency=low
+
+ * Implemented: SWP#FEFRA-449, SWP#FEFRA-441, SWP#FEFRA-440
+
+ -- Csaba Kertesz <csaba.kertesz at vincit.fi> Thu, 07 Oct 2010 12:23:51 +0200
+
+meegofeedback-reactionmaps (0.14.0-6) unstable; urgency=low
+
+ * Touch Screen kernel interface is closed when screen is dimmed or off
+ * Touch Screen kernel interface is closed when no reactionmaps active
+ * Added functional test for above cases
+ * Documentation improved and proof-read
+
+ -- Antti Pulakka <ext-antti.j.pulakka at nokia.com> Mon, 23 Aug 2010 16:16:32 +0200
+
meegofeedback-reactionmaps (0.14.0-5) unstable; urgency=low
* Fix for a memory leak similar to NB#182656 in meegofeedbackd daemon
--- debian/control
+++ debian/control
@@ -2,7 +2,7 @@
Section: libs
Priority: optional
Maintainer: Csaba Kertesz <csaba.kertesz at vincit.fi>
-Build-Depends: debhelper (>= 4.0.0), libmeegofeedback-dev (>= 0.9.1), libqt4-dev (>= 4.6) | libqt4-maemo5-dev (>= 4.6), libmeegotouch-dev, libx11-dev, libxi-dev, libexpat1-dev, libxext-dev, xserver-xorg-input-evdev-dev | no-evdev-dev, pkg-config (>= 0.22), zlib1g-dev, libxtst-dev
+Build-Depends: debhelper (>= 4.0.0), libmeegofeedback-dev (>= 0.10.5), libqt4-dev (>= 4.6) | libqt4-maemo5-dev (>= 4.6), libmeegotouch-dev, libx11-dev, libxi-dev, libexpat1-dev, libxext-dev, xserver-xorg-input-evdev-dev | no-evdev-dev, pkg-config (>= 0.22), zlib1g-dev, libxtst-dev
Standards-Version: 3.6.1
Package: meegofeedback-reactionmap
@@ -92,7 +92,7 @@
Package: libmeegoreactionmap-tests
Section: extra
Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, libmeegoreactionmap0 (= ${Source-Version}), libqtgui4, testrunner, ci-testing
+Depends: ${shlibs:Depends}, ${misc:Depends}, libmeegoreactionmap0 (= ${Source-Version}), libqtgui4, testrunner-lite, ci-testing
XB-Maemo-CI-Packages: libmeegoreactionmap0
XB-Maemo-CI-Stage: fast, staging, acceptance
Description: libmeegoreactionmap unit tests
@@ -106,7 +106,7 @@
Package: libmeegoreactionmap-mcompositor-tests
Section: extra
Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, libqtgui4, mcompositor, testrunner, ci-testing
+Depends: ${shlibs:Depends}, ${misc:Depends}, libqtgui4, mcompositor, testrunner-lite, ci-testing
XB-Maemo-CI-Packages: mcompositor
XB-Maemo-CI-Stage: staging, acceptance, validation
Description: Test to make sure that window stacking works properly
--- debian/rules
+++ debian/rules
@@ -51,6 +51,9 @@
$(MAKE) $(PARALLEL_MAKEFLAGS)
#docbook-to-man debian/meegofeedback-reactionmaps.sgml > meegofeedback-reactionmaps.1
+ # libmeegoreactionmap-doc package
+ $(MAKE) doc
+
touch build-stamp
clean:
@@ -69,9 +72,6 @@
dh_clean -k
dh_installdirs
- # libmeegoreactionmap-doc package
- make $(PARALLEL_MAKEFLAGS) doc
-
# Add here commands to install the package into debian/meegofeedback-reactionmaps.
INSTALL_ROOT=$(CURDIR)/debian/tmp make $(PARALLEL_MAKEFLAGS) install
--- doc/doc.pri
+++ doc/doc.pri
@@ -18,7 +18,7 @@
# Install rules
htmldocs.files = $${OUT_PWD}/doc/html/
- htmldocs.path = /usr/share/doc/meegofeedback-reactionmap
+ htmldocs.path = /usr/share/doc/libmeegoreactionmap-doc
htmldocs.CONFIG += no_check_exist
INSTALLS += htmldocs
}
--- doc/mdoxy.cfg.in
+++ doc/mdoxy.cfg.in
@@ -85,7 +85,7 @@
TOC_EXPAND = YES
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
-GENERATE_TREEVIEW = YES
+GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 200
--- doc/src/mainpage.dox
+++ doc/src/mainpage.dox
@@ -1,9 +1,21 @@
-/*! @mainpage MeeGo Touch Input Method Framework Documentation
+/*! @mainpage libmeegoreactionmap documentation
- at section general General documentation
+ at section Introduction
+
+This library provides a way for the developer to add triggers for specific non-visual feedback in an application when the user touches a defined part of the screen. Non-visual feedback in this context includes haptics (vibration), sounds and effects using the device lights. Feedback is most often used to confirm to the user that the application interface has received their input.
+
+Specifically, the main class of the library, MReactionMap, enables the developer to place an invisible reaction map on top of the application screen. Using screen coordinates, the developer can then define sections in this reaction map and assign each one a trigger for a specific feedback. This map enables widgets (application components, such as buttons) to trigger feedback when they are pressed or released, as long as their coordinates are defined in the reactionmap.
+
+ at section basicusage Basic Usage:
+
+<B>Main classes:</B>
+
+- MReactionMap : to add triggers for low latency haptic feedback to applications
+
+ at section Section2 General documentation
- <a href="tutorial.html">Tutorial for MReactionMap</a>
- at section api API reference
+ at section Section3 API reference
<a href="classes.html">All Classes</a>
*/
--- doc/src/tutorial.dox
+++ doc/src/tutorial.dox
@@ -1,26 +1,26 @@
/*! @page tutorial Tutorial for MReactionMap
@section Overview
-This tutorial shows how to make a simple "Hello World!" application based on QGraphicsView use meegoreactiomap to get its haptic input feedback.
+This tutorial shows how to make a simple "Hello World!" application based on QGraphicsView and use mreactiomap to add haptic input feedback to it.
-What's described here also works for MeeGo Touch applications since MeeGo Touch is built on top of QGraphicsView,
+What is described here also works for MeeGo Touch applications since MeeGo Touch is built on top of QGraphicsView.
@section Section1 Packages needed
Make sure you have the following packages installed in your scratchbox i386 target:
-- @c meegofeedback-reactionmap (version >= 0.14.0)
-- @c libmeegoreactionmap0 (version >= 0.14.0)
-- @c libmeegoreactionmap-dev (version >= 0.14.0)
-- @c libmeegoreactionmap-viewer (version >= 0.14.0)
-- @c libmeegofeedback0 (version >= 0.10.0)
-- @c meegofeedbackd (version >= 0.10.0)
-- @c meegofeedback-dummy (version >= 0.10.0)
+- @c meegofeedback-reactionmap
+- @c libmeegoreactionmap0
+- @c libmeegoreactionmap-dev
+- @c libmeegoreactionmap-viewer
+- @c libmeegofeedback0
+- @c meegofeedbackd
+- @c meegofeedback-dummy
- at c meegofeedback-dummy is a dummy backend for meegofeedbackd. It has to be installed it since we can't use (or need) a real backend in scratchbox.
+ at c meegofeedback-dummy is a dummy backend for the meegofeedbackd daemon. It has to be installed it since we cannot use (or need) a real hardware for haptic feedback in scratchbox.
@section Section2 The "Hello World!" sample application
-This sample application just displays two reactangles. One containing the word "Hello" and the other one, "World".
-It's hardcoded to be displayed on a 864x480 screen.
+This sample application displays two rectangles. One containing the word "Hello" and the other one, "World".
+It is hardcoded to be displayed on a 864x480 screen.
When you run it in scratchbox you should see the following in your Xephyr window:
@@ -85,92 +85,75 @@
@section Section3 Using libmeegoreactionmap
-Now let's make this sample application use libmeegoreactionmap. The objective is to make the "Hello" box give a "press" haptic feedback when user puts his finger on it and a "release" haptic feedback when user lifts his finger from it.
+Now let us make this sample application use libmeegoreactionmap. The objective is to make the "Hello" box give a "press" haptic feedback when the user puts their finger on it and a "release" haptic feedback when the user lifts their finger off it.
-The "World" box will stay without any haptic feedback.
+No haptic feedback is assigned to the "World" box in this tutorial.
@subsection Subsection31 Modifying reactionmaptutorialapp.pro file
-To make the application link against libmeegoreactionmap add the following line:
+To make the application link against libmeegoreactionmap, add the following line:
@code
CONFIG += meegoreactionmap
@endcode
@subsection Subsection32 Modifying main.cpp
-In the beginning of the file, include libfeedbackreactor header file:
+In the beginning of the file, include MReactionMap header file:
@code
#include <mreactionmap.h>
@endcode
-This header defines MReactionMap class.
+This header defines the MReactionMap class.
-Now let's create a reaction map for our application. A reaction map contains the description of all reactive areas of an application window. In other words: it says which (if any) haptic input feedback should be given when the screen is touched for every single part of the screen.
+Now let us create a reaction map for our application. A reaction map contains the description of all reactive areas of an application window. In other words: it states which (if any) haptic input feedback should be given when the screen is touched for every single part of the screen.
An application may only have one reaction map per top-level window. This means that if an application has more than one top-level window, there can be only one reaction map defined for each top-level window. Reaction map must be created after the top-level window in question has been created.
In our case, there is only one top-level window and it is the QGraphicsView itself.
-MReactionMap constructor takes two parameters. The first parameter is mandatory and it is the pointer to the top-level window. The actual pointer points to class QWidget which the QGraphicsView inherits. The second parameter is an optional name/identifier of the application. This information is used to locate and load all custom haptic input feedbacks that the application may have installed.
+MReactionMap constructor takes two parameters. The first parameter is mandatory as it is the pointer to the top-level window. It points to class QWidget which the QGraphicsView inherits. The second parameter is an optional name/identifier of the application. This information is used to locate and load all custom haptic input feedbacks that the application may have installed.
-Let's create our reaction map. Put the following line after @c mainWindow creation:
+Let us create our reaction map. Add the following line after @c mainWindow creation:
@code
MReactionMap reactionMap(&mainWindow, "reactionmaptutorial");
@endcode
-Next, add a function that draws a rectangular reactive area for a given QGraphicsItem.
+Using MReactionMap::setReactiveDrawingValue() method sets the default "press" feedback when finger touches the screen and the default "release" feedback when finger is lifted from the screen:
@code
-static void drawReactionMap(QGraphicsItem *item)
-{
- QList<QGraphicsView *> viewList = item->scene()->views();
-
- for (int i = 0; i < viewList.size(); ++i) {
- MReactionMap *reactionMap = MReactionMap::instance(viewList[i]);
-
- if (reactionMap == 0) {
- continue;
- }
-
- reactionMap->setTransform(item, viewList[i]);
- reactionMap->setReactiveDrawingValue();
- reactionMap->fillRectangle(item->boundingRect());
- }
-}
+ reactionMap.setReactiveDrawingValue();
@endcode
-Using MReactionMap::setTransform() causes the following rectangle drawing to use a transformation matrix that maps from item coordinates to reaction map coordinates.
-<br /><b>Warning:</b> The only supported transformations are scaling and translating. Undefined results will follow if the item is sheared or rotated.
-<br />Using MReactionMap::setReactiveDrawingValue() method sets the standard "press" feedback when finger touches the screen and the standard "release" feedback when finger is lifted from the screen.
-<br />Finally using MReactionMap::fillRectangle() method will draw the reactive area to the reaction map.
-Now add a line to draw the reactive area of the "Hello" box. To do this, put the following line before calling mainWindow.showFullScreen()
+Now add a function call to draw a rectangular reactive area around a given QGraphicsItem:
@code
- drawReactionMap(&helloRect);
+ reactionMap.fillItemBoundRect(&helloRect);
@endcode
+<b>Warning:</b> The only supported transformations are scaling and translating for the graphics items. Undefined results will follow if the item is sheared or rotated.
+
@section Section4 Running and testing in scratchbox
-How can you tell that your reaction map drawing code is really working? For that we use the @c meegoreactionmap-viewer tool.
+How can you tell that your reaction map drawing code is really working? For that we use the @c meegoreactionmap-viewer tool.
Follow these steps:
-- Run @c meegofeedbackd daemon
-- Run @c reactionmaptutorialapp
-- Open a new Xephyr window in, for instance, DISPLAY=:3
+-# Run @c meegofeedbackd daemon
+-# Run @c reactionmaptutorialapp
+-# Open a new Xephyr window in, for instance, DISPLAY=:3
- at c meegoreactionmap-viewer will run in this separate Xephyr window you just created. @c meegoreactionmap-viewer can take several parameters but the only mandatory one is the process id of the application whose reaction map you want to visualize.
+ at c meegoreactionmap-viewer will run in this separate Xephyr window you just created. @c meegoreactionmap-viewer can take several parameters but the only mandatory one is the process id of the application whose reaction map you want to visualize.
Run @c meegoreactionmap-viewer without any parameter to get information on its usage.
-For example: If the process id of your @c reactionmaptutorialapp instance is @c 6655 and the extra Xephyr window is on DISPLAY 3, the resulting command line would look like that:
+For example: If the process id of your @c reactionmaptutorialapp instance is @c 6655 and the extra Xephyr window is on DISPLAY 3, the resulting command line would look like this in scratchbox:
@code
$ DISPLAY=:3 meegoreactionmap-viewer 6655
@endcode
-Your extra Xephyr window should then look like the following:
+Your extra Xephyr window should then look similar to the following screenshot:
<img width="450" alt="meegoreactionmaptutorial2.png" src="meegoreactionmaptutorial2.png" height="260"></img>
-There you can see that the only part of the screen that gives haptic feedback is the one occupied by the "Hello" box. Since you didn't provide a color mapping file, the color red was used to represent areas that give "press" feedback when finger touches it and "release" feedback when finger is lifted from it. For information on color mapping files, run @c meegoreactionmap-viewer without any parameters.
+In the screenshot above you can see that the only part of the screen that gives haptic feedback is the one occupied by the "Hello" box. Since you did not provide a color mapping file, the color red is used to represent the area that gives "press" feedback when touched with a finger and "release" feedback when the finger is lifted from it. For information on color mapping files, run @c meegoreactionmap-viewer without any parameters.
@subsection Subsection41 Resulting main.cpp
@code
@@ -183,14 +166,15 @@
#include <QGraphicsRectItem>
#include <QGraphicsSimpleTextItem>
-static void drawReactionMap(QGraphicsItem *item);
-
int main (int argc, char **argv)
{
QApplication app(argc, argv);
QGraphicsView mainWindow;
mainWindow.setWindowFlags(Qt::FramelessWindowHint);
+
+ //Create reaction map for mainWindow
MReactionMap reactionMap(&mainWindow, "reactionmaptutorial");
+
QFont font;
QGraphicsScene scene;
@@ -218,29 +202,17 @@
mainWindow.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mainWindow.setAlignment(Qt::AlignLeft | Qt::AlignTop);
- drawReactionMap(&helloRect);
+ // Set the standard "press" feedback when finger touches the screen and
+ // the standard "release" feedback when finger is lifted from the screen
+ reactionMap.setReactiveDrawingValue();
+
+ // Draw a rectangular reactive area for "helloRect" QGraphicsItem:
+ reactionMap.fillItemBoundRect(&helloRect);
mainWindow.showFullScreen();
return app.exec();
}
-
-static void drawReactionMap(QGraphicsItem *item)
-{
- QList<QGraphicsView *> viewList = item->scene()->views();
-
- for (int i = 0; i < viewList.size(); ++i) {
- MReactionMap *reactionMap = MReactionMap::instance(viewList[i]);
-
- if (reactionMap == 0) {
- continue;
- }
-
- reactionMap->setTransform(item, viewList[i]);
- reactionMap->setReactiveDrawingValue();
- reactionMap->fillRectangle(item->boundingRect());
- }
-}
@endcode
@subsection Subsection42 Resulting reactionmaptutorialapp.pro
--- src/client/mreactionmap.cpp
+++ src/client/mreactionmap.cpp
@@ -106,6 +106,10 @@
void MReactionMap::setTransform(QGraphicsItem *item, QGraphicsView *view)
{
+ if (!item || !view) {
+ return;
+ }
+
d->setTransform(item, view);
}
@@ -156,27 +160,30 @@
void MReactionMap::fillItemBoundRect(QGraphicsItem *item)
{
- if (!item || !item->scene() || item->scene()->views().isEmpty()) {
+ if (!item) {
return;
}
- // Find the view that is associated with this reaction map
- int viewIndex = -1;
- for (int i = 0; i < item->scene()->views().size(); ++i) {
- if (d->topLevelWidget == item->scene()->views()[i]) {
- viewIndex = i;
- break;
- }
- }
+ QList<QGraphicsView*> views = d->findViewForItem(item);
// If a view associated with this reaction map was found, use that
// view's transformation to draw to this reaction map.
- if (viewIndex >= 0) {
+ if (!views.isEmpty()) {
QTransform currentTransform = d->transform;
- QRectF rect = item->boundingRect();
-
- setTransform(item, item->scene()->views()[viewIndex]);
- fillRectangle(rect);
+ QRectF itemRect = item->boundingRect();
+ // Fill the bounding rectangle in every view
+ for (int i = 0; i < views.size(); ++i) {
+ // Don't draw ouside the view, only draw the part of item
+ // that is currently visible inside the view.
+ QRectF viewRect = item->deviceTransform(views[i]->viewportTransform()).inverted().mapRect(views[i]->rect());
+ QRectF resultRect = viewRect.intersected(itemRect);
+
+ // Don't try to draw empty rectangels
+ if (!resultRect.isEmpty()) {
+ setTransform(item, views[i]);
+ fillRectangle(resultRect);
+ }
+ }
d->setTransform(currentTransform);
}
}
@@ -185,7 +192,7 @@
const QString &pressFeedback,
const QString &releaseFeedback)
{
- if (!item || !item->scene() || item->scene()->views().isEmpty()) {
+ if (!item) {
return;
}
--- src/client/mreactionmap_p.cpp
+++ src/client/mreactionmap_p.cpp
@@ -114,7 +114,7 @@
newSharedMemoryAddress = shmat(id, 0, 0);
- if ((int)newSharedMemoryAddress == -1) {
+ if ((qptrdiff)newSharedMemoryAddress == -1) {
qCritical() << "Unable to get shared memory address for"
<< tempFilePath;
newSharedMemoryAddress = 0;
@@ -169,6 +169,35 @@
transform = screenToReactionMapTransform;
}
+QList<QGraphicsView*> MReactionMapPrivate::findViewForItem(QGraphicsItem *item)
+{
+ QList<QGraphicsView*> retVal;
+ if (!item || !item->scene() || item->scene()->views().isEmpty()) {
+ return retVal;
+ }
+
+ // Go through all views of the items and find out which view(s)
+ // have a reaction map associated with the view (or the view's
+ // parent top level widget)
+ for (int i = 0; i < item->scene()->views().size(); ++i) {
+ // Find the top level widget
+ QWidget *parentWidget = item->scene()->views()[i];
+ while (parentWidget && parentWidget->parentWidget()) {
+ if (parentWidget->parentWidget()) {
+ parentWidget = parentWidget->parentWidget();
+ } else {
+ break;
+ }
+ }
+
+ if (topLevelWidget == parentWidget) {
+ retVal << item->scene()->views()[i];
+ }
+ }
+
+ return retVal;
+}
+
void MReactionMapPrivate::setTransform(QGraphicsItem *item, QGraphicsView *view)
{
// From item's local coordinate system to scene coordinate system
@@ -188,7 +217,7 @@
viewPosScreenCoords = view->mapToGlobal(QPoint(0,0));
viewToScreenTransform =
- QTransform::fromTranslate(-viewPosScreenCoords.x(), -viewPosScreenCoords.y());
+ QTransform::fromTranslate(viewPosScreenCoords.x(), viewPosScreenCoords.y());
// It's itemToScene followed by sceneToView, viewToScreen and finally by screenToReactionMap
transform =
--- src/client/mreactionmap_p.h
+++ src/client/mreactionmap_p.h
@@ -19,6 +19,7 @@
#include <QTransform>
#include <QObject>
+#include <QList>
#include "mfeedbackpalette.h"
#include "mreactionmapconnection.h"
@@ -48,6 +49,7 @@
// path to a temp file.
bool buildSharedMemoryImage(const QString& tempFilePath);
+ QList<QGraphicsView*> findViewForItem(QGraphicsItem *item);
void setTransform(QGraphicsItem *item, QGraphicsView *view);
void setTransform(QTransform transform);
// Build screenToReactionMapTransform attribute
--- src/mfsource/mfconnection.cpp
+++ src/mfsource/mfconnection.cpp
@@ -18,8 +18,10 @@
#include "mfsession.h"
#include <mfcommondata.h>
-#include <QLocalSocket>
+
+#include <QCoreApplication>
#include <QDebug>
+#include <QLocalSocket>
#include "mfreactionmap.h"
#include "mfreactionmapstack.h"
@@ -50,6 +52,7 @@
// Remove all existing reaction maps
QMap<quint32, MfReactionMap *>::iterator i = reactionMaps.begin();
while (i != reactionMaps.end()) {
+ stack->remove(i.value());
delete i.value();
i = reactionMaps.erase(i);
}
@@ -72,6 +75,33 @@
}
}
+void MfConnection::sessionSetupReady()
+{
+ MfReactionMap *newReactionMap = new MfReactionMap(sessions[0].session, sessions[0].windowId, clientPid, this);
+
+ if (reactionMaps.contains(sessions[0].id) == false &&
+ newReactionMap->init() == true) {
+ QDataStream socketStream(socket);
+
+ stack->add(newReactionMap);
+ reactionMaps.insert(sessions[0].id, newReactionMap);
+
+ // Send back information needed by the client to attach himself to the
+ // newly created shared memory
+ socketStream << sessions[0].id;
+ socketStream << newReactionMap->tempFilePath();
+
+ // Reaction map creation has ended
+ qDebug() << "MfConnection: finished adding reaction map for client"
+ << sessions[0].clientName;
+ sessions[0].session = NULL;
+ sessions.remove(0);
+ } else {
+ // We are doomed.
+ goDoomed();
+ }
+}
+
void MfConnection::init()
{
QDataStream socketStream (socket);
@@ -84,42 +114,24 @@
void MfConnection::readRequest()
{
quint8 requestType;
- QDataStream socketStream (socket);
+ QDataStream socketStream(socket);
socketStream >> requestType;
switch (requestType) {
case MF_REQUEST_ADD:
{
- quint32 identifier;
- QString clientName;
- quint32 windowId;
- MfReactionMap *newReactionMap;
+ SessionData newSession;
// Requested new reaction map
- socketStream >> identifier;
- socketStream >> clientName;
- socketStream >> windowId;
-
- newReactionMap = new MfReactionMap(new MfSession(clientName), windowId, clientPid, this);
-
- if (reactionMaps.contains(identifier) == false &&
- newReactionMap->init() == true) {
- stack->add(newReactionMap);
- reactionMaps.insert(identifier, newReactionMap);
-
- // Send back information needed by the client to attach himself to the
- // newly created shared memory
- socketStream << identifier;
- socketStream << newReactionMap->tempFilePath();
-
- // Reaction map creation has ended
- qDebug() << "MfConnection: finished adding reaction map for client"
- << clientName;
- } else {
- // We are doomed.
- goDoomed();
- }
+ socketStream >> newSession.id;
+ socketStream >> newSession.clientName;
+ socketStream >> newSession.windowId;
+
+ newSession.session = new MfSession(newSession.clientName);
+ sessions.prepend(newSession);
+ connect(newSession.session, SIGNAL(setupReady()), this, SLOT(sessionSetupReady()),
+ Qt::QueuedConnection);
}
break;
--- src/mfsource/mfconnection.h
+++ src/mfsource/mfconnection.h
@@ -19,11 +19,21 @@
#include <QObject>
#include <QMap>
+#include <QVector>
#include <QPointer>
class QLocalSocket;
class MfReactionMapStack;
class MfReactionMap;
+class MfSession;
+
+struct SessionData
+{
+ quint32 id;
+ QString clientName;
+ quint32 windowId;
+ MfSession* session;
+};
class MfConnection : public QObject
{
@@ -35,6 +45,7 @@
private slots:
void readSocketData();
+ void sessionSetupReady();
private:
void init();
@@ -51,6 +62,7 @@
MfReactionMapStack *stack;
QMap <quint32, MfReactionMap *> reactionMaps;
qint64 clientPid;
+ QVector<SessionData> sessions;
};
#endif
--- src/mfsource/mfkernelthread.cpp
+++ src/mfsource/mfkernelthread.cpp
@@ -26,13 +26,16 @@
#include <stdint.h>
#include <QtDebug>
+#include <QString>
#include "mfdefaulttranslator.h"
#include "mfreactionmapstack.h"
#include "mfsettings.h"
+static QString touchScreenDevicePath("/dev/input/ts");
+
MfKernelThread::MfKernelThread(MfReactionMapStack *reactionMapStack, QObject *parent) :
- QThread(parent), reactionMapStack(reactionMapStack)
+ QThread(parent), reactionMapStack(reactionMapStack), isActive(true)
{
}
@@ -60,24 +63,27 @@
{
bool ok = true;
int result;
- int nfsd;
// We must have at least one touch device
Q_ASSERT(touchDevicesVector.size() > 0);
- nfsd = computeNFSD();
+ nfds = computeNFDS();
do {
- ok = waitForEvent(nfsd);
+ ok = waitForEvent();
} while (ok);
- // Close all input event files
+ // Close all open input event file descriptors
for (int i = 0; i < touchDevicesVector.size(); ++i) {
- result = close(touchDevicesVector[i]->fd);
- if (result == -1) {
- qWarning("MfKernelThread: Failed to close input event fd.");
+ if (touchDevicesVector[i]->fd >= 0) {
+ result = close(touchDevicesVector[i]->fd);
+ touchDevicesVector[i]->fd = -1;
+ if (result == -1) {
+ qWarning("MfKernelThread: Failed to close input event fd.");
+ }
}
}
+
// Is it a right place to do the clean up?
qDeleteAll(touchDevicesVector);
touchDevicesVector.clear();
@@ -87,7 +93,60 @@
return true;
}
-bool MfKernelThread::waitForEvent(int nfsd)
+bool MfKernelThread::readHostMessage()
+{
+ bool ret = true;
+ int bytes;
+ char buf[1];
+
+ bytes = read(communicationSocketFd, buf, 1);
+ if (bytes < 1) {
+ qWarning("MfKernelThread: Failed to read a message from host at readHostMessage");
+ return ret;
+ }
+
+ switch (buf[0]) {
+ case MF_KERNEL_THREAD_STOP:
+ // Return false to break from the loop and end thread
+ ret = false;
+ break;
+
+ case MF_KERNEL_THREAD_PAUSE:
+ // Mark status as inactive and close all kernel interfaces
+ isActive = false;
+ for (int i = 0; i < touchDevicesVector.size(); ++i) {
+ MfTouchDevice *touchDevice = touchDevicesVector[i];
+ if (touchDevice->fd >= 0) {
+ close(touchDevice->fd);
+ touchDevice->fd = -1;
+ }
+ }
+ nfds = computeNFDS();
+ break;
+
+ case MF_KERNEL_THREAD_RESUME:
+ // Mark status as active and reopen all kernel interfaces
+ isActive = true;
+ for (int i = 0; i < touchDevicesVector.size(); ++i) {
+ MfTouchDevice *touchDevice = touchDevicesVector[i];
+ if (touchDevice->fd < 0) {
+ if ((touchDevice->fd = open(touchScreenDevicePath.toAscii().constData(), O_RDONLY)) < 0) {
+ touchDevice->fd = -errno;
+ qWarning("MfKernelThread: open error");
+ }
+ }
+ }
+ nfds = computeNFDS();
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+bool MfKernelThread::waitForEvent()
{
fd_set readFdSet;
int ret = 0;
@@ -96,22 +155,30 @@
// Build the file descriptors set
FD_ZERO(&readFdSet);
- FD_SET(stopListeningSocketFd, &readFdSet);
- for (i = 0; i < touchDevicesVector.size(); ++i) {
- FD_SET(touchDevicesVector[i]->fd, &readFdSet);
+ FD_SET(communicationSocketFd, &readFdSet);
+
+ // Only add touchsceen file descriptors if display is active
+ if (isActive) {
+ for (i = 0; i < touchDevicesVector.size(); ++i) {
+ if (touchDevicesVector[i]->fd >= 0) {
+ FD_SET(touchDevicesVector[i]->fd, &readFdSet);
+ }
+ }
}
- ret = select(nfsd, &readFdSet, NULL/*writefds*/, NULL/*exceptfds*/, NULL);
+
+ ret = select(nfds, &readFdSet, NULL/*writefds*/, NULL/*exceptfds*/, NULL);
if (ret == -1) {
qCritical("MfKernelThread: Error in select()");
ok = false;
- } else if (FD_ISSET(stopListeningSocketFd, &readFdSet)) {
- // It's time to exit
- ok = false;
- } else {
+ } else if (FD_ISSET(communicationSocketFd, &readFdSet)) {
+ ok = readHostMessage();
+ } else if (isActive) {
for (i = 0; i < touchDevicesVector.size(); ++i) {
- MfTouchDevice *touchDevice = touchDevicesVector[i];
- if (FD_ISSET(touchDevice->fd, &readFdSet)) {
- touchDevice->processEvents();
+ if (touchDevicesVector[i]->fd >= 0) {
+ MfTouchDevice *touchDevice = touchDevicesVector[i];
+ if (FD_ISSET(touchDevice->fd, &readFdSet)) {
+ touchDevice->processEvents();
+ }
}
}
}
@@ -122,10 +189,8 @@
bool MfKernelThread::scanInputDevices()
{
- // Loop until we find both touch points or we finished
- // scanning all available event files
int fd;
- fd = checkInputDevice("/dev/input/ts");
+ fd = checkInputDevice(touchScreenDevicePath.toAscii().constData());
if (fd == -ENOENT)
return false;
@@ -208,15 +273,19 @@
return highestFd;
}
-int MfKernelThread::computeNFSD()
+int MfKernelThread::computeNFDS()
{
- int highestFd;
+ int highestFd = -1;
+
+ // Only consider touch screen fd if screen is active
+ if (isActive) {
+ highestFd = findHighestTouchPointFd();
+ }
- highestFd = findHighestTouchPointFd();
- if (highestFd > stopListeningSocketFd) {
+ if (highestFd > communicationSocketFd) {
return highestFd + 1;
} else {
- return stopListeningSocketFd + 1;
+ return communicationSocketFd + 1;
}
}
--- src/mfsource/mfkernelthread.h
+++ src/mfsource/mfkernelthread.h
@@ -23,6 +23,12 @@
#include <QThread>
#include <QVector>
+// Define communication protocol between MfKernelThread
+// and MfTouchScreenListener (kernel implementation)
+#define MF_KERNEL_THREAD_STOP 0
+#define MF_KERNEL_THREAD_PAUSE 1
+#define MF_KERNEL_THREAD_RESUME 2
+
class MfReactionMapStack;
class MfTouchScreenTranslator;
@@ -65,7 +71,7 @@
QObject *parent = 0);
~MfKernelThread();
- int stopListeningSocketFd;
+ int communicationSocketFd;
protected:
@@ -75,18 +81,20 @@
bool setup();
bool listen();
+ bool readHostMessage();
bool scanInputDevices();
int checkInputDevice(const char *name);
- bool waitForEvent(int nfsd);
+ bool waitForEvent();
int findHighestTouchPointFd();
- // compute nfsd parameter used in select() function call
- int computeNFSD();
+ // Compute nfds parameter used in select() function call
+ int computeNFDS();
QVector<MfTouchDevice*> touchDevicesVector;
-
MfReactionMapStack *reactionMapStack;
+ int nfds;
+ bool isActive;
};
#endif
--- src/mfsource/mfreactionmap.cpp
+++ src/mfsource/mfreactionmap.cpp
@@ -224,8 +224,9 @@
int width = MfSettings::reactionMapWidth();
int height = MfSettings::reactionMapHeight();
- if (session)
+ if (session) {
buildFeedbackList(session->feedbackHash);
+ }
#ifdef FR_LOCAL_REACTIONMAP
// Allocate memory for image. No shared memory involved.
@@ -277,7 +278,7 @@
sharedMemoryAddress = shmat(sharedMemoryId, 0, 0);
- if ((int)sharedMemoryAddress == -1) {
+ if ((qptrdiff)sharedMemoryAddress == -1) {
qCritical() << "Unable to get shared memory address for"
<< tempFileName;
return false;
--- src/mfsource/mfreactionmapstack.cpp
+++ src/mfsource/mfreactionmapstack.cpp
@@ -26,7 +26,7 @@
#include "mfxcalib.h"
MfReactionMapStack::MfReactionMapStack(bool ignoreStacking, QObject *parent)
- : QObject(parent), ignoreStacking(ignoreStacking), calibration(0)
+ : QObject(parent), ignoreStacking(ignoreStacking), calibration(0), reactiveOnTop(false)
{
if (ignoreStacking) {
qDebug("MfReactionMapStack: Ignoring window stacking.");
@@ -68,9 +68,6 @@
{
QMutexLocker locker(&mutex);
- Q_ASSERT(reactionMapHash.contains(reactionMap->windowId()));
- Q_ASSERT(reactionMapList.contains(reactionMap));
-
if (reactionMapHash.remove(reactionMap->windowId())) {
reactionMapList.removeOne(reactionMap);
rebuildStack();
@@ -156,10 +153,22 @@
rebuildStack();
}
+bool MfReactionMapStack::hasWindowReactionMap(quint32 windowId) {
+ QMutexLocker locker(&mutex);
+
+ return reactionMapHash.contains(windowId);
+}
+
+bool MfReactionMapStack::isReactiveWindowOnTop() const
+{
+ return reactiveOnTop;
+}
+
void MfReactionMapStack::rebuildStack()
{
stack.clear();
quint32 windowId;
+ bool onTop = false;
for (int i = windowList.size() - 1; i >= 0; i--) {
windowId = windowList[i];
@@ -170,6 +179,16 @@
}
}
+ // Send signal when a topmost window that uses reaction maps
+ // appears or disappears.
+ if (!windowList.isEmpty()) {
+ onTop = reactionMapHash.contains(windowList.last());
+ }
+ if (onTop != reactiveOnTop) {
+ reactiveOnTop = onTop;
+ emit reactiveWindowOnTop(reactiveOnTop);
+ }
+
#ifdef MF_DEBUG
print();
#endif
--- src/mfsource/mfreactionmapstack.h
+++ src/mfsource/mfreactionmapstack.h
@@ -46,6 +46,13 @@
*/
void released(const QPoint &position);
+ bool hasWindowReactionMap(quint32 windowId);
+
+ bool isReactiveWindowOnTop() const;
+
+signals:
+ void reactiveWindowOnTop(bool state);
+
public slots:
/* Reorder reaction maps according to their window ids.
* @param window Current X Window ID stack, ordered bottom-to-top.
@@ -92,6 +99,9 @@
// Calibration instance for X coordinates
MfXCalib *calibration;
+
+ // Tells if the topmost window uses reaction map
+ bool reactiveOnTop;
};
#endif
--- src/mfsource/mfreactorsource.cpp
+++ src/mfsource/mfreactorsource.cpp
@@ -16,11 +16,14 @@
#include "mfreactorsource.h"
#include "mfserver.h"
+#include "mftouchscreenlistener.h"
+#include "mfxlistener.h"
#include <mfsettings.h>
MfReactorSource::MfReactorSource()
- : touchScreenListener(0), reactionMapStack(MfSettings::ignoreStacking())
+ : touchScreenListener(NULL), reactionMapStack(MfSettings::ignoreStacking()),
+ reactionMapActive(true), displayActive(true), initialized(false)
{
}
@@ -28,12 +31,17 @@
{
if (server) {
delete server;
- server = 0;
+ server = NULL;
}
if (touchScreenListener) {
delete touchScreenListener;
- touchScreenListener = 0;
+ touchScreenListener = NULL;
+ }
+
+ if (xListener) {
+ delete xListener;
+ xListener = NULL;
}
}
@@ -41,23 +49,76 @@
{
bool ok;
- ok = reactionMapStack.connect(&xListener,
+ if (initialized) {
+ return true;
+ }
+
+ xListener = new MfXListener(&reactionMapStack);
+
+ ok = reactionMapStack.connect(xListener,
SIGNAL(windowStackChanged(QList<quint32>)),
SLOT(reorder(QList<quint32>)));
if (!ok) return false;
- ok = xListener.startListening();
+ ok = connect(&reactionMapStack, SIGNAL(reactiveWindowOnTop(bool)),
+ this, SLOT(updateState()));
+ if (!ok) return false;
+
+ ok = xListener->startListening();
if (!ok) return false;
touchScreenListener = new MfTouchScreenListener(&reactionMapStack);
ok = touchScreenListener->startListening();
if (!ok) return false;
+ ok = connect(this, SIGNAL(stateChanged(bool)),
+ touchScreenListener, SLOT(setActive(bool)));
+ if (!ok) return false;
+
server = new MfServer(&reactionMapStack, this);
ok = server->init();
if (!ok) return false;
+ initialized = true;
+
+ // Get the real state after initalization
+ updateState();
+
return true;
}
+bool MfReactorSource::isActive() const
+{
+ return reactionMapActive;
+}
+
+void MfReactorSource::updateState()
+{
+ bool oldVal = reactionMapActive, reactiveOnTop;
+
+ if (!initialized) {
+ return;
+ }
+
+ reactiveOnTop = reactionMapStack.isReactiveWindowOnTop();
+
+ reactionMapActive = reactiveOnTop && displayActive;
+
+ if (oldVal != reactionMapActive) {
+ emit stateChanged(reactionMapActive);
+ }
+}
+
+void MfReactorSource::deviceStateChanged(const QMap<QString, QString> &newState)
+{
+ if (newState.contains("display")) {
+ if (newState["display"] == "off") {
+ displayActive = false;
+ } else {
+ displayActive = true;
+ }
+ updateState();
+ }
+}
+
Q_EXPORT_PLUGIN2(meegofeedback-reactionmaps, MfReactorSource);
--- src/mfsource/mfreactorsource.h
+++ src/mfsource/mfreactorsource.h
@@ -18,28 +18,46 @@
#define MFREACTORSOURCE_H
#include <QObject>
-#include <mfsourceinterface.h>
+#include <mfsourcebase.h>
#include "mfreactionmapstack.h"
-#include "mftouchscreenlistener.h"
-#include "mfxlistener.h"
class MfServer;
+class MfXListener;
+class MfTouchScreenListener;
-class MfReactorSource : public QObject, MfSourceInterface
+class MfReactorSource : public MfSourceBase
{
Q_OBJECT
Q_INTERFACES(MfSourceInterface)
public:
MfReactorSource();
virtual ~MfReactorSource();
+
+ // Exported method (defined in MfSourceBase)
bool init();
+ // Internal method
+ bool isActive() const;
+
+public slots:
+ // Exported method (defined in MfSourceBase)
+ void deviceStateChanged(const QMap<QString, QString> &newState);
+
+signals:
+ void stateChanged(bool active);
+
+private slots:
+ void updateState();
+
private:
MfTouchScreenListener *touchScreenListener;
MfServer *server;
MfReactionMapStack reactionMapStack;
- MfXListener xListener;
+ MfXListener *xListener;
+ bool reactionMapActive;
+ bool displayActive;
+ bool initialized;
};
#endif
--- src/mfsource/mfsource_common.pri
+++ src/mfsource/mfsource_common.pri
@@ -2,7 +2,7 @@
INCLUDEPATH += . \
../common
CONFIG += link_pkgconfig plugin meegofeedback
-QT += network
+QT += network dbus
PKGCONFIG += xi xorg-evdev
QMAKE_CXXFLAGS += -finline-functions -fno-strict-aliasing
CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG_OUTPUT
--- src/mfsource/mftouchscreenlistener.h
+++ src/mfsource/mftouchscreenlistener.h
@@ -33,6 +33,11 @@
bool startListening();
bool stopListening();
+ bool isActive();
+
+public slots:
+ void setActive(bool active);
+
private:
MfTouchScreenListenerPriv *d;
};
--- src/mfsource/mftouchscreenlistener_dummy.cpp
+++ src/mfsource/mftouchscreenlistener_dummy.cpp
@@ -36,3 +36,13 @@
{
return true;
}
+
+bool MfTouchScreenListener::isActive()
+{
+ return true;
+}
+
+void MfTouchScreenListener::setActive(bool active)
+{
+ Q_UNUSED(active);
+}
--- src/mfsource/mftouchscreenlistener_kernel.cpp
+++ src/mfsource/mftouchscreenlistener_kernel.cpp
@@ -28,14 +28,16 @@
// 0 - Used by MfTouchScreenListener on main thread
// 1 - Used by MfKernelThread on listener thread
- int stopListeningSocketFdPair[2];
+ int communicationSocketFdPair[2];
+
+ bool isActive;
};
MfTouchScreenListenerPriv::MfTouchScreenListenerPriv(MfReactionMapStack *reactionMapStack)
- : kernelThread(reactionMapStack)
+ : kernelThread(reactionMapStack), isActive(true)
{
- stopListeningSocketFdPair[0] = -1;
- stopListeningSocketFdPair[1] = -1;
+ communicationSocketFdPair[0] = -1;
+ communicationSocketFdPair[1] = -1;
}
MfTouchScreenListener::MfTouchScreenListener(MfReactionMapStack *reactionMapStack,
@@ -61,28 +63,30 @@
bool MfTouchScreenListener::startListening()
{
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, d->stopListeningSocketFdPair)) {
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, d->communicationSocketFdPair)) {
qCritical("MfTouchScreenListener: Failed to create socket pair");
return false;
}
- d->kernelThread.stopListeningSocketFd = d->stopListeningSocketFdPair[1];
+ d->kernelThread.communicationSocketFd = d->communicationSocketFdPair[1];
+ // Set the stack size quite low to avoid too much memory mappings
+ d->kernelThread.setStackSize(512*1024);
d->kernelThread.start();
return true;
}
bool MfTouchScreenListener::stopListening()
{
- char msg = 1;
+ char msg = MF_KERNEL_THREAD_STOP;
if (!d->kernelThread.isRunning()) {
// Nothing to be done
return true;
}
- // Just send something
- if (write(d->stopListeningSocketFdPair[0], &msg, sizeof(char)) != sizeof(char)) {
+ // Send MF_KERNEL_THREAD_STOP to thread
+ if (write(d->communicationSocketFdPair[0], &msg, sizeof(char)) != sizeof(char)) {
qWarning("MfTouchScreenListener: Failed to send thread stop msg.");
}
@@ -92,16 +96,39 @@
d->kernelThread.wait();
}
- if (close(d->stopListeningSocketFdPair[0]) == -1) {
+ if (close(d->communicationSocketFdPair[0]) == -1) {
qWarning("MfTouchScreenListener: Failed to close stopListening socket");
}
- d->stopListeningSocketFdPair[0] = -1;
+ d->communicationSocketFdPair[0] = -1;
- if (close(d->stopListeningSocketFdPair[1]) == -1) {
+ if (close(d->communicationSocketFdPair[1]) == -1) {
qWarning("MfTouchScreenListener: Failed to close stopListening socket");
}
- d->stopListeningSocketFdPair[1] = -1;
+ d->communicationSocketFdPair[1] = -1;
qDebug("MfTouchScreenListener: Stopped nicely");
return true;
}
+
+bool MfTouchScreenListener::isActive()
+{
+ return d->isActive;
+}
+
+void MfTouchScreenListener::setActive(bool active)
+{
+ if (active != d->isActive) {
+ char msg;
+ if (active) {
+ msg = MF_KERNEL_THREAD_RESUME;
+ } else {
+ msg = MF_KERNEL_THREAD_PAUSE;
+ }
+
+ if (write(d->communicationSocketFdPair[0], &msg, sizeof(char)) != sizeof(char)) {
+ qWarning("MfTouchScreenListener: Failed to send control message to MfKernelThread.");
+ }
+
+ d->isActive = active;
+ }
+}
--- src/mfsource/mftouchscreenlistener_xcore.cpp
+++ src/mfsource/mftouchscreenlistener_xcore.cpp
@@ -45,3 +45,13 @@
d->xcoreThread.start();
return true;
}
+
+bool MfTouchScreenListener::isActive()
+{
+ return true;
+}
+
+void MfTouchScreenListener::setActive(bool active)
+{
+ Q_UNUSED(active);
+}
--- src/mfsource/mftouchscreenlistener_xrecord.cpp
+++ src/mfsource/mftouchscreenlistener_xrecord.cpp
@@ -201,3 +201,12 @@
return NULL;
}
+bool MfTouchScreenListener::isActive()
+{
+ return true;
+}
+
+void MfTouchScreenListener::setActive(bool active)
+{
+ Q_UNUSED(active);
+}
--- src/mfsource/mfxlistener.cpp
+++ src/mfsource/mfxlistener.cpp
@@ -24,8 +24,8 @@
#include <QDebug>
-MfXListener::MfXListener(QObject *parent)
- : QThread(parent)
+MfXListener::MfXListener(MfReactionMapStack *reactionMapStack, QObject *parent)
+ : QThread(parent), reactionMapStack(reactionMapStack)
{
qRegisterMetaType< QList<quint32> >("QList<quint32>");
}
@@ -94,7 +94,8 @@
int ret = 0;
// MfXListenerPriv object belongs to the listener thread
- d = new MfXListenerPriv();
+ d = new MfXListenerPriv(reactionMapStack);
+
ok = QObject::connect(d, SIGNAL(windowStackChanged(QList<quint32>)),
this, SIGNAL(windowStackChanged(QList<quint32>)));
if (!ok) {
--- src/mfsource/mfxlistener.h
+++ src/mfsource/mfxlistener.h
@@ -25,6 +25,7 @@
#include <QMetaType>
class MfXListenerPriv;
+class MfReactionMapStack;
/*!
* Listens for X events in a separate thread, emitting signals when
@@ -36,7 +37,7 @@
class MfXListener : public QThread {
Q_OBJECT
public:
- MfXListener(QObject *parent = 0);
+ MfXListener(MfReactionMapStack *reactionMapStack, QObject *parent = 0);
virtual ~MfXListener();
// Start listening for X events.
@@ -64,6 +65,8 @@
// 0 - Used on main thread side
// 1 - Used on listener thread side
int stopListeningSocketFdPair[2];
+
+ MfReactionMapStack *reactionMapStack;
};
#endif
--- src/mfsource/mfxlistener_p.cpp
+++ src/mfsource/mfxlistener_p.cpp
@@ -15,33 +15,83 @@
*/
#include "mfxlistener_p.h"
+#include "mfreactionmapstack.h"
#include <X11/Xatom.h>
-
+#include <X11/Xproto.h>
#include <QDebug>
-MfXListenerPriv::MfXListenerPriv()
+static int (*xDefaultErrorHandler)(Display *, XErrorEvent *) = NULL;
+
+MfXListenerPriv::MfXListenerPriv(MfReactionMapStack *reactionMapStack)
: display(NULL),
netClientListStackingAtom(None),
- stackedWindows(NULL),
- stackedWindowsSize(0)
+ reactionMapStack(reactionMapStack)
{
}
MfXListenerPriv::~MfXListenerPriv()
{
- if (stackedWindows != NULL) {
- XFree(stackedWindows);
- stackedWindows = NULL;
- stackedWindowsSize = 0;
- }
-
if (display) {
XCloseDisplay(display);
display = NULL;
}
}
+bool MfXListenerPriv::isWindowIgnored(quint32 windowId)
+{
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long bytesAfterReturn;
+ int status;
+ Atom *windowTypeData = NULL;
+ bool retVal = false;
+
+ status = XGetWindowProperty(
+ display,
+ windowId,
+ netWindowTypeAtom,
+ 0, // long_offset
+ (~0L), // long_length
+ False, // delete
+ XA_ATOM, // required type
+ &actual_type,
+ &actual_format,
+ &nitems,
+ &bytesAfterReturn,
+ (unsigned char**)&windowTypeData);
+
+ if (status != Success) {
+ nitems = 0;
+
+ // Window must be ignored since it no longer exists
+ retVal = true;
+ }
+
+ if (bytesAfterReturn != 0) {
+ // Maybe not be so lazy and just read those missing bytes.
+ qCritical() << "MfXListener: Unexpected behaviour:" << bytesAfterReturn
+ << "bytes still unread after return.\n";
+ nitems = 0;
+ }
+
+ // Ignore window if it is of type _NET_WM_WINDOW_TYPE_NOTIFICATION
+ for (unsigned int i = 0; i < nitems; ++i) {
+ if (windowTypeData[i] == netWindowTypeNotificationAtom) {
+ retVal = true;
+ break;
+ }
+ }
+
+ if (windowTypeData) {
+ XFree(windowTypeData);
+ windowTypeData = NULL;
+ }
+
+ return retVal;
+}
+
bool MfXListenerPriv::checkNetClientListStackingProperty()
{
Atom actual_type;
@@ -50,7 +100,7 @@
unsigned long bytesAfterReturn;
Window *stackedWindowsReturned = NULL;
int status;
- bool stackedWindowsChanged = false;
+ QList<quint32> stackedWindowsNew;
status = XGetWindowProperty(
display,
@@ -80,52 +130,66 @@
if (bytesAfterReturn != 0) {
// Maybe not be so lazy and just read those missing bytes.
- fprintf(stderr, "Unexpected behaviour: %lu bytes still unread after return.\n",
- bytesAfterReturn);
+ qCritical() << "MfXListener: Unexpected behaviour:" << bytesAfterReturn
+ << "bytes still unread after return.\n";
goto ERROR;
}
- if (nitems == stackedWindowsSize) {
- if (nitems > 0 &&
- memcmp(stackedWindowsReturned, stackedWindows, sizeof(Window)*nitems) != 0) {
-
- stackedWindowsChanged = true;
+ for (unsigned int i = nitems; i > 0; --i) {
+ // Skip windows with certain type
+ if (isWindowIgnored(stackedWindowsReturned[i-1]) == false) {
+ // Add window to the beginning of stack
+ stackedWindowsNew.prepend(stackedWindowsReturned[i-1]);
+
+ // Stop adding windows when first window without reaction map
+ // is encountered. The list ends with first window without
+ // associated reaction map.
+ if (reactionMapStack->hasWindowReactionMap(stackedWindowsReturned[i-1]) == false) {
+ break;
+ }
}
- } else {
- stackedWindowsChanged = true;
}
- // Free our current stackedWindows
- if (stackedWindows) {
- XFree(stackedWindows);
- stackedWindows = NULL;
- stackedWindowsSize = 0;
+ // Notify about changed stacking order
+ if (stackedWindowsNew != stackedWindows) {
+ stackedWindows = stackedWindowsNew;
+ emit windowStackChanged(stackedWindows);
}
- // Update it
- stackedWindows = stackedWindowsReturned;
- stackedWindowsSize = nitems;
-
- if (stackedWindowsChanged) {
- QList<quint32> windowList;
- for (unsigned long i = 0; i < stackedWindowsSize; i++) {
- windowList.append(stackedWindows[i]);
- }
- emit windowStackChanged(windowList);
+ // Free returned data
+ if (stackedWindowsReturned) {
+ XFree(stackedWindowsReturned);
+ stackedWindowsReturned = NULL;
}
return true;
+
ERROR:
if (stackedWindowsReturned) {
XFree(stackedWindowsReturned);
+ stackedWindowsReturned = NULL;
}
return false;
}
+int xListenerErrorHandler(Display *display, XErrorEvent *errorEvent)
+{
+ // If error is BadWindow for property request, ignore the error.
+ if (errorEvent->request_code == X_GetProperty &&
+ errorEvent->error_code == BadWindow) {
+ qCritical("MfXListener: X window 0x%08x no longer existed when asking properties", (quint32)errorEvent->resourceid);
+ return 0;
+ }
+
+ return xDefaultErrorHandler(display, errorEvent);
+}
+
bool MfXListenerPriv::init()
{
int status;
QByteArray displayString;
+ Atom atoms[3];
+ const char *atomNames[3] = { "_NET_CLIENT_LIST_STACKING", "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_NOTIFICATION" };
// Try to get the DISPLAY environment variable. If it is not
// defined, default to :0 and try to open that.
@@ -134,6 +198,8 @@
displayString = ":0";
}
+ xDefaultErrorHandler = XSetErrorHandler(xListenerErrorHandler);
+
display = XOpenDisplay(displayString.constData());
if (!display) {
@@ -143,12 +209,16 @@
rootWindow = DefaultRootWindow(display);
- netClientListStackingAtom = XInternAtom(display, "_NET_CLIENT_LIST_STACKING", False);
- if (netClientListStackingAtom == None) {
- qCritical("Failed to intern atom _NET_CLIENT_LIST_STACKING.");
+ status = XInternAtoms(display, (char**)atomNames, 3, False, atoms);
+ if (!status) {
+ qCritical("Failed to intern atoms.");
return false;
}
+ netClientListStackingAtom = atoms[0];
+ netWindowTypeAtom = atoms[1];
+ netWindowTypeNotificationAtom = atoms[2];
+
status = XSelectInput(display, rootWindow, PropertyChangeMask);
if (status == BadWindow) {
return false;
--- src/mfsource/mfxlistener_p.h
+++ src/mfsource/mfxlistener_p.h
@@ -22,25 +22,31 @@
#include <QDataStream>
#include <QTextStream>
#include <QMetaType>
+#include <QList>
#include <X11/Xlib.h>
+class MfReactionMapStack;
+
class MfXListenerPriv : public QObject {
Q_OBJECT
public:
- MfXListenerPriv();
+ MfXListenerPriv(MfReactionMapStack *reactionMapStack);
~MfXListenerPriv();
bool init();
void processXEvents();
bool checkNetClientListStackingProperty();
+ bool isWindowIgnored(quint32 windowId);
Display* display;
Window rootWindow;
Atom netClientListStackingAtom;
+ Atom netWindowTypeAtom;
+ Atom netWindowTypeNotificationAtom;
- Window *stackedWindows;
- unsigned long stackedWindowsSize;
+ QList<quint32> stackedWindows;
+ MfReactionMapStack *reactionMapStack;
signals:
void windowStackChanged(QList<quint32> newWindowStack);
--- tests/ft_clientqtapp/main.cpp
+++ tests/ft_clientqtapp/main.cpp
@@ -25,15 +25,10 @@
int main (int argc, char **argv)
{
- if (argc != 2) {
- qDebug() << "Missing application name parameter";
- return 1;
- }
-
QApplication app(argc, argv);
- QPushButton mainWindow(argv[1]);
+ QPushButton mainWindow("Test button");
mainWindow.setWindowFlags(Qt::FramelessWindowHint);
- MReactionMap reactionMap(&mainWindow, argv[1]);
+ MReactionMap reactionMap(&mainWindow);
paintReaction(&mainWindow);
--- tests/ft_mfxlistener/ft_mfxlistener.pro
+++ tests/ft_mfxlistener/ft_mfxlistener.pro
@@ -1,20 +1,37 @@
TARGET = ft_mfxlistener
-INCLUDEPATH += ../../src/mfsource
-CONFIG += x11
+INCLUDEPATH += ../../src/mfsource ../../src/common
+CONFIG += x11 link_pkgconfig
+PKGCONFIG += xorg-evdev
QMAKE_CXXFLAGS += -fno-strict-aliasing
SOURCES += \
main.cpp \
logger.cpp \
+ mfutil_mock.cpp \
../../src/mfsource/mfxlistener.cpp \
../../src/mfsource/mfxlistener_p.cpp \
+ ../../src/mfsource/mfreactionmapstack.cpp \
+ ../../src/mfsource/mfreactionmap.cpp \
+ ../../src/mfsource/mfxcalib.cpp \
+ ../../src/common/mfsettings.cpp
HEADERS += \
logger.h \
+ mfutil.h \
+ mfutil_mock.h \
+ mffeedback.h \
+ mffeedback_mock.h \
+ mfsession.h \
+ mfsession_mock.h \
../../src/mfsource/mfxlistener.h \
../../src/mfsource/mfxlistener_p.h \
+ ../../src/mfsource/mfreactionmapstack.h \
+ ../../src/mfsource/mfreactionmap.h \
+ ../../src/mfsource/mfxcalib.h \
+ ../../src/common/mfcommondata.h \
+ ../../src/common/mfsettings.h
target.path = $$[QT_INSTALL_LIBS]/libmeegoreactionmap-tests
INSTALLS += target
--- tests/ft_mfxlistener/main.cpp
+++ tests/ft_mfxlistener/main.cpp
@@ -28,7 +28,7 @@
{
QCoreApplication app(argc, argv);
Logger logger;
- MfXListener xListener;
+ MfXListener xListener(NULL);
bool ok;
bool nonstop = false;
--- tests/ft_mfxlistener/mffeedback.h
+++ tests/ft_mfxlistener/mffeedback.h
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef MFFEEDBACK_H
+#define MFFEEDBACK_H
+
+#include "mffeedback_mock.h"
+
+#endif
--- tests/ft_mfxlistener/mffeedback_mock.h
+++ tests/ft_mfxlistener/mffeedback_mock.h
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef MFFEEDBACK_MOCK_H
+#define MFFEEDBACK_MOCK_H
+
+#include <QObject>
+#include <QString>
+
+class MfFeedback : public QObject {
+ Q_OBJECT
+
+public:
+ MfFeedback(const QString &name) : QObject(0) { Q_UNUSED(name); }
+ virtual ~MfFeedback() {}
+
+ QString name() const {return QString();}
+
+ bool operator== (const MfFeedback &other) const { Q_UNUSED(other); return true;}
+
+ void emitPlay(qint64 timestamp) { Q_UNUSED(timestamp); }
+
+private slots:
+ void play(qint64 timestamp) { Q_UNUSED(timestamp); }
+
+};
+
+#endif
--- tests/ft_mfxlistener/mfsession.h
+++ tests/ft_mfxlistener/mfsession.h
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef MFSESSION_H
+#define MFSESSION_H
+
+#include "mfsession_mock.h"
+
+#endif
--- tests/ft_mfxlistener/mfsession_mock.h
+++ tests/ft_mfxlistener/mfsession_mock.h
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef MFSESSION_MOCK_H
+#define MFSESSION_MOCK_H
+
+#include <QObject>
+#include <QString>
+#include <QHash>
+
+class MfFeedback;
+
+class MfSession : public QObject
+{
+ Q_OBJECT
+public:
+ MfSession(const QString &applicationName, QObject *parent = 0)
+ : QObject(parent), _applicationName(applicationName) {}
+
+ virtual ~MfSession() {}
+
+ QHash<QString, MfFeedback*> feedbackHash;
+
+ const QString &applicationName() {return _applicationName;}
+private:
+ QString _applicationName;
+};
+
+#endif
--- tests/ft_mfxlistener/mfutil.h
+++ tests/ft_mfxlistener/mfutil.h
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef MFUTIL_H
+#define MFUTIL_H
+
+#include "mfutil_mock.h"
+
+#endif
--- tests/ft_mfxlistener/mfutil_mock.cpp
+++ tests/ft_mfxlistener/mfutil_mock.cpp
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#include "mfutil_mock.h"
+
+QString mfTempDir()
+{
+ return QString();
+}
+
+qint64 getTimestamp()
+{
+ return 0;
+}
+
--- tests/ft_mfxlistener/mfutil_mock.h
+++ tests/ft_mfxlistener/mfutil_mock.h
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef MFUTILMOCK_H
+#define MFUTILMOCK_H
+
+#include <QString>
+
+QString mfTempDir();
+
+qint64 getTimestamp();
+
+#endif
--- tests/ft_multipleviewqtapp
+++ tests/ft_multipleviewqtapp
+(directory)
--- tests/ft_multipleviewqtapp/ft_multipleviewqtapp.pro
+++ tests/ft_multipleviewqtapp/ft_multipleviewqtapp.pro
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+
+INCLUDEPATH += ../../src/client
+LIBS += ../../libmeegoreactionmap.so
+
+# Input
+SOURCES += main.cpp testapplication.cpp
+HEADERS += testapplication.h
+
+QMAKE_EXTRA_TARGETS += check
+check.depends = $$TARGET
+check.commands = $$system(true)
+
+QMAKE_EXTRA_TARGETS += check-xml
+check-xml.depends = $$TARGET
+check-xml.commands = $$system(true)
--- tests/ft_multipleviewqtapp/main.cpp
+++ tests/ft_multipleviewqtapp/main.cpp
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#include "testapplication.h"
+
+int main(int argc, char *argv[])
+{
+ TestApplication app(argc, argv);
+ return app.exec();
+}
--- tests/ft_multipleviewqtapp/testapplication.cpp
+++ tests/ft_multipleviewqtapp/testapplication.cpp
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#include "testapplication.h"
+
+#include <QDebug>
+#include <QTimer>
+
+TestApplication::~TestApplication()
+{
+ delete mainWindow;
+ mainWindow = NULL;
+
+ delete reactionMap;
+ reactionMap = NULL;
+}
+
+void TestApplication::drawReactionMap()
+{
+ MReactionMap *mapmap = MReactionMap::instance(view1);
+
+ mapmap->clear();
+ mapmap->setReactiveDrawingValue();
+ mapmap->fillItemBoundRect(bigRect);
+ mapmap->fillItemBoundRect(smallRect);
+}
+
+TestApplication::TestApplication(int argc, char **argv)
+ : QApplication(argc, argv)
+{
+ Q_UNUSED(argc);
+ Q_UNUSED(argv);
+
+ mainWindow = new QWidget();
+ view1 = new QGraphicsView();
+ view2 = new QGraphicsView();
+ bigRect = new QGraphicsRectItem(0, 0, 100, 100);
+ smallRect = new QGraphicsRectItem(0, 0, 50, 50);
+ screenRect = new QGraphicsRectItem(0, 0, 1000, 1000);
+ layout = new QGridLayout();
+ scene = new QGraphicsScene();
+
+ reactionMap = new MReactionMap(mainWindow);
+
+ // Put bigger rectangle in place
+ bigRect->setPos(10, 50);
+ scene->addItem(bigRect);
+
+ // Put smaller rectangle in place
+ smallRect->setPos(900, 900);
+ scene->addItem(smallRect);
+ scene->addItem(screenRect);
+
+ view1->setScene(scene);
+ view1->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+
+ // Zoom in the other view a bit
+ view2->setScene(scene);
+ view2->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ view2->scale(1.5, 1.5);
+
+ // Add views to the layout
+ layout->addWidget(view1, 0, 0);
+ layout->addWidget(view2, 0, 1);
+
+ mainWindow->setLayout(layout);
+ mainWindow->show();
+
+ // Redraw reaction map on slider value changes
+ connect(view1->verticalScrollBar(), SIGNAL(valueChanged(int)), SLOT(drawReactionMap()));
+ connect(view1->horizontalScrollBar(), SIGNAL(valueChanged(int)), SLOT(drawReactionMap()));
+ connect(view2->verticalScrollBar(), SIGNAL(valueChanged(int)), SLOT(drawReactionMap()));
+ connect(view2->horizontalScrollBar(), SIGNAL(valueChanged(int)), SLOT(drawReactionMap()));
+
+ // Move views to suitable places
+ view1->verticalScrollBar()->setSliderPosition(0);
+ view1->horizontalScrollBar()->setSliderPosition(0);
+ view2->verticalScrollBar()->setSliderPosition(0);
+ view2->horizontalScrollBar()->setSliderPosition(110);
+
+ // Draw initial reaction map after everything has appeared
+ QTimer::singleShot(100, this, SLOT(drawReactionMap()));
+}
+
--- tests/ft_multipleviewqtapp/testapplication.h
+++ tests/ft_multipleviewqtapp/testapplication.h
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef TESTAPPLICATION_H
+#define TESTAPPLICATION_H
+
+#include <QApplication>
+#include <QGridLayout>
+#include <QGraphicsView>
+#include <QGraphicsScene>
+#include <QGraphicsRectItem>
+#include <QWidget>
+#include <QScrollBar>
+#include <QObject>
+#include <mreactionmap.h>
+#include <stdio.h>
+
+class TestApplication : public QApplication
+{
+ Q_OBJECT
+
+public:
+ TestApplication(int argc, char **argv);
+ virtual ~TestApplication();
+
+public slots:
+ void drawReactionMap();
+
+private:
+ QGraphicsView *view1, *view2;
+ QGraphicsScene *scene;
+ QGraphicsRectItem *bigRect;
+ QGraphicsRectItem *smallRect;
+ QGraphicsRectItem *screenRect;
+ QWidget *mainWindow;
+ QGridLayout *layout;
+ MReactionMap *reactionMap;
+};
+
+#endif
+
--- tests/ft_touchscreenmanaging
+++ tests/ft_touchscreenmanaging
+(directory)
--- tests/ft_touchscreenmanaging/ft_touchscreenmanaging.pro
+++ tests/ft_touchscreenmanaging/ft_touchscreenmanaging.pro
+include(../common_top.pri)
+
+TEMPLATE = app
+CONFIG += console meegofeedback link_pkgconfig
+QT += network
+PKGCONFIG += xorg-evdev
+TARGET = ft_touchscreenmanaging
+INCLUDEPATH += ../../src/mfsource ../../src/common
+SRCDIR = ../../src
+
+SOURCES += \
+ main.cpp \
+ mftouchscreenlistener_mock.cpp \
+ mfxlistener_mock.cpp \
+ mfserver_mock.cpp \
+ $$SRCDIR/mfsource/mfreactorsource.cpp \
+ $$SRCDIR/mfsource/mfreactionmap.cpp \
+ $$SRCDIR/mfsource/mfreactionmapstack.cpp \
+ $$SRCDIR/mfsource/mfxcalib.cpp \
+ $$SRCDIR/common/mfsettings.cpp
+
+HEADERS += \
+ mftouchscreenlistener_mock.h \
+ mfxlistener_mock.h \
+ mfserver_mock.h \
+ $$SRCDIR/mfsource/mftouchscreenlistener.h \
+ $$SRCDIR/mfsource/mfreactorsource.h \
+ $$SRCDIR/mfsource/mfreactionmap.h \
+ $$SRCDIR/mfsource/mfreactionmapstack.h \
+ $$SRCDIR/mfsource/mfserver.h \
+ $$SRCDIR/mfsource/mfxcalib.h \
+ $$SRCDIR/mfsource/mfxlistener.h \
+ $$SRCDIR/common/mfsettings.h
+
+target.path = $$[QT_INSTALL_LIBS]/libmeegoreactionmap-tests
+INSTALLS += target
+
+include(../common_bot.pri)
--- tests/ft_touchscreenmanaging/main.cpp
+++ tests/ft_touchscreenmanaging/main.cpp
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#include <QCoreApplication>
+#include <QDebug>
+#include <mfreactorsource.h>
+
+#include "mftouchscreenlistener_mock.h"
+#include "mfxlistener_mock.h"
+#include "mfserver_mock.h"
+
+bool verifyStatuses(MfReactorSource *src, bool reactionMapActive,
+ bool touchScreenListenerActive,
+ int touchScreenListenerSetActiveCalled)
+{
+ bool retVal = true;
+
+ if (!src) {
+ qCritical() << "verifyStatuses: NULL MfReactorSource provided!";
+ return false;
+ }
+
+ if (src->isActive() != reactionMapActive) {
+ qCritical() << "verifyStatuses: MfReactorSource::isActive:" << src->isActive()
+ << "Expected:" << reactionMapActive;
+ retVal = false;
+ }
+
+ if (isTouchScreenListenerActive != touchScreenListenerActive) {
+ qCritical() << "verifyStatuses: isTouchScreenListenerActive:" << isTouchScreenListenerActive
+ << "Expected:" << touchScreenListenerActive;
+ retVal = false;
+ }
+
+ if (touchScreenListenerSetActiveCallCount != touchScreenListenerSetActiveCalled) {
+ qCritical() << "verifyStatuses: touchScreenListenerSetActiveCallCount:" << touchScreenListenerSetActiveCallCount
+ << "Expected:" << touchScreenListenerSetActiveCalled;
+ retVal = false;
+ }
+
+ return retVal;
+}
+
+int main(int argc, char **argv)
+{
+ QCoreApplication fooApp(argc, argv);
+ QList<quint32> windowList;
+ QMap<QString, QString> deviceState;
+
+ // Create a window list, top to bottom: 3, 2, 1, 0
+ windowList << 0; // Does not have a reaction map
+ windowList << 1; // Does have a reaction map
+ windowList << 2; // Does have a reaction map
+ windowList << 3; // Does not have a reaction map
+
+ MfReactorSource *src = new MfReactorSource();
+
+ src->init();
+
+ // Report initial window stacking to MfReactionMapStack
+ touchScreenListenerSetActiveCallCount = 0;
+ stackEmitter.emitWindowStackChanged(windowList);
+ fooApp.processEvents();
+
+ // After initalization MfReactorSource should be inactive,
+ // MfTouchScreenListener should be inactive and
+ // MfTouchScreenListener::setActive()
+ // should not have been called
+ if (!verifyStatuses(src, false, false, 0)) {
+ qFatal("Test FAILED.");
+ }
+
+ // Go through all possible states
+ // 1. Reaction map on top and display is off
+ touchScreenListenerSetActiveCallCount = 0;
+ // Rearrange windows so that reactive is on top
+ windowList.move(2, 3); // 2, 3, 1, 0
+ stackEmitter.emitWindowStackChanged(windowList);
+ fooApp.processEvents();
+ // Notify display is "off"
+ deviceState["display"] = "off";
+ src->deviceStateChanged(deviceState);
+ fooApp.processEvents();
+ if (!verifyStatuses(src, false, false, 2)) {
+ qFatal("Test FAILED.");
+ }
+
+ // 2. Reaction map on top and display is on
+ touchScreenListenerSetActiveCallCount = 0;
+ // Notify display is "on"
+ deviceState["display"] = "on";
+ src->deviceStateChanged(deviceState);
+ fooApp.processEvents();
+ if (!verifyStatuses(src, true, true, 1)) {
+ qFatal("Test FAILED.");
+ }
+
+ // 3. Reaction map not on top and display is off
+ touchScreenListenerSetActiveCallCount = 0;
+ // Notify display is "off"
+ deviceState["display"] = "off";
+ src->deviceStateChanged(deviceState);
+ // Rearrange windows so that reactive is not on top
+ windowList.move(2, 3); // 3, 2, 1, 0
+ stackEmitter.emitWindowStackChanged(windowList);
+ fooApp.processEvents();
+ if (!verifyStatuses(src, false, false, 1)) {
+ qFatal("Test FAILED.");
+ }
+
+ // 4. Reaction map not on top and display is on
+ touchScreenListenerSetActiveCallCount = 0;
+ // Notify display is "off"
+ deviceState["display"] = "on";
+ src->deviceStateChanged(deviceState);
+ fooApp.processEvents();
+ if (!verifyStatuses(src, false, false, 0)) {
+ qFatal("Test FAILED.");
+ }
+
+ delete src;
+
+ qCritical() << "Test SUCCESSFUL";
+
+ return 0;
+}
+
--- tests/ft_touchscreenmanaging/mfserver_mock.cpp
+++ tests/ft_touchscreenmanaging/mfserver_mock.cpp
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#include "mfserver_mock.h"
+#include <mfserver.h>
+#include <mfreactionmapstack.h>
+#include <mfreactionmap.h>
+
+#include <QDebug>
+
+MfServer::MfServer(MfReactionMapStack *stack, QObject *parent)
+ : QObject(parent), stack(stack)
+{
+}
+
+bool MfServer::init()
+{
+ MfReactionMap *map;
+
+ // Create two reaction maps with window id's 1 and 2 and
+ // add them to the reactionmap stack.
+ map = new MfReactionMap(NULL, 1, 1, this);
+ stack->add(map);
+
+ map = new MfReactionMap(NULL, 2, 2, this);
+ stack->add(map);
+
+ return true;
+}
+
+void MfServer::removePreExistingSharedMemory()
+{
+}
+
+void MfServer::onNewConnection()
+{
+}
--- tests/ft_touchscreenmanaging/mfserver_mock.h
+++ tests/ft_touchscreenmanaging/mfserver_mock.h
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef MFSERVERMOCK_H
+#define MFSERVERMOCK_H
+
+#endif
--- tests/ft_touchscreenmanaging/mftouchscreenlistener_mock.cpp
+++ tests/ft_touchscreenmanaging/mftouchscreenlistener_mock.cpp
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#include "mftouchscreenlistener_mock.h"
+#include <mftouchscreenlistener.h>
+
+bool isTouchScreenListenerActive = true;
+int touchScreenListenerSetActiveCallCount = 0;
+
+MfTouchScreenListener::MfTouchScreenListener(MfReactionMapStack *reactionMapStack,
+ QObject *parent)
+ : QObject(parent)
+{
+ Q_UNUSED(reactionMapStack);
+}
+
+MfTouchScreenListener::~MfTouchScreenListener()
+{
+}
+
+bool MfTouchScreenListener::startListening()
+{
+ return true;
+}
+
+bool MfTouchScreenListener::stopListening()
+{
+ return true;
+}
+
+bool MfTouchScreenListener::isActive()
+{
+ return isTouchScreenListenerActive;
+}
+
+void MfTouchScreenListener::setActive(bool active)
+{
+ isTouchScreenListenerActive = active;
+ touchScreenListenerSetActiveCallCount++;
+}
--- tests/ft_touchscreenmanaging/mftouchscreenlistener_mock.h
+++ tests/ft_touchscreenmanaging/mftouchscreenlistener_mock.h
+/* This file is part of meegofeedbackd
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef MFTOUCHSCREENLISTENERMOCK_H
+#define MFTOUCHSCREENLISTENERMOCK_H
+
+extern bool isTouchScreenListenerActive;
+extern int touchScreenListenerSetActiveCallCount;
+
+#endif
--- tests/ft_touchscreenmanaging/mfxlistener_mock.cpp
+++ tests/ft_touchscreenmanaging/mfxlistener_mock.cpp
+/* This file is part of meegofeedback-reactionmaps
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#include "mfxlistener_mock.h"
+#include <mfxlistener.h>
+#include <QDebug>
+
+MfXListenerMock stackEmitter(NULL);
+
+void MfXListenerMock::emitWindowStackChanged(QList<quint32> newWindowStack)
+{
+ emit windowStackChanged(newWindowStack);
+}
+
+MfXListener::MfXListener(MfReactionMapStack *reactionMapStack, QObject *parent)
+ : QThread(parent)
+{
+ Q_UNUSED(reactionMapStack);
+}
+
+MfXListener::~MfXListener()
+{
+ stopListening();
+}
+
+bool MfXListener::startListening()
+{
+ bool ok;
+ ok = connect(&stackEmitter, SIGNAL(windowStackChanged(QList<quint32>)),
+ SIGNAL(windowStackChanged(QList<quint32>)));
+ if (!ok) {
+ qCritical("Failed to connect MfXListener signal");
+ }
+
+ start(QThread::NormalPriority);
+
+ return true;
+}
+
+bool MfXListener::stopListening()
+{
+ if (!isRunning()) {
+ // Nothing to be done
+ return true;
+ }
+
+ exit();
+
+ if (!wait(500)) {
+ // Ok, let's use brute force
+ qCritical() << "Terminating by force";
+ terminate();
+ wait();
+ }
+
+ return true;
+}
+
+void MfXListener::run()
+{
+ exec();
+}
--- tests/ft_touchscreenmanaging/mfxlistener_mock.h
+++ tests/ft_touchscreenmanaging/mfxlistener_mock.h
+/* This file is part of meegofeedbackd
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef MFXLISTENERMOCK_H
+#define MFXLISTENERMOCK_H
+
+#include <QObject>
+#include <QList>
+
+class MfReactionMapStack;
+
+class MfXListenerMock : public QObject
+{
+ Q_OBJECT
+
+public:
+ MfXListenerMock(MfReactionMapStack *reactionMapStack, QObject *parent = 0) : QObject(parent) { Q_UNUSED(reactionMapStack); };
+ virtual ~MfXListenerMock() {};
+
+signals:
+ void windowStackChanged(QList<quint32> newWindowStack);
+
+public slots:
+ void emitWindowStackChanged(QList<quint32> newWindowStack);
+};
+
+extern MfXListenerMock stackEmitter;
+
+#endif
--- tests/tests.pro
+++ tests/tests.pro
@@ -10,7 +10,9 @@
ut_mreactionmap \
ft_clientqtapp \
ft_mfxlistener \
- ft_multiplemainwindowqtapp
+ ft_multiplemainwindowqtapp \
+ ft_touchscreenmanaging \
+ ft_multipleviewqtapp
QMAKE_STRIP = echo
include(shell.pri)
--- tests/tests.xml
+++ tests/tests.xml
@@ -31,6 +31,9 @@
<case name="ft_mfxlistener" description="ft_mfxlistener" requirement="" timeout="60">
<step expected_result="0">/usr/lib/libmeegoreactionmap-tests/ft_mfxlistener</step>
</case>
+ <case name="ft_touchscreenmanaging" description="ft_touchscreenmanaging" requirement="" timeout="60">
+ <step expected_result="0">/usr/lib/libmeegoreactionmap-tests/ft_touchscreenmanaging</step>
+ </case>
<environments>
<scratchbox>false</scratchbox>
--- tests/ut_mreactionmap/mreactionmapconnection_mock.cpp
+++ tests/ut_mreactionmap/mreactionmapconnection_mock.cpp
@@ -93,7 +93,7 @@
}
sharedMemoryAddress = shmat(sharedMemoryId, 0, 0);
- if ((int)sharedMemoryAddress == -1) {
+ if ((qptrdiff)sharedMemoryAddress == -1) {
qCritical() << "MReactionMapConnection: Unable to get shared memory address for"
<< shmPath;
return false;
--- tools/meegoreactionmap-viewer/mreactionmapviewer.cpp
+++ tools/meegoreactionmap-viewer/mreactionmapviewer.cpp
@@ -211,7 +211,7 @@
sharedMemoryAddress = shmat(id, 0, 0);
- if ((int)sharedMemoryAddress == -1) {
+ if ((qptrdiff)sharedMemoryAddress == -1) {
qCritical() << "Unable to get shared memory address for"
<< tempFilePath;
sharedMemoryAddress = 0;
++++++ meegotouch-feedbackreactionmaps.yaml
--- meegotouch-feedbackreactionmaps.yaml
+++ meegotouch-feedbackreactionmaps.yaml
@@ -1,6 +1,6 @@
Name: meegotouch-feedbackreactionmaps
Summary: MeeGo Touch Feedback ReactionMaps Plugin
-Version: 0.14.0.5
+Version: 0.14.1.3
Release: 1
Group: System/Libraries
License: LGPLv2.1
More information about the MeeGo-commits
mailing list