aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarja Hassinen <ext-marja.2.hassinen@nokia.com>2009-10-27 15:30:58 +0200
committerMarja Hassinen <ext-marja.2.hassinen@nokia.com>2009-10-27 15:30:58 +0200
commit0d10978ef7662ad8ee44ad03ad880f41eba89083 (patch)
treecfec371a5f8917bafa05ce7cac5d69634edb1dcc
parent79dcc67663fca09c7bcb919db94536e685ce8f61 (diff)
parent67b7dd1ab469691d12887c64c6af8996de99475a (diff)
Merge branch 'master' into protocol_chge_provider
-rw-r--r--.gitignore2
-rw-r--r--HACKING19
-rw-r--r--Makefile.am2
-rw-r--r--am/tests.am4
-rw-r--r--configure.ac21
-rw-r--r--debian/changelog22
-rw-r--r--doc/context-arch.txt2
-rw-r--r--doc/demos.txt57
-rw-r--r--gtk-doc.make201
-rw-r--r--libcontextprovider/context-provide/Makefile.am17
-rw-r--r--libcontextprovider/context-provide/commandwatcher.cpp112
-rw-r--r--libcontextprovider/context-provide/commandwatcher.h23
-rw-r--r--libcontextprovider/context-provide/context-provide.cpp10
-rw-r--r--libcontextprovider/context-provide/propertyproxy.cpp49
-rw-r--r--libcontextprovider/context-provide/propertyproxy.h45
-rw-r--r--libcontextprovider/customer-tests/subscription/Makefile.am7
-rw-r--r--libcontextprovider/customer-tests/types/Makefile.am5
-rw-r--r--libcontextprovider/customer-tests/value-changes/Makefile.am5
-rw-r--r--libcontextprovider/doc/Makefile.am4
-rw-r--r--libcontextprovider/man/context-provide-v2.125
-rw-r--r--libcontextprovider/src/Makefile.am4
-rw-r--r--libcontextsubscriber/.gitignore1
-rw-r--r--libcontextsubscriber/Makefile.am2
-rw-r--r--libcontextsubscriber/cli/Makefile.am7
-rw-r--r--libcontextsubscriber/cls/Makefile.am8
-rwxr-xr-xlibcontextsubscriber/customer-tests/asynchronicity/rapidchanges.py4
-rwxr-xr-xlibcontextsubscriber/customer-tests/commander/commander_disabled.py3
-rwxr-xr-xlibcontextsubscriber/customer-tests/registry/registry.py2
-rwxr-xr-xlibcontextsubscriber/customer-tests/subscription/multiprovider.py100
-rwxr-xr-xlibcontextsubscriber/customer-tests/subscription/multiprovider2.py90
-rwxr-xr-xlibcontextsubscriber/customer-tests/subscription/subscription.py1
-rw-r--r--libcontextsubscriber/customer-tests/testplugins/timeplugin1/Makefile.am4
-rw-r--r--libcontextsubscriber/customer-tests/testplugins/timeplugin2/Makefile.am4
-rw-r--r--libcontextsubscriber/customer-tests/tests.xml15
-rw-r--r--libcontextsubscriber/doc/Makefile.am4
-rw-r--r--libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/Makefile.am17
-rw-r--r--libcontextsubscriber/src/Makefile.am6
-rw-r--r--libcontextsubscriber/src/contextkitplugin.cpp141
-rw-r--r--libcontextsubscriber/src/contextkitplugin.h34
-rw-r--r--libcontextsubscriber/src/handlesignalrouter.cpp4
-rw-r--r--libcontextsubscriber/src/handlesignalrouter.h4
-rw-r--r--libcontextsubscriber/src/iproviderplugin.h4
-rw-r--r--libcontextsubscriber/src/propertyhandle.cpp120
-rw-r--r--libcontextsubscriber/src/propertyhandle.h7
-rw-r--r--libcontextsubscriber/src/provider.cpp50
-rw-r--r--libcontextsubscriber/src/provider.h15
-rw-r--r--libcontextsubscriber/src/timedvalue.h53
-rw-r--r--libcontextsubscriber/unit-tests/handlesignalrouter/propertyhandle.h6
-rw-r--r--libcontextsubscriber/unit-tests/handlesignalrouter/testhandlesignalrouter.cpp22
-rw-r--r--libcontextsubscriber/unit-tests/propertyhandle/.gitignore2
-rw-r--r--libcontextsubscriber/unit-tests/propertyhandle/Makefile.am3
-rw-r--r--libcontextsubscriber/unit-tests/propertyhandle/provider.h11
-rw-r--r--libcontextsubscriber/unit-tests/propertyhandle/testpropertyhandle.cpp30
-rw-r--r--libcontextsubscriber/unit-tests/provider/.gitignore1
-rw-r--r--libcontextsubscriber/unit-tests/provider/Makefile.am2
-rw-r--r--libcontextsubscriber/unit-tests/provider/contextkitplugin.h6
-rw-r--r--libcontextsubscriber/unit-tests/provider/handlesignalrouter.h2
-rw-r--r--libcontextsubscriber/unit-tests/provider/testprovider.cpp13
-rw-r--r--libcontextsubscriber/update-contextkit-providers/Makefile.am4
-rw-r--r--m4/dolt.m4177
-rw-r--r--python/ContextKit/cltool.py16
-rwxr-xr-xsandbox/context-proxy112
-rw-r--r--sandbox/messaging-to-self/main.cpp (renamed from libcontextsubscriber/sandbox/messaging-to-self/main.cpp)0
-rw-r--r--sandbox/messaging-to-self/messaging-to-self.pro (renamed from libcontextsubscriber/sandbox/messaging-to-self/messaging-to-self.pro)0
-rw-r--r--sandbox/messaging-to-self/myobject.h (renamed from libcontextsubscriber/sandbox/messaging-to-self/myobject.h)0
-rw-r--r--sandbox/messaging-to-self/mythread.h (renamed from libcontextsubscriber/sandbox/messaging-to-self/mythread.h)0
-rw-r--r--sandbox/messaging-to-self/queuedinvoker.cpp (renamed from libcontextsubscriber/sandbox/messaging-to-self/queuedinvoker.cpp)0
-rw-r--r--sandbox/messaging-to-self/queuedinvoker.h (renamed from libcontextsubscriber/sandbox/messaging-to-self/queuedinvoker.h)0
-rw-r--r--sandbox/multithreading-tests/Makefile.am (renamed from libcontextsubscriber/multithreading-tests/Makefile.am)0
-rw-r--r--sandbox/multithreading-tests/new-property-in-thread/.gitignore (renamed from libcontextsubscriber/multithreading-tests/new-property-in-thread/.gitignore)0
-rw-r--r--sandbox/multithreading-tests/new-property-in-thread/Makefile.am (renamed from libcontextsubscriber/multithreading-tests/new-property-in-thread/Makefile.am)5
-rw-r--r--sandbox/multithreading-tests/new-property-in-thread/main.cpp (renamed from libcontextsubscriber/multithreading-tests/new-property-in-thread/main.cpp)0
-rw-r--r--sandbox/multithreading-tests/new-property-in-thread/thread.h (renamed from libcontextsubscriber/multithreading-tests/new-property-in-thread/thread.h)0
-rw-r--r--sandbox/multithreading-tests/old-property-in-thread/.gitignore (renamed from libcontextsubscriber/multithreading-tests/old-property-in-thread/.gitignore)0
-rw-r--r--sandbox/multithreading-tests/old-property-in-thread/Makefile.am (renamed from libcontextsubscriber/multithreading-tests/stress-test/Makefile.am)5
-rw-r--r--sandbox/multithreading-tests/old-property-in-thread/main.cpp (renamed from libcontextsubscriber/multithreading-tests/old-property-in-thread/main.cpp)0
-rw-r--r--sandbox/multithreading-tests/old-property-in-thread/thread.h (renamed from libcontextsubscriber/multithreading-tests/old-property-in-thread/thread.h)0
-rw-r--r--sandbox/multithreading-tests/single-thread/.gitignore (renamed from libcontextsubscriber/multithreading-tests/single-thread/.gitignore)0
-rw-r--r--sandbox/multithreading-tests/single-thread/Makefile.am (renamed from libcontextsubscriber/multithreading-tests/single-thread/Makefile.am)5
-rw-r--r--sandbox/multithreading-tests/single-thread/listener.h (renamed from libcontextsubscriber/multithreading-tests/single-thread/listener.h)0
-rw-r--r--sandbox/multithreading-tests/single-thread/main.cpp (renamed from libcontextsubscriber/multithreading-tests/single-thread/main.cpp)0
-rw-r--r--sandbox/multithreading-tests/stress-test/.gitignore (renamed from libcontextsubscriber/multithreading-tests/stress-test/.gitignore)0
-rw-r--r--sandbox/multithreading-tests/stress-test/1provider.cdb (renamed from libcontextsubscriber/multithreading-tests/stress-test/1provider.cdb)bin2727 -> 2727 bytes
-rw-r--r--sandbox/multithreading-tests/stress-test/2providers.cdb (renamed from libcontextsubscriber/multithreading-tests/stress-test/2providers.cdb)bin3423 -> 3423 bytes
-rw-r--r--sandbox/multithreading-tests/stress-test/Makefile.am (renamed from libcontextsubscriber/multithreading-tests/old-property-in-thread/Makefile.am)5
-rw-r--r--sandbox/multithreading-tests/stress-test/main.cpp (renamed from libcontextsubscriber/multithreading-tests/stress-test/main.cpp)0
-rwxr-xr-xsandbox/multithreading-tests/stress-test/provider.py (renamed from libcontextsubscriber/multithreading-tests/stress-test/provider.py)0
-rwxr-xr-xsandbox/multithreading-tests/stress-test/runme.sh (renamed from libcontextsubscriber/multithreading-tests/stress-test/runme.sh)0
-rw-r--r--sandbox/multithreading-tests/stress-test/thread.h (renamed from libcontextsubscriber/multithreading-tests/stress-test/thread.h)0
-rw-r--r--sandbox/multithreading-tests/using-backend-from-thread/.gitignore (renamed from libcontextsubscriber/multithreading-tests/using-backend-from-thread/.gitignore)0
-rw-r--r--sandbox/multithreading-tests/using-backend-from-thread/Makefile.am (renamed from libcontextsubscriber/multithreading-tests/using-backend-from-thread/Makefile.am)5
-rw-r--r--sandbox/multithreading-tests/using-backend-from-thread/main.cpp (renamed from libcontextsubscriber/multithreading-tests/using-backend-from-thread/main.cpp)0
-rw-r--r--sandbox/multithreading-tests/using-backend-from-thread/thread.h (renamed from libcontextsubscriber/multithreading-tests/using-backend-from-thread/thread.h)0
-rw-r--r--sandbox/multithreading-tests/wait-for-subscription-only-in-thread/.gitignore (renamed from libcontextsubscriber/multithreading-tests/wait-for-subscription-only-in-thread/.gitignore)0
-rw-r--r--sandbox/multithreading-tests/wait-for-subscription-only-in-thread/Makefile.am (renamed from libcontextsubscriber/multithreading-tests/wait-for-subscription-only-in-thread/Makefile.am)5
-rw-r--r--sandbox/multithreading-tests/wait-for-subscription-only-in-thread/main.cpp (renamed from libcontextsubscriber/multithreading-tests/wait-for-subscription-only-in-thread/main.cpp)0
-rw-r--r--sandbox/multithreading-tests/wait-for-subscription-only-in-thread/thread.h (renamed from libcontextsubscriber/multithreading-tests/wait-for-subscription-only-in-thread/thread.h)0
-rw-r--r--sandbox/multithreading-tests/wait-for-subscription-thread/.gitignore (renamed from libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/.gitignore)0
-rw-r--r--sandbox/multithreading-tests/wait-for-subscription-thread/Makefile.am18
-rw-r--r--sandbox/multithreading-tests/wait-for-subscription-thread/main.cpp (renamed from libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/main.cpp)0
-rw-r--r--sandbox/multithreading-tests/wait-for-subscription-thread/thread.h (renamed from libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/thread.h)0
-rw-r--r--spec/ContextKit.xml41
-rw-r--r--spec/Makefile.am3
-rw-r--r--spec/all.xml1
-rw-r--r--spec/generic-types.xml6
105 files changed, 1313 insertions, 529 deletions
diff --git a/.gitignore b/.gitignore
index a333a903..a7c4bd86 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,5 @@ flexi-properties.xml
mocs.cpp
moc_*
TAGS
+doltcompile
+doltlibtool
diff --git a/HACKING b/HACKING
index f2cae842..87ecc542 100644
--- a/HACKING
+++ b/HACKING
@@ -177,13 +177,17 @@ Here is the general procedure:
$ make maintainer-clean || make distclean
+ If you don't have any new files not commited yet, you can also use:
+
+ $ git clean -dfx
+
- Recreate the build cruft.
$ ./autogen.sh
- Configure your source tree as needed for making a release.
- $ ./configure --enable-maintainer-mode --enable-gtk-doc
+ $ ./configure --enable-doc
- Build the source tree and do a "make distcheck"
@@ -200,13 +204,12 @@ the contents of the created directory.
Building a debian package
-------------------------
-After a git clone, you first have to build vala C sources and
-documentation. If you have extracted a distribution tarball, then you
-already have these files. Otherwise just do a ./configure, let's
-double check that all of the documentation tools and the vala compiler
-is found and make. After that you are ready to run
-'dpkg-buildpackage -us -uc -rfakeroot -b' to get your shiny new debian
-packages.
+After a git clone, you first have to build documentation. If you have
+extracted a distribution tarball, then you already have these files.
+Otherwise just do a ./configure, let's double check that all of the
+documentation tools and the vala compiler is found and make. After
+that you are ready to run 'dpkg-buildpackage -us -uc -rfakeroot -b' to
+get your shiny new debian packages.
Making releases
---------------
diff --git a/Makefile.am b/Makefile.am
index f37e1164..4ed81457 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,7 +12,7 @@ SUBDIRS = \
tools \
common
-DISTCLEANFILES = lcov.info lcov.html
+DISTCLEANFILES = lcov.info lcov.html doltlibtool doltcompile
MAINTAINERCLEANFILES = INSTALL
check-sum:
diff --git a/am/tests.am b/am/tests.am
index 26c3ca26..51aca517 100644
--- a/am/tests.am
+++ b/am/tests.am
@@ -55,9 +55,9 @@ all-am:
$(MAKE) $(AM_MAKEFLAGS) $(check_LIBRARIES) $(check_PROGRAMS); \
fi
-$(top_builddir)/common/libcommon.la:
+$(top_builddir)/common/libcommon.la: FORCE
$(MAKE) -C $(top_builddir)/common libcommon.la
-.PHONY: coverage covdircheck $(top_builddir)/common/libcommon.la
+.PHONY: coverage covdircheck FORCE
include $(top_srcdir)/am/covoptioncheck.am
diff --git a/configure.ac b/configure.ac
index 6a67c160..1f6d090d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ([2.61])
-AC_INIT([ContextKit], [0.3.11~unreleased], [marius.vollmer@nokia.com], ContextKit)
+AC_INIT([ContextKit], [0.4~unreleased], [marius.vollmer@nokia.com], ContextKit)
AC_CONFIG_SRCDIR([Makefile.am])
AM_INIT_AUTOMAKE([-Wall -Werror foreign dist-bzip2 tar-ustar 1.9])
@@ -10,7 +10,8 @@ AC_PROG_CC
CFLAGS="$CXXFLAGS -Wall"
AC_PROG_CXX
CXXFLAGS="$CXXFLAGS -Wall"
-AC_PROG_LIBTOOL
+LT_INIT([disable-static])
+DOLT
AM_PATH_PYTHON
# check for libraries
@@ -30,12 +31,6 @@ AC_SUBST([CDB_LIBS])
# tools for documentation
AX_FEATURE_DISABLEABLE([doc], [BUILD_DOCS], [disable building of documentation])
-AC_MSG_CHECKING([for gtk-doc])
-PKG_CHECK_EXISTS([gtk-doc >= 1.9],[AC_MSG_RESULT([yes])],
- [AC_MSG_RESULT([no])
- missing_deps_BUILD_DOCS="$missing_deps_BUILD_DOCS, gtk-doc >= 1.9"])
-HTML_DIR="${datadir}/gtk-doc/html"
-AC_SUBST([HTML_DIR])
AX_DISABLE_FEATURE_ON_PROG([Dot drawing tool], [BUILD_DOCS], [DOT], [dot])
AX_DISABLE_FEATURE_ON_PROG([Asciidoc], [BUILD_DOCS], [ASCIIDOC], [asciidoc], [8.2.7])
AX_DISABLE_FEATURE_ON_PROG([source-highlight], [BUILD_DOCS], [SOURCE_HIGHLIGHT], [source-highlight])
@@ -43,8 +38,6 @@ AX_DISABLE_FEATURE_ON_PROG([xsltproc], [BUILD_DOCS], [XSLTPROC], [xsltproc])
AX_DISABLE_FEATURE_ON_PROG([xmllint], [BUILD_DOCS], [XMLLINT], [xmllint])
AX_DISABLE_FEATURE_ON_PROG([doxygen], [BUILD_DOCS], [DOXYGEN], [doxygen])
AM_CONDITIONAL([CONTEXTKIT_BUILD_DOCS], [test "$missing_deps_BUILD_DOCS" = ""])
-AM_CONDITIONAL([GTK_DOC_USE_LIBTOOL], [test "$missing_deps_BUILD_DOCS" = ""])
-AM_CONDITIONAL([ENABLE_GTK_DOC], [test "$missing_deps_BUILD_DOCS" = ""])
# coverage tools
AX_FEATURE_DISABLEABLE([coverage], [COVERAGE], [disable unittests' coverage support])
@@ -80,14 +73,6 @@ AC_CONFIG_FILES([
libcontextsubscriber/unit-tests/provider/Makefile
libcontextsubscriber/unit-tests/util/Makefile
libcontextsubscriber/unit-tests/nanoxml/Makefile
- libcontextsubscriber/multithreading-tests/Makefile
- libcontextsubscriber/multithreading-tests/new-property-in-thread/Makefile
- libcontextsubscriber/multithreading-tests/old-property-in-thread/Makefile
- libcontextsubscriber/multithreading-tests/single-thread/Makefile
- libcontextsubscriber/multithreading-tests/stress-test/Makefile
- libcontextsubscriber/multithreading-tests/using-backend-from-thread/Makefile
- libcontextsubscriber/multithreading-tests/wait-for-subscription-only-in-thread/Makefile
- libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/Makefile
libcontextsubscriber/update-contextkit-providers/Makefile
libcontextprovider/contextprovider-1.0.pc
libcontextprovider/Makefile
diff --git a/debian/changelog b/debian/changelog
index 30e76721..1930cedc 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,16 @@
-contextkit (0.3.11~unreleased) unstable; urgency=low
+contextkit (0.4~unreleased) unstable; urgency=low
- *
+ * Subscriber part of libcontextsubscriber now supports multiple
+ providers for one property.
+ * Support both the old and the new ContextKit D-Bus protocol in
+ libcontextsubscriber.
+ * The start command in context-provide is now able to reregister
+ the service name if needed as advertised in the help.
+ * context-provide supports proxying in Commander mode.
- -- Marja Hassinen <ext-marja.2.hassinen@nokia.com> Tue, 15 Oct 2009 16:25:04 +0300
+ Implemented: SWP#CntFr-349, SWP#CntFr-353
+
+ -- Gergely Risko <gergely+context@risko.hu> Thu, 22 Oct 2009 13:42:27 +0300
contextkit (0.3.10) unstable; urgency=low
@@ -10,7 +18,7 @@ contextkit (0.3.10) unstable; urgency=low
providers for one property.
* New tool: context-ls for listing available context properties.
- Implemented: CntFr-324, CntFr-318, CntFr-343
+ Implemented: SWP#CntFr-324, SWP#CntFr-318, SWP#CntFr-343
-- Marja Hassinen <ext-marja.2.hassinen@nokia.com> Tue, 15 Oct 2009 16:25:04 +0300
@@ -20,7 +28,7 @@ contextkit (0.3.9) unstable; urgency=low
* Removed complex types from core.context, since they're not
supported yet.
- Implemented: CntFr-337, CntFr-203
+ Implemented: SWP#CntFr-337, SWP#CntFr-203
-- Marja Hassinen <ext-marja.2.hassinen@nokia.com> Tue, 06 Oct 2009 15:00:00 +0300
@@ -32,7 +40,7 @@ contextkit (0.3.8) unstable; urgency=low
* New package libcontextprovider-tests added, containing customer tests
of the libcontextprovider.
- Implemented: CntFr-323
+ Implemented: SWP#CntFr-323
-- Gergely Risko <gergely+context@risko.hu> Mon, 05 Oct 2009 09:02:50 +0300
@@ -67,7 +75,7 @@ contextkit (0.3.5) unstable; urgency=low
stderr from the libcontextprovider library
* Fixes: NB#121556 - C API of libcontextprovider uses Glib types
- Implemented: CntFr-305
+ Implemented: SWP#CntFr-305
-- Gergely Risko <gergely+context@risko.hu> Mon, 22 Sep 2009 11:36:40 +0300
diff --git a/doc/context-arch.txt b/doc/context-arch.txt
index 767dcf35..bc8f77dc 100644
--- a/doc/context-arch.txt
+++ b/doc/context-arch.txt
@@ -394,7 +394,7 @@ Packages
.+contextkit+
-Languages:: C, C++, Vala
+Languages:: C, C++
License:: LGPL 2.1
diff --git a/doc/demos.txt b/doc/demos.txt
deleted file mode 100644
index 0add33bc..00000000
--- a/doc/demos.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-Demo / manual test descrption
-
-Feature to be demonstrated:
-- Dropping the context prefix both on provider side and on client side, when doing the dbus traffic.
-
-
-0.
-
-Versions used in this tests:
-
-Latest versions (27.5.2009) of DuiValueSpace and libcontextprovider:
-libcontextprovider0_0.1.8~unreleased_armel.deb
-libduivaluespace0_0.9~unreleased_armel.deb
-
-1a. Build the packages from ContextKit repository (branch removecontextprefix) inside scratchbox.
-Outside scratchbox:
-./autogen.sh --enable-gtk-doc
-./configure
-make
-make clean
-
-Inside scratchbox:
-./configure
-make
-dpkg-buildpackage -b -us -uc -rfakeroot
-
-1b. Build the packages from DuiValueSpace repository (branch dropping-context) inside scratchbox.
-
-Inside scratchbox:
-./configure
-make
-dpkg-buildpackage -b -us -uc -rfakeroot
-
-Note: When these versions are released, they can be obtained directly from Harmattan repository.
-
-
-3. Copy the .deb packages to the device and install them.
-
-On the device:
-4. Install context-subscriber-example.
-
-5. Start monitoring DBus traffic on system bus.
-dbus-monitor --system
-
-6. Run context-subscriber-example.
-
-7. Outcome: Even though the context-provider-example and context-subscriber-example use the keys with "Context." prefix, they still work together, and dbus-monitor shows that the keys are transmitted without the "Context." prefix.
-
-signal sender=:1.15 -> dest=(null destination) serial=38 path=/org/freedesktop/ContextKit/Subscribers/6; interface=org.freedesktop.ContextKit.Subscriber; member=Changed
- array [
- dict entry(
- string "Example.EdgeUp"
- variant int32 3
- )
- ]
- array [
- ]
diff --git a/gtk-doc.make b/gtk-doc.make
deleted file mode 100644
index fa7fd6c4..00000000
--- a/gtk-doc.make
+++ /dev/null
@@ -1,201 +0,0 @@
-# -*- mode: makefile -*-
-
-####################################
-# Everything below here is generic #
-####################################
-
-if GTK_DOC_USE_LIBTOOL
-GTKDOC_CC = $(LIBTOOL) --mode=compile $(CC) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-GTKDOC_LD = $(LIBTOOL) --mode=link $(CC) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
-GTKDOC_RUN = $(LIBTOOL) --mode=execute
-else
-GTKDOC_CC = $(CC) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-GTKDOC_LD = $(CC) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
-GTKDOC_RUN = sh -c
-endif
-
-# We set GPATH here; this gives us semantics for GNU make
-# which are more like other make's VPATH, when it comes to
-# whether a source that is a target of one rule is then
-# searched for in VPATH/GPATH.
-#
-GPATH = $(srcdir)
-
-TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)
-
-EXTRA_DIST = \
- $(content_files) \
- $(HTML_IMAGES) \
- $(DOC_MAIN_SGML_FILE) \
- $(DOC_MODULE)-sections.txt \
- $(DOC_MODULE)-overrides.txt
-
-DOC_STAMPS=scan-build.stamp tmpl-build.stamp sgml-build.stamp html-build.stamp \
- $(srcdir)/tmpl.stamp $(srcdir)/sgml.stamp $(srcdir)/html.stamp
-
-SCANOBJ_FILES = \
- $(DOC_MODULE).args \
- $(DOC_MODULE).hierarchy \
- $(DOC_MODULE).interfaces \
- $(DOC_MODULE).prerequisites \
- $(DOC_MODULE).signals
-
-REPORT_FILES = \
- $(DOC_MODULE)-undocumented.txt \
- $(DOC_MODULE)-undeclared.txt \
- $(DOC_MODULE)-unused.txt
-
-CLEANFILES = $(SCANOBJ_FILES) $(REPORT_FILES) $(DOC_STAMPS)
-
-if ENABLE_GTK_DOC
-all-local: html-build.stamp
-else
-all-local:
-endif
-
-docs: html-build.stamp
-
-$(REPORT_FILES): sgml-build.stamp
-
-#### scan ####
-
-scan-build.stamp: $(HFILE_GLOB) $(CFILE_GLOB)
- @echo 'gtk-doc: Scanning header files'
- @-chmod -R u+w $(srcdir)
- cd $(srcdir) && \
- gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES)
- if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null 2>&1 ; then \
- CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" RUN="$(GTKDOC_RUN)" CFLAGS="$(GTKDOC_CFLAGS) $(CFLAGS)" LDFLAGS="$(GTKDOC_LIBS) $(LDFLAGS)" gtkdoc-scangobj $(SCANGOBJ_OPTIONS) --module=$(DOC_MODULE) --output-dir=$(srcdir) ; \
- else \
- cd $(srcdir) ; \
- for i in $(SCANOBJ_FILES) ; do \
- test -f $$i || touch $$i ; \
- done \
- fi
- touch scan-build.stamp
-
-$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp
- @true
-
-#### templates ####
-
-tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt
- @echo 'gtk-doc: Rebuilding template files'
- @-chmod -R u+w $(srcdir)
- cd $(srcdir) && gtkdoc-mktmpl --module=$(DOC_MODULE) $(MKTMPL_OPTIONS)
- touch tmpl-build.stamp
-
-tmpl.stamp: tmpl-build.stamp
- @true
-
-tmpl/*.sgml:
- @true
-
-
-#### xml ####
-
-sgml-build.stamp: tmpl.stamp $(HFILE_GLOB) $(CFILE_GLOB) $(DOC_MODULE)-sections.txt $(srcdir)/tmpl/*.sgml $(expand_content_files)
- @echo 'gtk-doc: Building XML'
- @-chmod -R u+w $(srcdir)
- cd $(srcdir) && \
- gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $(MKDB_OPTIONS)
- touch sgml-build.stamp
-
-sgml.stamp: sgml-build.stamp
- @true
-
-#### html ####
-
-html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files)
- @echo 'gtk-doc: Building HTML'
- @-chmod -R u+w $(srcdir)
- rm -rf $(srcdir)/html
- mkdir $(srcdir)/html
- mkhtml_options=""; \
- gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-path"; \
- if test "$(?)" = "0"; then \
- mkhtml_options=--path="$(srcdir)"; \
- fi
- cd $(srcdir)/html && gtkdoc-mkhtml $(mkhtml_options) $(MKHTML_OPTIONS) $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE)
- test "x$(HTML_IMAGES)" = "x" || ( cd $(srcdir) && cp $(HTML_IMAGES) html )
- @echo 'gtk-doc: Fixing cross-references'
- cd $(srcdir) && gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS)
- touch html-build.stamp
-
-##############
-
-clean-local:
- rm -f *~ *.bak
- rm -rf .libs
-
-distclean-local:
- cd $(srcdir) && \
- rm -rf xml $(REPORT_FILES) \
- $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt
-
-maintainer-clean-local: clean
- cd $(srcdir) && rm -rf xml html
-
-install-data-local:
- installfiles=`echo $(srcdir)/html/*`; \
- if test "$$installfiles" = '$(srcdir)/html/*'; \
- then echo '-- Nothing to install' ; \
- else \
- if test -n "$(DOC_MODULE_VERSION)"; then \
- installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \
- else \
- installdir="$(DESTDIR)$(TARGET_DIR)"; \
- fi; \
- $(mkinstalldirs) $${installdir} ; \
- for i in $$installfiles; do \
- echo '-- Installing '$$i ; \
- $(INSTALL_DATA) $$i $${installdir}; \
- done; \
- if test -n "$(DOC_MODULE_VERSION)"; then \
- mv -f $${installdir}/$(DOC_MODULE).devhelp2 \
- $${installdir}/$(DOC_MODULE)-$(DOC_MODULE_VERSION).devhelp2; \
- mv -f $${installdir}/$(DOC_MODULE).devhelp \
- $${installdir}/$(DOC_MODULE)-$(DOC_MODULE_VERSION).devhelp; \
- fi; \
- ! which gtkdoc-rebase >/dev/null 2>&1 || \
- gtkdoc-rebase --relative --dest-dir=$(DESTDIR) --html-dir=$${installdir} ; \
- fi
-
-uninstall-local:
- if test -n "$(DOC_MODULE_VERSION)"; then \
- installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \
- else \
- installdir="$(DESTDIR)$(TARGET_DIR)"; \
- fi; \
- rm -rf $${installdir}
-
-#
-# Require gtk-doc when making dist
-#
-#if ENABLE_GTK_DOC
-#dist-check-gtkdoc:
-#else
-#dist-check-gtkdoc:
-# @echo "*** gtk-doc must be installed and enabled in order to make dist"
-# @false
-#endif
-
-# contextkit note: instead of checking the availability of gtk-doc,
-# just make the procedure, without hesitation. gtk-doc + distcheck is
-# so hacky and messed up that we haven't found out a better way yet
-dist-check-gtkdoc: html-build.stamp
-
-dist-hook: dist-check-gtkdoc dist-hook-local
- mkdir $(distdir)/tmpl
- mkdir $(distdir)/xml
- mkdir $(distdir)/html
- -cp $(srcdir)/tmpl/*.sgml $(distdir)/tmpl
- -cp $(srcdir)/xml/*.xml $(distdir)/xml
- cp $(srcdir)/html/* $(distdir)/html
- -cp $(srcdir)/$(DOC_MODULE).types $(distdir)/
- -cp $(srcdir)/$(DOC_MODULE)-sections.txt $(distdir)/
- cd $(distdir) && rm -f $(DISTCLEANFILES)
- ! which gtkdoc-rebase >/dev/null 2>&1 || \
- gtkdoc-rebase --online --relative --html-dir=$(distdir)/html
-
-.PHONY : dist-hook-local docs
diff --git a/libcontextprovider/context-provide/Makefile.am b/libcontextprovider/context-provide/Makefile.am
index 571ecd16..4a559065 100644
--- a/libcontextprovider/context-provide/Makefile.am
+++ b/libcontextprovider/context-provide/Makefile.am
@@ -1,5 +1,7 @@
bin_PROGRAMS = context-provide-internal
-context_provide_internal_SOURCES = context-provide.cpp commandwatcher.cpp commandwatcher.h
+context_provide_internal_SOURCES = context-provide.cpp \
+ commandwatcher.cpp commandwatcher.h propertyproxy.h \
+ propertyproxy.cpp
AM_CXXFLAGS = $(QtCore_CFLAGS) $(QtDBus_CFLAGS) \
'-DCONTEXT_LOG_MODULE_NAME="context-provide"'
@@ -7,17 +9,18 @@ LIBS += $(QtCore_LIBS)
# library dependency hack for seamless make
AM_CXXFLAGS += -I$(srcdir)/../src \
- -I$(top_srcdir)/common
+ -I$(top_srcdir)/common \
+ -I$(top_srcdir)/libcontextsubscriber/src
-context_provide_internal_LDADD = ../src/libcontextprovider.la $(top_builddir)/common/libcommon.la
+context_provide_internal_LDADD = ../src/libcontextprovider.la $(top_builddir)/common/libcommon.la $(top_builddir)/libcontextsubscriber/src/libcontextsubscriber.la
-../src/libcontextprovider.la:
+../src/libcontextprovider.la: FORCE
$(MAKE) -C ../src libcontextprovider.la
-$(top_builddir)/common/libcommon.la:
- $(MAKE) -C $(top_builddir)/common libcommon.la
+../../libcontextsubscriber/src/libcontextsubscriber.la: FORCE
+ $(MAKE) -C ../../libcontextsubscriber/src libcontextsubscriber.la
-.PHONY: ../src/libcontextprovider.la $(top_builddir)/common/libcommon.la
+.PHONY: FORCE
# moccing
nodist_context_provide_internal_SOURCES = mocs.cpp
diff --git a/libcontextprovider/context-provide/commandwatcher.cpp b/libcontextprovider/context-provide/commandwatcher.cpp
index 25092948..9a44de1d 100644
--- a/libcontextprovider/context-provide/commandwatcher.cpp
+++ b/libcontextprovider/context-provide/commandwatcher.cpp
@@ -20,8 +20,12 @@
*/
#include "commandwatcher.h"
+#include "propertyproxy.h"
#include "sconnect.h"
+#include <contextpropertyinfo.h>
+#include <contextregistryinfo.h>
#include <service.h>
+
#include <QTextStream>
#include <QFile>
#include <QSocketNotifier>
@@ -33,18 +37,46 @@
#include <errno.h>
#include <QMap>
#include <QDir>
+#include <QSet>
+
+const QString CommandWatcher::commanderBusName = "org.freedesktop.ContextKit.Commander";
CommandWatcher::CommandWatcher(QString bn, QDBusConnection::BusType bt, int commandfd, QObject *parent) :
- QObject(parent), commandfd(commandfd), out(stdout), busName(bn), busType(bt)
+ QObject(parent), commandfd(commandfd),
+ registryInfo(ContextRegistryInfo::instance()),
+ out(stdout), busName(bn), busType(bt), started(false)
{
commandNotifier = new QSocketNotifier(commandfd, QSocketNotifier::Read, this);
sconnect(commandNotifier, SIGNAL(activated(int)), this, SLOT(onActivated()));
+ if (busName == commanderBusName) {
+ ContextProperty::ignoreCommander();
+ ContextProperty::setTypeCheck(true);
+ sconnect(registryInfo, SIGNAL(changed()), this, SLOT(onRegistryChanged()));
+ onRegistryChanged();
+ }
}
CommandWatcher::~CommandWatcher()
{
- foreach(Property* p, properties) {
+ foreach(Property *p, properties)
+ delete p;
+ foreach(PropertyProxy *p, proxies)
+ delete p;
+}
+
+void CommandWatcher::onRegistryChanged()
+{
+ qDebug() << "registry changed";
+ foreach (PropertyProxy *p, proxies)
delete p;
+ proxies.clear();
+ // (Re)create the proxies and restore the user's will of overriding.
+ foreach (QString key, registryInfo->listKeys()) {
+ if (ContextPropertyInfo(key).provided()) {
+ qDebug() << "creating proxy for" << key;
+ proxies.insert(key, new PropertyProxy(key, !properties.contains(key),
+ this));
+ }
}
}
@@ -77,7 +109,10 @@ void CommandWatcher::help()
qDebug() << "Available commands:\n";
qDebug() << " add TYPE KEY [VALUE] - create new key with the given type";
qDebug() << " KEY=VALUE - set KEY to the given VALUE";
+ qDebug() << " info KEY - prints the real (proxied) value of KEY";
qDebug() << " unset KEY - sets KEY to unknown";
+ qDebug() << " del KEY - delete KEY, useful if the tool is commander";
+ qDebug() << " list - same as calling info for all known keys";
qDebug() << " sleep INTERVAL - sleep the INTERVAL amount of seconds";
qDebug() << " dump [FILENAME] - dump the xml content of the defined props";
qDebug() << " start - (re)register everything on D-Bus";
@@ -101,6 +136,12 @@ void CommandWatcher::interpret(const QString& command)
// Interpret commands
if (QString("add").startsWith(commandName)) {
addCommand(args);
+ } else if (QString("del").startsWith(commandName)) {
+ delCommand(args);
+ } else if (QString("info").startsWith(commandName)) {
+ infoCommand(args);
+ } else if (QString("list").startsWith(commandName)) {
+ listCommand();
} else if (QString("sleep").startsWith(commandName)) {
sleepCommand(args);
} else if (QString("exit").startsWith(commandName)) {
@@ -152,6 +193,8 @@ void CommandWatcher::addCommand(const QStringList& args)
} else {
types.insert(keyName, keyType);
properties.insert(keyName, new Property(keyName));
+ if (busName == commanderBusName && proxies.contains(keyName))
+ proxies[keyName]->enable(false);
out << "Added key: " << keyName << " with type: " << keyType << endl;
out.flush();
}
@@ -159,6 +202,67 @@ void CommandWatcher::addCommand(const QStringList& args)
// handle default value
if (args.count() > 2)
setCommand(keyName + "=\"" + QStringList(args.mid(2)).join(" ") + "\"");
+ else
+ unsetCommand(QStringList(keyName));
+
+ // if service is already started then it has to be restarted after a property is added
+ if (started && busName != CommandWatcher::commanderBusName)
+ startCommand();
+}
+
+void CommandWatcher::delCommand(const QStringList &args)
+{
+ if (args.count() < 1) {
+ qDebug() << "ERROR: need to specify KEY";
+ return;
+ }
+
+ const QString keyName = unquote(args.at(0));
+
+ types.remove(keyName);
+ delete properties.take(keyName);
+ if (busName == commanderBusName && proxies.contains(keyName))
+ proxies[keyName]->enable(true);
+ out << "Deleted key: " << keyName << endl;
+ out.flush();
+}
+
+void CommandWatcher::listCommand()
+{
+ foreach (QString key,
+ QSet<QString>::fromList(properties.keys()) +
+ QSet<QString>::fromList(proxies.keys()))
+ infoCommand(QStringList(key));
+}
+
+void CommandWatcher::infoCommand(const QStringList &args)
+{
+ if (args.count() < 1) {
+ qDebug() << "ERROR: need to specify KEY";
+ return;
+ }
+ QString keyName = args.at(0);
+ if (properties.contains(keyName)) {
+ out << types[keyName] << " " << keyName;
+ if (properties[keyName]->value().isNull())
+ out << " is Unknown" << endl;
+ else
+ out << " = " << properties[keyName]->value().toString() << endl;
+ } else if (busName != commanderBusName) {
+ qDebug() << "ERROR:" << keyName << "not addd";
+ }
+ if (busName == commanderBusName) {
+ if (!proxies.contains(keyName))
+ qDebug() << "ERROR:" << keyName << "not known";
+ else {
+ out << "real: " << proxies[keyName]->type() << " "
+ << keyName;
+ if (proxies[keyName]->realValue().isNull())
+ out << " is Unknown" << endl;
+ else
+ out << " = " << proxies[keyName]->realValue().toString() << endl;
+ }
+ }
}
void CommandWatcher::sleepCommand(const QStringList& args)
@@ -279,10 +383,12 @@ void CommandWatcher::unsetCommand(const QStringList& args)
void CommandWatcher::startCommand()
{
Service service(busType, busName);
+ service.stop(); // this is harmless if we are not started yet, but useful if we are
if (!service.start()) {
- qDebug() << "Starting service failed";
+ qDebug() << "Starting service failed, no D-Bus or the service name is already taken";
exit(2);
}
out << "Service started" << endl;
out.flush();
+ started = true;
}
diff --git a/libcontextprovider/context-provide/commandwatcher.h b/libcontextprovider/context-provide/commandwatcher.h
index e8248599..114fa65b 100644
--- a/libcontextprovider/context-provide/commandwatcher.h
+++ b/libcontextprovider/context-provide/commandwatcher.h
@@ -31,6 +31,8 @@ using namespace ContextProvider;
class QFile;
class QSocketNotifier;
class QString;
+class PropertyProxy;
+class ContextRegistryInfo;
template <typename K, typename V> class QMap;
class CommandWatcher : public QObject
@@ -41,28 +43,37 @@ public:
CommandWatcher(QString busName, QDBusConnection::BusType busType, int commandfd, QObject *parent = 0);
~CommandWatcher();
void addCommand(const QStringList& args);
+ static const QString commanderBusName;
private:
- int commandfd;
- QSocketNotifier *commandNotifier;
void interpret(const QString& command);
- QMap <QString, QString> types; // key -> type
- QMap <QString, Property*> properties; // property index
void help();
- QString unquote(const QString& str);
void unsetCommand(const QStringList& args);
void setCommand(const QString& command);
void sleepCommand(const QStringList& args);
void flushCommand();
void dumpCommand(const QStringList& args);
+ void delCommand(const QStringList& args);
+ void infoCommand(const QStringList& args);
+ void listCommand();
void startCommand();
+ QString unquote(const QString& str);
+
+ int commandfd;
+ QSocketNotifier *commandNotifier;
+ QMap <QString, QString> types; // key -> type
+ QMap <QString, Property*> properties; // property index
+ QMap <QString, PropertyProxy*> proxies;
+ ContextRegistryInfo *registryInfo;
+
QTextStream out;
- bool silent;
QString busName;
QDBusConnection::BusType busType;
+ bool started;
private slots:
void onActivated();
+ void onRegistryChanged();
};
#endif
diff --git a/libcontextprovider/context-provide/context-provide.cpp b/libcontextprovider/context-provide/context-provide.cpp
index c95b6aa4..551b5a4b 100644
--- a/libcontextprovider/context-provide/context-provide.cpp
+++ b/libcontextprovider/context-provide/context-provide.cpp
@@ -19,6 +19,8 @@
*
*/
+#include "commandwatcher.h"
+
#include <QCoreApplication>
#include <QString>
#include <QStringList>
@@ -26,12 +28,9 @@
#include <QDebug>
#include <stdlib.h>
#include <service.h>
-#include "commandwatcher.h"
using namespace ContextProvider;
-#define COMMANDER "org.freedesktop.ContextKit.Commander"
-
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
@@ -55,7 +54,7 @@ int main(int argc, char **argv)
// Help? Show it and be gone.
// FIXME: has to replace this with argv[0]
out << "Usage: context-provide --v2 [--session | --system] [BUSNAME]\n";
- out << "BUSNAME is " COMMANDER " by default, and bus is session.\n";
+ out << "BUSNAME is " << CommandWatcher::commanderBusName << " by default, and bus is session.\n";
return 0;
}
@@ -77,7 +76,7 @@ int main(int argc, char **argv)
if (args.count() < 2) {
// No arguments at all? Use commander by default.
- args.push_back(COMMANDER);
+ args.push_back(CommandWatcher::commanderBusName);
}
// Parameter? Extract the session bus and type from it.
@@ -103,7 +102,6 @@ int main(int argc, char **argv)
qDebug() << "Service:" << busName.toLocal8Bit().data() << "on" <<
((busType == QDBusConnection::SessionBus) ? "session" : "system");
-
CommandWatcher commandWatcher(busName, busType, STDIN_FILENO, QCoreApplication::instance());
for (int i=2; i < args.count(); i+=3)
diff --git a/libcontextprovider/context-provide/propertyproxy.cpp b/libcontextprovider/context-provide/propertyproxy.cpp
new file mode 100644
index 00000000..9c012a24
--- /dev/null
+++ b/libcontextprovider/context-provide/propertyproxy.cpp
@@ -0,0 +1,49 @@
+#include "propertyproxy.h"
+#include "sconnect.h"
+#include "contextproperty.h"
+#include "contextpropertyinfo.h"
+#include "property.h"
+#include "logging.h"
+
+PropertyProxy::PropertyProxy(QString key, bool enabled, QObject *parent) :
+ QObject(parent), enabled(enabled)
+{
+ subscriber = new ContextProperty(key, this);
+ provider = new ContextProvider::Property(key, this);
+ sconnect(subscriber, SIGNAL(valueChanged()),
+ this, SLOT(onValueChanged()));
+ enable(enabled);
+}
+
+void PropertyProxy::enable(bool enable)
+{
+ qDebug() << (const char *)(enable ? "enabled" : "disabled") <<
+ "proxying" << subscriber->key();
+ enabled = enable;
+ if (enable)
+ provider->setValue(value);
+}
+
+QVariant PropertyProxy::realValue() const
+{
+ return value;
+}
+
+QString PropertyProxy::type() const
+{
+ return subscriber->info()->type();
+}
+
+void PropertyProxy::onValueChanged()
+{
+ value = subscriber->value();
+ if (enabled)
+ provider->setValue(value);
+ QTextStream out(stdout);
+ out << "real: " << type() << " " << subscriber->key();
+ if (realValue().isNull())
+ out << " is Unknown" << endl;
+ else
+ out << " = " << realValue().toString() << endl;
+ out.flush();
+}
diff --git a/libcontextprovider/context-provide/propertyproxy.h b/libcontextprovider/context-provide/propertyproxy.h
new file mode 100644
index 00000000..f185f2ad
--- /dev/null
+++ b/libcontextprovider/context-provide/propertyproxy.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Marius Vollmer <marius.vollmer@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.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef PROPERTYPROXY_H
+#define PROPERTYPROXY_H
+
+#include "contextproperty.h"
+#include "property.h"
+
+class PropertyProxy : public QObject
+{
+ Q_OBJECT;
+public:
+ PropertyProxy(QString key, bool enabled = true, QObject *parent = 0);
+ void enable(bool enable);
+ QVariant realValue() const;
+ QString type() const;
+private slots:
+ void onValueChanged();
+private:
+ ContextProvider::Property *provider;
+ ContextProperty *subscriber;
+ bool enabled;
+ QVariant value;
+};
+
+#endif
diff --git a/libcontextprovider/customer-tests/subscription/Makefile.am b/libcontextprovider/customer-tests/subscription/Makefile.am
index 6d6dc42b..b4d69087 100644
--- a/libcontextprovider/customer-tests/subscription/Makefile.am
+++ b/libcontextprovider/customer-tests/subscription/Makefile.am
@@ -13,13 +13,10 @@ AM_CXXFLAGS = $(QtCore_CFLAGS) $(QtDBus_CFLAGS) $(QtTest_CFLAGS) -I$(srcdir)/..
LIBS += $(QtCore_LIBS) $(QtDBus_LIBS) $(QtTest_LIBS)
subscriptiontests_LDADD = ../../src/libcontextprovider.la $(top_builddir)/common/libcommon.la
-../../src/libcontextprovider.la:
+../../src/libcontextprovider.la: FORCE
$(MAKE) -C ../../src libcontextprovider.la
-$(top_builddir)/common/libcommon.la:
- $(MAKE) -C $(top_builddir)/common libcommon.la
-
-.PHONY: ../../libcontextprovider.la $(top_builddir)/libcommon.la
+.PHONY: FORCE
# moccing
nodist_subscriptiontests_SOURCES = mocs.cpp
diff --git a/libcontextprovider/customer-tests/types/Makefile.am b/libcontextprovider/customer-tests/types/Makefile.am
index 469920b9..e2ca07fd 100644
--- a/libcontextprovider/customer-tests/types/Makefile.am
+++ b/libcontextprovider/customer-tests/types/Makefile.am
@@ -9,9 +9,10 @@ check-customer: $(test_PROGRAMS)
AM_CXXFLAGS = $(QtCore_CFLAGS) $(QtDBus_CFLAGS) $(QtTest_CFLAGS) -I$(srcdir)/../../src -I$(top_srcdir)/common
LIBS += $(QtCore_LIBS) $(QtDBus_LIBS) $(QtTest_LIBS)
typestests_LDADD = ../../src/libcontextprovider.la
-../../src/libcontextprovider.la:
+
+../../src/libcontextprovider.la: FORCE
$(MAKE) -C ../../src libcontextprovider.la
-.PHONY: ../../libcontextprovider.la
+.PHONY: FORCE
# moccing
nodist_typestests_SOURCES = mocs.cpp
diff --git a/libcontextprovider/customer-tests/value-changes/Makefile.am b/libcontextprovider/customer-tests/value-changes/Makefile.am
index 1ccf3215..6b104c16 100644
--- a/libcontextprovider/customer-tests/value-changes/Makefile.am
+++ b/libcontextprovider/customer-tests/value-changes/Makefile.am
@@ -9,9 +9,10 @@ check-customer: $(test_PROGRAMS)
AM_CXXFLAGS = $(QtCore_CFLAGS) $(QtDBus_CFLAGS) $(QtTest_CFLAGS) -I$(srcdir)/../../src -I$(top_srcdir)/common
LIBS += $(QtCore_LIBS) $(QtDBus_LIBS) $(QtTest_LIBS)
valuechangestests_LDADD = ../../src/libcontextprovider.la
-../../src/libcontextprovider.la:
+
+../../src/libcontextprovider.la: FORCE
$(MAKE) -C ../../src libcontextprovider.la
-.PHONY: ../../libcontextprovider.la
+.PHONY: FORCE
# moccing
nodist_valuechangestests_SOURCES = mocs.cpp
diff --git a/libcontextprovider/doc/Makefile.am b/libcontextprovider/doc/Makefile.am
index 627b7778..1274e3c6 100644
--- a/libcontextprovider/doc/Makefile.am
+++ b/libcontextprovider/doc/Makefile.am
@@ -4,7 +4,9 @@ endif
DOXYCFG = $(srcdir)/doxy.cfg
-doxygen:
+doxygen: html/index.html
+
+html/index.html: ../src/*.cpp ../src/*.h
@if test x$(srcdir) = x. ; then \
echo srcdir=$(srcdir) $(DOXYGEN) $(DOXYCFG); \
srcdir=$(srcdir) $(DOXYGEN) $(DOXYCFG); \
diff --git a/libcontextprovider/man/context-provide-v2.1 b/libcontextprovider/man/context-provide-v2.1
index 855a5521..a4bbf63e 100644
--- a/libcontextprovider/man/context-provide-v2.1
+++ b/libcontextprovider/man/context-provide-v2.1
@@ -27,10 +27,16 @@ Properties can also be provided on the command line with \fITYPE\fR
If at least one property is specified on the command line the service
is autostarted and will start providing the properties right away,
-otherwise you have to use the \fBstart\fR command after all of the
-properties have been added by \fBadd\fR invocations. In both cases
+otherwise you have to use the \fB`start'\fR command after all of the
+properties have been added by \fB`add'\fR invocations. In both cases
the service name registered for the service on D-Bus will be \fIBUSNAME\fR.
+If no \fIBUSNAME\fR is given the tool acts as a Commander, taking control of
+all subscribers in the system. This mode by default proxies the real values
+of all properties. To control a property you have to \fB`add'\fR the
+property, which stops forwarding the corresponding property. You can undo
+this via the \fB`del'\fR command.
+
.SH OPTIONS
.TP
\fB--system\fR
@@ -47,6 +53,12 @@ provided properties. The initial value will be \fIINITVALUE\fR if
specified, otherwise unset (null). This has to be called before an
attempt is made to set a key value. \fITYPE\fR can be: STRING, INT,
BOOL, DOUBLE. Example: "add INT Battery.Status 20".
+
+In \fICommander\fR mode it also ceases proxying the real property.
+.TP
+\fBdel\fR \fIKEY\fR
+makes context-provide forget \fIKEY\fR. In \fICommander\fR mode, restores
+proxying of the real property.
.TP
\fIKEY\fB=\fIVALUE\fR
sets the given \fIKEY\fR value to the new \fIVALUE\fR. Example: "Battery.Status=99".
@@ -54,6 +66,13 @@ sets the given \fIKEY\fR value to the new \fIVALUE\fR. Example: "Battery.Status=
\fBunset\fR \fIKEY\fR
sets the given \fIKEY\fR to non specified (null).
.TP
+\fBinfo\fR \fIKEY\fR
+prints the type, name and current value of \fIKEY\fR. In \fICommander\fR
+mode the real value (from the original provider) is printed as well.
+.TP
+\fBlist\fR
+same as calling `info' for all known keys (both proxied and added ones)
+.TP
\fBsleep\fR \fIINTERVAL\fR
sleeps and blocks the main loop for the given amount of seconds. Used
mainly for internal testing purposes. Example: "sleep 10".
@@ -64,7 +83,7 @@ by the \fIFILENAME\fR, the default is 'context-provide.context' in the
current directory.
.TP
\fBstart\fR
-try publish the \fIBUSNAME\fR of the provider on D-Bus, exit if it fails.
+try to (re)publish the \fIBUSNAME\fR of the provider on D-Bus, exit if it fails.
.TP
\fBexit\fR
exit from the program.
diff --git a/libcontextprovider/src/Makefile.am b/libcontextprovider/src/Makefile.am
index b4feb297..eac30d7e 100644
--- a/libcontextprovider/src/Makefile.am
+++ b/libcontextprovider/src/Makefile.am
@@ -34,10 +34,10 @@ AM_CXXFLAGS = $(QtCore_CFLAGS) $(QtDBus_CFLAGS) $(DBUS_CFLAGS) \
LIBS += $(QtCore_LIBS) $(QtDBus_LIBS)
libcontextprovider_la_LIBADD=$(top_builddir)/common/libcommon.la
-$(top_builddir)/common/libcommon.la:
+$(top_builddir)/common/libcommon.la: FORCE
$(MAKE) -C $(top_builddir)/common libcommon.la
-.PHONY: $(top_builddir)/common/libcommon.la
+.PHONY: FORCE
# moccing
nodist_libcontextprovider_la_SOURCES = mocs.cpp
diff --git a/libcontextsubscriber/.gitignore b/libcontextsubscriber/.gitignore
index 3ba1ffed..616c4958 100644
--- a/libcontextsubscriber/.gitignore
+++ b/libcontextsubscriber/.gitignore
@@ -42,6 +42,7 @@ coverage/
# Other binaries
/cli/context-listen
+/cls/context-ls
/update-tool/update-tool
/update-contextkit-providers/update-contextkit-providers
diff --git a/libcontextsubscriber/Makefile.am b/libcontextsubscriber/Makefile.am
index 35609d42..435fd078 100644
--- a/libcontextsubscriber/Makefile.am
+++ b/libcontextsubscriber/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = src unit-tests customer-tests multithreading-tests cli cls update-contextkit-providers doc man
+SUBDIRS = src unit-tests customer-tests cli cls update-contextkit-providers doc man
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = contextsubscriber-1.0.pc
diff --git a/libcontextsubscriber/cli/Makefile.am b/libcontextsubscriber/cli/Makefile.am
index 43fe4c95..21f6b543 100644
--- a/libcontextsubscriber/cli/Makefile.am
+++ b/libcontextsubscriber/cli/Makefile.am
@@ -13,13 +13,10 @@ AM_CXXFLAGS += -I$(srcdir)/../src \
context_listen_LDADD = ../src/libcontextsubscriber.la $(top_builddir)/common/libcommon.la
-../src/libcontextsubscriber.la:
+../src/libcontextsubscriber.la: FORCE
$(MAKE) -C ../src libcontextsubscriber.la
-$(top_builddir)/common/libcommon.la:
- $(MAKE) -C $(top_builddir)/common libcommon.la
-
-.PHONY: ../src/libcontextsubscriber.la $(top_builddir)/common/libcommon.la
+.PHONY: FORCE
# moccing
nodist_context_listen_SOURCES = mocs.cpp
diff --git a/libcontextsubscriber/cls/Makefile.am b/libcontextsubscriber/cls/Makefile.am
index 82fc46ce..72ad14e4 100644
--- a/libcontextsubscriber/cls/Makefile.am
+++ b/libcontextsubscriber/cls/Makefile.am
@@ -10,14 +10,10 @@ AM_CXXFLAGS += -I$(srcdir)/../src \
-I$(top_srcdir)/common
context_ls_LDADD = ../src/libcontextsubscriber.la $(top_builddir)/common/libcommon.la
-
-../src/libcontextsubscriber.la:
+../src/libcontextsubscriber.la: FORCE
$(MAKE) -C ../src libcontextsubscriber.la
-$(top_builddir)/common/libcommon.la:
- $(MAKE) -C $(top_builddir)/common libcommon.la
-
-.PHONY: ../src/libcontextsubscriber.la $(top_builddir)/common/libcommon.la
+.PHONY: FORCE
# moccing
# nodist_context_ls_SOURCES = mocs.cpp
diff --git a/libcontextsubscriber/customer-tests/asynchronicity/rapidchanges.py b/libcontextsubscriber/customer-tests/asynchronicity/rapidchanges.py
index f58aa887..cdb6d345 100755
--- a/libcontextsubscriber/customer-tests/asynchronicity/rapidchanges.py
+++ b/libcontextsubscriber/customer-tests/asynchronicity/rapidchanges.py
@@ -66,7 +66,9 @@ class RapidChanges(unittest.TestCase):
context_client.resume()
# /.^/ is a regexp that doesn't match anything
context_client.expect(CLTool.STDOUT, ".^", 3, wantdump=False)
- self.assertEqual(context_client.last_output, "test.fast = int:54\n",
+ if context_client.last_output != "test.fast = int:54\n":
+ context_client.printio()
+ self.assert_(False,
"expected a single valueChanged")
provider_fast.close()
diff --git a/libcontextsubscriber/customer-tests/commander/commander_disabled.py b/libcontextsubscriber/customer-tests/commander/commander_disabled.py
index 5e3a6648..0fffd634 100755
--- a/libcontextsubscriber/customer-tests/commander/commander_disabled.py
+++ b/libcontextsubscriber/customer-tests/commander/commander_disabled.py
@@ -46,9 +46,10 @@ class CommanderDisabled(unittest.TestCase):
commander.expect(CLTool.STDOUT, "Added", 10) # wait for it
os.environ["CONTEXT_CLI_IGNORE_COMMANDER"] = ""
listen = CLTool("context-listen", "test.int")
+ listen.expect(CLTool.STDERR, "Available commands", 10) # wait for it
self.assert_(listen.expect(CLTool.STDOUT,
CLTool.wanted("test.int", "int", "42"),
- 1),
+ 3),
"Provider provided value is wrong")
def runTests():
diff --git a/libcontextsubscriber/customer-tests/registry/registry.py b/libcontextsubscriber/customer-tests/registry/registry.py
index 629946f3..12dbfbe0 100755
--- a/libcontextsubscriber/customer-tests/registry/registry.py
+++ b/libcontextsubscriber/customer-tests/registry/registry.py
@@ -67,7 +67,7 @@ class PrintingProperties(unittest.TestCase):
self.assert_(info_client.expectAll(CLTool.STDOUT,
expected_results,
- 1),
+ 10),
"Bad introspection result from context-ls")
def runTests():
diff --git a/libcontextsubscriber/customer-tests/subscription/multiprovider.py b/libcontextsubscriber/customer-tests/subscription/multiprovider.py
new file mode 100755
index 00000000..02013797
--- /dev/null
+++ b/libcontextsubscriber/customer-tests/subscription/multiprovider.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+##
+## Copyright (C) 2008, 2009 Nokia. All rights reserved.
+##
+## Contact: Marius Vollmer <marius.vollmer@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.
+##
+## This library is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+## 02110-1301 USA
+
+import sys
+import os
+import unittest
+from ContextKit.cltool import CLTool
+
+class MultiProvider(unittest.TestCase):
+ def testMultipleProviders(self):
+ """
+ Description
+ This test verifies correct client behavior in the presence of
+ multiple providers.
+
+ Steps
+ 1. starts up a client
+ 2. starts two providers (X and Y) providing the same P property
+ 3. X sets P to V1 and verifies that the client got it
+ 4. Y sets P to V2 and likewise verifies in the client
+ 5. Y sets P to NULL, the client verifies that P goes back to V1
+ 6. Y sets P to V3, the client verifies P == V3
+ 7. Y is removed from the registry, client verifies that P == V1
+ 8. X is removed from the registry, client verifies that P == NULL
+ """
+ client = CLTool("context-listen", "test.prop")
+ client.expect(CLTool.STDERR, "Available commands", 3)
+
+ provider_x = CLTool("context-provide", "--v2", "test.X",
+ "int", "test.prop", "44")
+ provider_x.send("dump x.context")
+ provider_x.expect(CLTool.STDOUT, "Wrote", 10)
+
+ provider_y = CLTool("context-provide", "--v2", "test.Y",
+ "int", "test.prop", "22")
+ provider_y.send("dump y.context")
+ provider_y.expect(CLTool.STDOUT, "Wrote", 10)
+
+ provider_x.send("test.prop = 55");
+ provider_x.expect(CLTool.STDOUT, "Setting key", 10)
+ self.assert_(client.expect(CLTool.STDOUT,
+ CLTool.wanted("test.prop", "int", "55"),
+ 3))
+
+ provider_y.send("test.prop = 77");
+ provider_y.expect(CLTool.STDOUT, "Setting key", 10)
+ self.assert_(client.expect(CLTool.STDOUT,
+ CLTool.wanted("test.prop", "int", "77"),
+ 3))
+
+ provider_y.send("unset test.prop");
+ provider_y.expect(CLTool.STDOUT, "Setting key", 10)
+ self.assert_(client.expect(CLTool.STDOUT,
+ CLTool.wanted("test.prop", "int", "55"),
+ 3))
+
+ provider_y.send("test.prop = 99");
+ provider_y.expect(CLTool.STDOUT, "Setting key", 10)
+ self.assert_(client.expect(CLTool.STDOUT,
+ CLTool.wanted("test.prop", "int", "99"),
+ 3))
+
+ provider_y.close()
+ os.unlink("y.context")
+ self.assert_(client.expect(CLTool.STDOUT,
+ CLTool.wanted("test.prop", "int", "55"),
+ 3))
+
+ provider_x.close()
+ os.unlink("x.context")
+ self.assert_(client.expect(CLTool.STDOUT,
+ CLTool.wantedUnknown("test.prop"),
+ 3))
+ client.close()
+
+def runTests():
+ suiteInstallation = unittest.TestLoader().loadTestsFromTestCase(MultiProvider)
+ result = unittest.TextTestRunner(verbosity=2).run(suiteInstallation)
+ return len(result.errors + result.failures)
+
+if __name__ == "__main__":
+ sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)
+ sys.exit(runTests())
diff --git a/libcontextsubscriber/customer-tests/subscription/multiprovider2.py b/libcontextsubscriber/customer-tests/subscription/multiprovider2.py
new file mode 100755
index 00000000..70e89a8f
--- /dev/null
+++ b/libcontextsubscriber/customer-tests/subscription/multiprovider2.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+##
+## Copyright (C) 2008, 2009 Nokia. All rights reserved.
+##
+## Contact: Marius Vollmer <marius.vollmer@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.
+##
+## This library is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+## 02110-1301 USA
+
+import sys
+import os
+import unittest
+import time
+from ContextKit.cltool import CLTool
+
+class MultiProvider(unittest.TestCase):
+ def tearDown(self):
+ try:
+ os.unlink("x.context")
+ except:
+ pass
+ try:
+ os.unlink("y.context")
+ except:
+ pass
+
+ def testMultipleProviders2(self):
+ """
+ Description
+ This test verifies correct client behavior in the presence
+ of multiple providers. In this test we always start the
+ client after the providers have already been started and
+ values have been set.
+
+ Steps
+ 1. starts two providers (X and Y) providing the same P property
+ 2. X sets P to V1
+ 3. Y sets P to V2
+ 4. starts a client and check that value for P is V2
+ 5. starts a client with different provider order and
+ checks that value for P is still V2
+ """
+ # please reenable this test when new protocol on provider side is merged!
+ return
+
+ provider_x = CLTool("context-provide", "--v2", "test.x",
+ "int", "test.prop", "44")
+ provider_x.send("dump x.context")
+ provider_x.expect(CLTool.STDOUT, "Wrote", 10)
+
+ provider_y = CLTool("context-provide", "--v2", "test.y",
+ "int", "test.prop", "22")
+ provider_y.send("dump y.context")
+ provider_y.expect(CLTool.STDOUT, "Wrote", 10)
+
+ client = CLTool("context-listen")
+ client.expect(CLTool.STDERR, "Available commands", 3)
+ provider_x.send("sleep 2")
+ provider_x.expect(CLTool.STDOUT, "Sleeping", 10)
+ client.send("n test.prop")
+
+ time.sleep(4)
+
+ client.send("value test.prop")
+ self.assert_(client.expect(CLTool.STDOUT,
+ "\nvalue: int:22\n",
+ 3))
+ client.close()
+ provider_x.close()
+ provider_y.close()
+
+def runTests():
+ suiteInstallation = unittest.TestLoader().loadTestsFromTestCase(MultiProvider)
+ result = unittest.TextTestRunner(verbosity=2).run(suiteInstallation)
+ return len(result.errors + result.failures)
+
+if __name__ == "__main__":
+ sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)
+ sys.exit(runTests())
diff --git a/libcontextsubscriber/customer-tests/subscription/subscription.py b/libcontextsubscriber/customer-tests/subscription/subscription.py
index 91e304bd..62b0c0c5 100755
--- a/libcontextsubscriber/customer-tests/subscription/subscription.py
+++ b/libcontextsubscriber/customer-tests/subscription/subscription.py
@@ -418,6 +418,7 @@ class MultipleSubscribers(unittest.TestCase):
self.context_client4.expect(CLTool.STDERR, "Available commands", 10) # wait for it
def tearDown(self):
+ self.flexiprovider.send("exit")
self.flexiprovider.close()
self.context_client1.close()
self.context_client2.close()
diff --git a/libcontextsubscriber/customer-tests/testplugins/timeplugin1/Makefile.am b/libcontextsubscriber/customer-tests/testplugins/timeplugin1/Makefile.am
index 1bfee787..9f8f97a5 100644
--- a/libcontextsubscriber/customer-tests/testplugins/timeplugin1/Makefile.am
+++ b/libcontextsubscriber/customer-tests/testplugins/timeplugin1/Makefile.am
@@ -19,13 +19,13 @@ AM_CXXFLAGS = -I$(top_srcdir)/common \
contextsubscribertime1_la_LDFLAGS = -avoid-version -module
-$(top_builddir)/common/libcommon.a:
+$(top_builddir)/common/libcommon.a: FORCE
$(MAKE) -C $(top_builddir)/common libcommon.a
LIBS += $(CDB_LIBS) $(QtCore_LIBS) $(QtDBus_LIBS)
contextsubscribertime1_la_LIBADD=$(top_builddir)/common/libcommon.la
-.PHONY: $(top_builddir)/common/libcommon.la
+.PHONY: FORCE
# moccing
nodist_contextsubscribertime1_la_SOURCES = mocs.cpp
diff --git a/libcontextsubscriber/customer-tests/testplugins/timeplugin2/Makefile.am b/libcontextsubscriber/customer-tests/testplugins/timeplugin2/Makefile.am
index 537159b0..fdbc492b 100644
--- a/libcontextsubscriber/customer-tests/testplugins/timeplugin2/Makefile.am
+++ b/libcontextsubscriber/customer-tests/testplugins/timeplugin2/Makefile.am
@@ -19,13 +19,13 @@ AM_CXXFLAGS = -I$(top_srcdir)/common \
contextsubscribertime2_la_LDFLAGS = -avoid-version -module
-$(top_builddir)/common/libcommon.a:
+$(top_builddir)/common/libcommon.a: FORCE
$(MAKE) -C $(top_builddir)/common libcommon.a
LIBS += $(CDB_LIBS) $(QtCore_LIBS) $(QtDBus_LIBS)
contextsubscribertime2_la_LIBADD=$(top_builddir)/common/libcommon.la
-.PHONY: $(top_builddir)/common/libcommon.la
+.PHONY: FORCE
# moccing
nodist_contextsubscribertime2_la_SOURCES = mocs.cpp
diff --git a/libcontextsubscriber/customer-tests/tests.xml b/libcontextsubscriber/customer-tests/tests.xml
index 91823244..5c114768 100644
--- a/libcontextsubscriber/customer-tests/tests.xml
+++ b/libcontextsubscriber/customer-tests/tests.xml
@@ -82,7 +82,20 @@
<case name="libsub016" description="Plugin loading of libcontextsubscriber" requirement="" timeout="20">
<step expected_result="0">. /tmp/session_bus_address.user;export CONTEXT_PROVIDERS=.; cd /usr/share/libcontextsubscriber-tests/pluginchanging;python /usr/share/libcontextsubscriber-tests/pluginchanging/pluginchanging.py</step>
</case>
-
+ <case name="libsub017" description="Multiple providers"
+ requirement="" timeout="20">
+ <step expected_result="0">. /tmp/session_bus_address.user;export CONTEXT_PROVIDERS=.; cd /usr/share/libcontextsubscriber-tests/subscription; python multiprovider.py</step>
+ </case>
+ <case name="libsub018" description="Rapid changes"
+ requirement="" timeout="20">
+ <step expected_result="0">. /tmp/session_bus_address.user;export CONTEXT_PROVIDERS=.; cd /usr/share/libcontextsubscriber-tests/asynchronicity; python rapidchanges.py</step>
+ </case>
+ <!-- Please add this as soon as the provider library supports the new protocol
+ <case name="libsub019" description="Multiprovider timestamp"
+ requirement="" timeout="20">
+ <step expected_result="0">. /tmp/session_bus_address.user;export CONTEXT_PROVIDERS=.; cd /usr/share/libcontextsubscriber-tests/subscription; python multiprovider2.py</step>
+ </case>
+ -->
<environments>
<scratchbox>false</scratchbox>
<hardware>true</hardware>
diff --git a/libcontextsubscriber/doc/Makefile.am b/libcontextsubscriber/doc/Makefile.am
index 627b7778..1274e3c6 100644
--- a/libcontextsubscriber/doc/Makefile.am
+++ b/libcontextsubscriber/doc/Makefile.am
@@ -4,7 +4,9 @@ endif
DOXYCFG = $(srcdir)/doxy.cfg
-doxygen:
+doxygen: html/index.html
+
+html/index.html: ../src/*.cpp ../src/*.h
@if test x$(srcdir) = x. ; then \
echo srcdir=$(srcdir) $(DOXYGEN) $(DOXYCFG); \
srcdir=$(srcdir) $(DOXYGEN) $(DOXYCFG); \
diff --git a/libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/Makefile.am b/libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/Makefile.am
deleted file mode 100644
index 6e80e6d8..00000000
--- a/libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/Makefile.am
+++ /dev/null
@@ -1,17 +0,0 @@
-noinst_PROGRAMS = run-test
-run_test_SOURCES = main.cpp thread.h
-
-AM_CXXFLAGS = $(QtCore_CFLAGS)
-LIBS += $(QtCore_LIBS)
-
-# library dependency hack for seamless make in cli/
-AM_CXXFLAGS += -I$(srcdir)/../../src
-run_test_LDADD = ../../src/libcontextsubscriber.la
-../../src/libcontextsubscriber.la:
- $(MAKE) -C ../../src libcontextsubscriber.la
-.PHONY: ../../src/libcontextsubscriber.la
-
-# moccing
-nodist_run_test_SOURCES = mocs.cpp
-QT_TOMOC = $(filter %.h, $(run_test_SOURCES))
-include $(top_srcdir)/am/qt.am
diff --git a/libcontextsubscriber/src/Makefile.am b/libcontextsubscriber/src/Makefile.am
index e72bf620..05e5dc1d 100644
--- a/libcontextsubscriber/src/Makefile.am
+++ b/libcontextsubscriber/src/Makefile.am
@@ -12,7 +12,7 @@ libcontextsubscriber_la_SOURCES = contextproperty.cpp \
handlesignalrouter.h queuedinvoker.cpp queuedinvoker.h \
loggingfeatures.h contextkitplugin.h contextkitplugin.cpp \
iproviderplugin.h contextproviderinfo.h nanoxml.h nanoxml.cpp \
- asyncdbusinterface.cpp
+ asyncdbusinterface.cpp timedvalue.h
includecontextsubscriberdir=$(includedir)/contextsubscriber
includecontextsubscriber_HEADERS = contextproperty.h \
@@ -26,13 +26,13 @@ AM_CXXFLAGS = -I$(top_srcdir)/common \
'-DDEFAULT_CONTEXT_CORE_DECLARATIONS="@datadir@/contextkit/core.context"' \
'-DCONTEXT_LOG_MODULE_NAME="libcontextsubscriber"'
-$(top_builddir)/common/libcommon.la:
+$(top_builddir)/common/libcommon.la: FORCE
$(MAKE) -C $(top_builddir)/common libcommon.la
LIBS += $(CDB_LIBS) $(QtCore_LIBS) $(QtXml_LIBS) $(QtDBus_LIBS)
libcontextsubscriber_la_LIBADD=$(top_builddir)/common/libcommon.la
-.PHONY: $(top_builddir)/common/libcommon.la
+.PHONY: FORCE
# moccing
nodist_libcontextsubscriber_la_SOURCES = mocs.cpp
diff --git a/libcontextsubscriber/src/contextkitplugin.cpp b/libcontextsubscriber/src/contextkitplugin.cpp
index a4ed0738..ad34ac56 100644
--- a/libcontextsubscriber/src/contextkitplugin.cpp
+++ b/libcontextsubscriber/src/contextkitplugin.cpp
@@ -24,7 +24,9 @@
#include "subscriberinterface.h"
#include "sconnect.h"
#include <QStringList>
+#include <QDBusPendingCall>
#include <QTimer>
+#include <QDBusPendingReply>
/// Creates a new instance, the service to connect to has to be passed
/// in \c constructionString in the format <tt>[session|dbus]:servicename</tt>.
@@ -53,6 +55,34 @@ namespace ContextSubscriber {
const QString ContextKitPlugin::managerPath = "/org/freedesktop/ContextKit/Manager";
const QString ContextKitPlugin::managerIName = "org.freedesktop.ContextKit.Manager";
+const QString ContextKitPlugin::propertyIName = "org.maemo.contextkit.Property";
+const QString ContextKitPlugin::corePrefix = "/org/maemo/contextkit/";
+
+/// Converts a key name to a protocol level object path. There is a
+/// distinction, because core properties have the form
+/// <tt>/org/maemo/contextkit/Screen/TopEdge</tt> on D-Bus level, but
+/// on higher levels they are <tt>Screen.TopEdge</tt>. Non-core
+/// properties should simply have a name like
+/// /com/nokia/modem/Specific/Feature, so they can be used as object
+/// paths without further conversions.
+QString ContextKitPlugin::keyToPath(QString key)
+{
+ if (key.startsWith("/"))
+ return key;
+
+ return corePrefix + key.replace('.', '/');
+}
+
+/// Inverse of \c keyToPath.
+QString ContextKitPlugin::pathToKey(QString path)
+{
+ if (path.startsWith(corePrefix)) {
+ QString key = path.mid(corePrefix.size());
+ return key.replace('/', '.');
+ }
+
+ return path;
+}
/// Creates subscriber and manager interface, tries to get a
/// subscriber instance from the manager and starts listening for
@@ -64,6 +94,7 @@ ContextKitPlugin::ContextKitPlugin(const QDBusConnection bus, const QString& bus
connection(new QDBusConnection(bus)),
busName(busName)
{
+ reset();
// Notice if the provider on the dbus comes and goes
sconnect(providerListener, SIGNAL(nameAppeared()),
this, SLOT(onProviderAppeared()));
@@ -77,23 +108,31 @@ ContextKitPlugin::ContextKitPlugin(const QDBusConnection bus, const QString& bus
QMetaObject::invokeMethod(this, "onProviderAppeared", Qt::QueuedConnection);
}
+void ContextKitPlugin::reset()
+{
+ delete(subscriberInterface);
+ subscriberInterface = 0;
+ delete(managerInterface);
+ managerInterface = 0;
+ newProtocol = false;
+ connection->disconnect(busName, "", propertyIName, "ValueChanged",
+ this, SLOT(onNewValueChanged(QList<QVariant>,quint64,QDBusMessage)));
+}
+
/// Gets a new subscriber interface from manager when the provider
/// appears.
void ContextKitPlugin::onProviderAppeared()
{
contextDebug() << "ContextKitPlugin::onProviderAppeared";
- delete subscriberInterface;
- subscriberInterface = 0;
- delete managerInterface;
+ reset();
managerInterface = new AsyncDBusInterface(busName, managerPath, managerIName, *connection, this);
if (!managerInterface->callWithCallback("GetSubscriber",
QList<QVariant>(),
this,
SLOT(onDBusGetSubscriberFinished(QDBusObjectPath)),
SLOT(onDBusGetSubscriberFailed(QDBusError)))) {
- emit failed(QString("Wasn't able to call GetSubscriber on the managerinterface: ") +
- managerInterface->lastError().message());
+ onDBusGetSubscriberFailed(managerInterface->lastError());
}
}
@@ -101,8 +140,7 @@ void ContextKitPlugin::onProviderAppeared()
void ContextKitPlugin::onProviderDisappeared()
{
contextDebug() << "ContextKitPlugin::onProviderDisappeared";
- delete subscriberInterface;
- subscriberInterface = 0;
+ reset();
emit failed("Provider went away");
}
@@ -130,7 +168,21 @@ void ContextKitPlugin::onDBusGetSubscriberFinished(QDBusObjectPath objectPath)
void ContextKitPlugin::onDBusGetSubscriberFailed(QDBusError err)
{
- emit failed("Was unable to get subscriber object on dbus: " + err.message());
+ contextWarning() <<
+ "Trying new protocol, because were not able to get subscriber object on dbus: " +
+ err.message();
+ reset();
+ newProtocol = true;
+
+ // connect to dbus value changes too!
+ connection->connect(busName, "", propertyIName, "ValueChanged",
+ this, SLOT(onNewValueChanged(QList<QVariant>,quint64,QDBusMessage)));
+
+ // We queue the emitting of ready, because if subscribtions are
+ // already scheduled, they all will be tried in response and
+ // (apparently) we can't start a new pendingcall inside the error
+ // callback of an other one without a deadlock.
+ QMetaObject::invokeMethod(this, "ready", Qt::QueuedConnection);
}
/// Signals the Provider that the subscribe is finished.
@@ -150,13 +202,42 @@ void ContextKitPlugin::onDBusSubscribeFailed(QList<QString> keys, QString error)
/// Forwards the subscribe request to the wire.
void ContextKitPlugin::subscribe(QSet<QString> keys)
{
- subscriberInterface->subscribe(keys);
+ if (newProtocol)
+ foreach (QString key, keys) {
+ QDBusPendingCall pc = connection->asyncCall(QDBusMessage::createMethodCall(busName,
+ keyToPath(key),
+ propertyIName,
+ "Subscribe"));
+ PendingSubscribeWatcher *psw = new PendingSubscribeWatcher(pc, key, this);
+ sconnect(psw,
+ SIGNAL(subscribeFinished(QString)),
+ this,
+ SIGNAL(subscribeFinished(QString)));
+ sconnect(psw,
+ SIGNAL(subscribeFailed(QString,QString)),
+ this,
+ SIGNAL(subscribeFailed(QString,QString)));
+ sconnect(psw,
+ SIGNAL(valueChanged(QString,TimedValue)),
+ this,
+ SIGNAL(valueChanged(QString,TimedValue)));
+ }
+ else
+ subscriberInterface->subscribe(keys);
}
/// Forwards the unsubscribe request to the wire.
void ContextKitPlugin::unsubscribe(QSet<QString> keys)
{
- subscriberInterface->unsubscribe(keys);
+ if (newProtocol)
+ foreach (QString key, keys) {
+ connection->asyncCall(QDBusMessage::createMethodCall(busName,
+ keyToPath(key),
+ propertyIName,
+ "Unsubscribe"));
+ }
+ else
+ subscriberInterface->unsubscribe(keys);
}
/// Forwards value changes from the wire to the upper layer (Provider).
@@ -166,4 +247,44 @@ void ContextKitPlugin::onDBusValuesChanged(QMap<QString, QVariant> values)
emit valueChanged(key, values[key]);
}
+static TimedValue createTimedValue(const QList<QVariant> value, quint64 time)
+{
+ if (value.size() == 0)
+ return TimedValue(QVariant(), time);
+ else
+ return TimedValue(value.at(0), time);
+}
+
+void ContextKitPlugin::onNewValueChanged(QList<QVariant> value,
+ quint64 timestamp,
+ QDBusMessage message)
+{
+ emit valueChanged(pathToKey(message.path()), createTimedValue(value,
+ timestamp));
+}
+
+PendingSubscribeWatcher::PendingSubscribeWatcher(const QDBusPendingCall &call,
+ const QString &key,
+ QObject * parent) :
+ QDBusPendingCallWatcher(call, parent), key(key)
+{
+ sconnect(this, SIGNAL(finished(QDBusPendingCallWatcher *)),
+ this, SLOT(onFinished()));
+ sconnect(this, SIGNAL(finished(QDBusPendingCallWatcher *)),
+ this, SLOT(deleteLater()));
+}
+
+void PendingSubscribeWatcher::onFinished()
+{
+ QDBusPendingReply<QList<QVariant>, quint64> reply = *this;
+ if (reply.isError()) {
+ emit subscribeFailed(key, reply.error().message());
+ return;
+ }
+
+ emit valueChanged(key, createTimedValue(reply.argumentAt<0>(),
+ reply.argumentAt<1>()));
+ emit subscribeFinished(key);
+}
+
}
diff --git a/libcontextsubscriber/src/contextkitplugin.h b/libcontextsubscriber/src/contextkitplugin.h
index 5fd3b8d2..7566e3f5 100644
--- a/libcontextsubscriber/src/contextkitplugin.h
+++ b/libcontextsubscriber/src/contextkitplugin.h
@@ -27,8 +27,10 @@
#include "provider.h"
#include "iproviderplugin.h"
#include "asyncdbusinterface.h"
+#include "timedvalue.h"
#include <QString>
#include <QDBusConnection>
+#include <QDBusPendingCallWatcher>
#include <QDBusObjectPath>
#include <QSet>
#include <QVariant>
@@ -39,6 +41,26 @@ extern "C" {
}
namespace ContextSubscriber {
+class PendingSubscribeWatcher : public QDBusPendingCallWatcher
+{
+ Q_OBJECT;
+
+public:
+ PendingSubscribeWatcher(const QDBusPendingCall &call,
+ const QString &key,
+ QObject * parent = 0);
+private slots:
+ void onFinished();
+
+signals:
+ void subscribeFailed(QString, QString);
+ void valueChanged(QString, TimedValue);
+ void subscribeFinished(QString);
+
+private:
+ QString key;
+};
+
class ContextKitPlugin : public IProviderPlugin
{
Q_OBJECT
@@ -58,6 +80,9 @@ signals:
#endif
private slots:
+ void onNewValueChanged(QList<QVariant> value,
+ quint64 timestamp,
+ QDBusMessage message);
void onDBusValuesChanged(QMap<QString, QVariant> values);
void onDBusGetSubscriberFinished(QDBusObjectPath objectPath);
void onDBusGetSubscriberFailed(QDBusError err);
@@ -67,6 +92,11 @@ private slots:
void onProviderDisappeared();
private:
+ static QString keyToPath(QString key);
+ static QString pathToKey(QString key);
+
+ void reset();
+
QMap<QString, QVariant>& mergeNullsWithMap(QMap<QString, QVariant> &map, QStringList nulls) const;
DBusNameListener *providerListener; ///< Listens to provider's (dis)appearance over DBus
@@ -76,9 +106,13 @@ private:
QDBusConnection *connection; ///< The connection to DBus
QString busName; ///< The D-Bus service name of the ContextKit provider connected to
+ bool newProtocol; ///< The provider on D-Bus speaks the new protocol only.
+
static const QString managerIName; ///< org.freedesktop.ContextKit.Manager
static const QString subscriberIName; ///< org.freedesktop.ContextKit.Subscriber
static const QString managerPath; ///< /org/freedesktop/ContextKit/Manager
+ static const QString propertyIName; ///< org.maemo.contextkit.Property
+ static const QString corePrefix; ///< /org/maemo/contextkit/
};
diff --git a/libcontextsubscriber/src/handlesignalrouter.cpp b/libcontextsubscriber/src/handlesignalrouter.cpp
index 8d7da41c..aa9e6372 100644
--- a/libcontextsubscriber/src/handlesignalrouter.cpp
+++ b/libcontextsubscriber/src/handlesignalrouter.cpp
@@ -53,10 +53,10 @@ void HandleSignalRouter::onValueChanged(QString key)
handle->onValueChanged();
}
-void HandleSignalRouter::onSubscribeFinished(QString key)
+void HandleSignalRouter::onSubscribeFinished(Provider *provider, QString key)
{
PropertyHandle* handle = PropertyHandle::instance(key);
- handle->setSubscribeFinished();
+ handle->setSubscribeFinished(provider);
}
} // end namespace
diff --git a/libcontextsubscriber/src/handlesignalrouter.h b/libcontextsubscriber/src/handlesignalrouter.h
index 940ceb4c..59a45c6e 100644
--- a/libcontextsubscriber/src/handlesignalrouter.h
+++ b/libcontextsubscriber/src/handlesignalrouter.h
@@ -28,6 +28,8 @@
namespace ContextSubscriber {
+class Provider;
+
class HandleSignalRouter : public QObject
{
Q_OBJECT
@@ -36,7 +38,7 @@ public:
public slots:
void onValueChanged(QString key);
- void onSubscribeFinished(QString key);
+ void onSubscribeFinished(Provider *provider, QString key);
private:
HandleSignalRouter();
diff --git a/libcontextsubscriber/src/iproviderplugin.h b/libcontextsubscriber/src/iproviderplugin.h
index dcd4342c..d14ad48e 100644
--- a/libcontextsubscriber/src/iproviderplugin.h
+++ b/libcontextsubscriber/src/iproviderplugin.h
@@ -22,6 +22,8 @@
#ifndef IPROVIDERPLUGIN_H
#define IPROVIDERPLUGIN_H
+#include "timedvalue.h"
+
#include <QObject>
#include <QVariant>
@@ -43,8 +45,10 @@ signals:
void ready();
void failed(QString error);
void subscribeFinished(QString key);
+ void subscribeFinished(QString key, TimedValue timedvalue);
void subscribeFailed(QString failedKey, QString error);
void valueChanged(QString key, QVariant value);
+ void valueChanged(QString key, TimedValue timedvalue);
};
typedef IProviderPlugin* (*PluginFactoryFunc)(QString constructionString);
diff --git a/libcontextsubscriber/src/propertyhandle.cpp b/libcontextsubscriber/src/propertyhandle.cpp
index f0348e71..73a88877 100644
--- a/libcontextsubscriber/src/propertyhandle.cpp
+++ b/libcontextsubscriber/src/propertyhandle.cpp
@@ -73,12 +73,8 @@ bool PropertyHandle::typeCheckEnabled = false;
*/
PropertyHandle::PropertyHandle(const QString& key)
- : myProvider(0), myInfo(0), subscribeCount(0), subscribePending(true), myKey(key)
+ : myInfo(0), subscribeCount(0), myKey(key)
{
- // Note: We set subscribePending to true, assuming that the
- // intention of the upper layer is to subscribe construction time.
- // If this intention is changed, changes are needed here as well.
-
// Read the information about the provider. This needs to be
// done before calling updateProvider.
myInfo = new ContextPropertyInfo(myKey, this);
@@ -90,6 +86,9 @@ PropertyHandle::PropertyHandle(const QString& key)
// Start listening for the context commander, and also initiate a
// NameHasOwner check.
+ // Because of the waitForSubscription() feature, we immediately need to
+ // subscribe to the real providers when the commander presence becomes
+ // known. So, these connect()s need to be synchronous (not queued).
sconnect(commanderListener, SIGNAL(nameAppeared()),
this, SLOT(updateProvider()));
sconnect(commanderListener, SIGNAL(nameDisappeared()),
@@ -127,55 +126,43 @@ void PropertyHandle::setTypeCheck(bool typeCheck)
/// renews the subscriptions.
void PropertyHandle::updateProvider()
{
- Provider *newProvider;
+ QList<Provider*> newProviders;
contextDebug() << F_PLUGINS;
if (commandingEnabled && commanderListener->isServicePresent() == DBusNameListener::Present) {
// If commander is present it should be able to override the
// property, so connect to it.
- newProvider = Provider::instance(commanderInfo);
+ newProviders << Provider::instance(commanderInfo);
+ Provider::instance(commanderInfo)->clearValues();
} else {
// The myInfo object doesn't have to be re-created, because it
// just routes the function calls to a registry backend.
- if (myInfo->provided()) {
- // If myInfo knows the current provider which should be
- // connected to, connect to it.
- contextDebug() << F_PLUGINS << "Key exists";
- QList<ContextProviderInfo> providers = myInfo->providers();
- if (providers.size() > 1)
- contextCritical() << "multi-process not implemented yet";
- else if (providers.size() == 0)
- contextCritical() << "property provided() but no providers() is empty";
-
- newProvider = Provider::instance(providers[0]);
- } else {
- // Otherwise we keep the pointer to the old provider.
- // This way, we can still continue communicating with the
- // provider even though the key is no longer in the
- // registry.
- contextDebug() << F_PLUGINS << "Key doesn't exist -> keep old provider info";
-
- newProvider = myProvider;
-
- if (newProvider == 0) {
- // This is the first place where we can know that the
- // provider for this property doesn't exist. We
- // shouldn't block waiting for subscription for such a property.
- subscribePending = false;
- }
- }
+ foreach (ContextProviderInfo info, myInfo->providers())
+ newProviders << Provider::instance(info);
+ contextDebug() << newProviders.size() << "providers for" << myKey;
}
-
- if (newProvider != myProvider && subscribeCount > 0) {
- // The provider has changed and ContextProperty classes are subscribed to this handle.
- // Unsubscribe from the old provider
- if (myProvider) myProvider->unsubscribe(myKey);
- // And subscribe to the new provider
- if (newProvider) subscribePending = newProvider->subscribe(myKey);
+ if (subscribeCount > 0) {
+ // Unsubscribe from old providers and subscribe to the new ones.
+ foreach (Provider *oldprovider, myProviders)
+ oldprovider->unsubscribe(myKey);
+ pendingSubscriptions.clear();
+ foreach (Provider *newprovider, newProviders)
+ if (newprovider->subscribe(myKey))
+ pendingSubscriptions << newprovider;
}
+ myProviders = newProviders;
+ // If all subscriptions succeeded immediately, then we have to trigger
+ // recomputing the value now. Otherwise we rely on the
+ // subscribeFinished signal.
+ if (subscribeCount > 0 && pendingSubscriptions.empty())
+ onValueChanged();
+}
- myProvider = newProvider;
+/// Sets \c subscribePending to false.
+void PropertyHandle::setSubscribeFinished(Provider *provider)
+{
+ pendingSubscriptions.remove(provider);
}
/// Increase the \c subscribeCount of this context property and
@@ -186,8 +173,11 @@ void PropertyHandle::subscribe()
QMutexLocker locker(&subscribeCountLock);
++subscribeCount;
- if (subscribeCount == 1 && myProvider != 0) {
- subscribePending = myProvider->subscribe(myKey);
+ if (subscribeCount == 1) {
+ pendingSubscriptions.clear();
+ foreach (Provider *provider, myProviders)
+ if (provider->subscribe(myKey))
+ pendingSubscriptions << provider;
}
}
@@ -198,18 +188,13 @@ void PropertyHandle::unsubscribe()
{
QMutexLocker locker(&subscribeCountLock);
--subscribeCount;
- if (subscribeCount == 0 && myProvider != 0) {
- subscribePending = false;
- myProvider->unsubscribe(myKey);
+ if (subscribeCount == 0) {
+ pendingSubscriptions.clear();
+ foreach (Provider *provider, myProviders)
+ provider->unsubscribe(myKey);
}
}
-/// Sets \c subscribePending to false.
-void PropertyHandle::setSubscribeFinished()
-{
- subscribePending = false;
-}
-
QString PropertyHandle::key() const
{
return myKey;
@@ -223,7 +208,14 @@ QVariant PropertyHandle::value() const
bool PropertyHandle::isSubscribePending() const
{
- return subscribePending;
+ // We wait until commander presence is unknown ...
+ if (commanderListener->isServicePresent() == DBusNameListener::Unknown)
+ return true;
+ // ... or until we get some value ...
+ if (!myValue.isNull())
+ return false;
+ // ... or all pending subscriptions finished.
+ return pendingSubscriptions.size() != 0;
}
/// Used by the \c HandleSignalRouter to change the value of the
@@ -233,8 +225,22 @@ bool PropertyHandle::isSubscribePending() const
/// valueChanged() signal.
void PropertyHandle::onValueChanged()
{
- // FIXME: implement multiprocess here
- QVariant newValue = myProvider->get(myKey).value;
+ bool found = false;
+ TimedValue latest = QVariant();
+
+ foreach (Provider *provider, myProviders) {
+ TimedValue current = provider->get(myKey);
+ if (current.value.isNull())
+ continue;
+ if (!found) {
+ found = true;
+ latest = current;
+ } else if (latest < current)
+ latest = current;
+ }
+ QVariant newValue;
+ if (found)
+ newValue = latest.value;
if (typeCheckEnabled // type checks enabled
&& !newValue.isNull() // variable is non-null
@@ -253,7 +259,7 @@ void PropertyHandle::onValueChanged()
}
if (!checked) {
- contextCritical() << "Provider error, bad type for " << myKey <<
+ contextCritical() << "Provider error, bad type for " << myKey <<
"wanted:" << myType << "got:" << newValue.typeName();
return;
}
diff --git a/libcontextsubscriber/src/propertyhandle.h b/libcontextsubscriber/src/propertyhandle.h
index a6cfb587..e6f06897 100644
--- a/libcontextsubscriber/src/propertyhandle.h
+++ b/libcontextsubscriber/src/propertyhandle.h
@@ -52,7 +52,7 @@ public:
static PropertyHandle* instance(const QString& key);
void onValueChanged();
- void setSubscribeFinished();
+ void setSubscribeFinished(Provider *provider);
static void ignoreCommander();
static void setTypeCheck(bool typeCheck);
@@ -65,12 +65,11 @@ private slots:
private:
PropertyHandle(const QString& key);
- Provider *myProvider; ///< Provider of this property
+ QSet<Provider*> pendingSubscriptions; ///< Providers pending subscription
+ QList<Provider*> myProviders; ///< Providers of this property
ContextPropertyInfo *myInfo; ///< Metadata for this property
unsigned int subscribeCount; ///< Number of subscribed ContextProperty objects subscribed to this property
QMutex subscribeCountLock;
- bool subscribePending; ///< True when the subscription has been started, but hasn't been finished yet
- /// (used by the waitForSubscription() feature)
QString myKey; ///< Key of this property
mutable QReadWriteLock valueLock;
QVariant myValue; ///< Current value of this property
diff --git a/libcontextsubscriber/src/provider.cpp b/libcontextsubscriber/src/provider.cpp
index ef3ce984..dff7adb4 100644
--- a/libcontextsubscriber/src/provider.cpp
+++ b/libcontextsubscriber/src/provider.cpp
@@ -34,11 +34,6 @@
namespace ContextSubscriber {
-TimedValue::TimedValue(const QVariant &value) : value(value)
-{
- clock_gettime(CLOCK_MONOTONIC, &time);
-}
-
/*!
\class IProviderPlugin
\brief Interface for provider plugins.
@@ -175,6 +170,8 @@ void Provider::constructPlugin()
// Connect the signal of changing values to the class who handles it
HandleSignalRouter* handleSignalRouter = HandleSignalRouter::instance();
+ sconnect(plugin, SIGNAL(valueChanged(QString, TimedValue)),
+ this, SLOT(onPluginValueChanged(QString, TimedValue)));
sconnect(plugin, SIGNAL(valueChanged(QString, QVariant)),
this, SLOT(onPluginValueChanged(QString, QVariant)));
sconnect(this, SIGNAL(valueChanged(QString)),
@@ -185,12 +182,18 @@ void Provider::constructPlugin()
sconnect(plugin, SIGNAL(failed(QString)),
this, SLOT(onPluginFailed(QString)));
+ // The following signals are queued, because a plugin might emit
+ // subscribeFinished() right in the subscribe() call.
+ qRegisterMetaType<TimedValue>("TimedValue");
+ sconnect(plugin, SIGNAL(subscribeFinished(QString, TimedValue)),
+ this, SLOT(onPluginSubscribeFinished(QString, TimedValue)),
+ Qt::QueuedConnection);
sconnect(plugin, SIGNAL(subscribeFinished(QString)),
this, SLOT(onPluginSubscribeFinished(QString)), Qt::QueuedConnection);
sconnect(plugin, SIGNAL(subscribeFailed(QString, QString)),
this, SLOT(onPluginSubscribeFailed(QString, QString)), Qt::QueuedConnection);
- sconnect(this, SIGNAL(subscribeFinished(QString)),
- handleSignalRouter, SLOT(onSubscribeFinished(QString)));
+ sconnect(this, SIGNAL(subscribeFinished(Provider *,QString)),
+ handleSignalRouter, SLOT(onSubscribeFinished(Provider *,QString)));
}
/// Updates \c pluginState to \c READY and requests subscription for
@@ -210,6 +213,13 @@ void Provider::onPluginReady()
handleSubscribes();
}
+/// Clears the cached values for this provider. This is used when the
+/// provider instance is (re)connected to the commander.
+void Provider::clearValues()
+{
+ values.clear();
+}
+
/// Updates \c pluginState to \c FAILED and signals subscribeFinished
/// for keys we are trying to subscribe to.
void Provider::onPluginFailed(QString error)
@@ -229,10 +239,17 @@ void Provider::signalSubscribeFinished(QString key)
{
QMutexLocker lock(&subscribeLock);
if (subscribedKeys.contains(key))
- emit subscribeFinished(key);
+ emit subscribeFinished(this, key);
}
/// Forwards the call to \c signalSubscribeFinished.
+void Provider::onPluginSubscribeFinished(QString key, TimedValue value)
+{
+ signalSubscribeFinished(key);
+ onPluginValueChanged(key, value);
+}
+
+/// Deprecated.
void Provider::onPluginSubscribeFinished(QString key)
{
contextDebug() << key;
@@ -318,7 +335,7 @@ void Provider::handleSubscribes()
contextDebug() << "Plugin init has failed";
if (toSubscribe.size() > 0)
foreach (QString key, toSubscribe)
- emit subscribeFinished(key);
+ emit subscribeFinished(this, key);
toSubscribe.clear();
toUnsubscribe.clear();
break;
@@ -332,6 +349,21 @@ void Provider::handleSubscribes()
/// Forwards the \c newValue for \c key received from the plugin to
/// the upper layers via \c HandleSignalRouter.
+void Provider::onPluginValueChanged(QString key, TimedValue newValue)
+{
+ QMutexLocker lock(&subscribeLock);
+ if (subscribedKeys.contains(key)) {
+ // FIXME: try out if everything works with lock.unlock() here
+ values.insert(key, newValue);
+ emit valueChanged(key);
+ }
+ else
+ contextWarning() << "Received a property not subscribed to:" << key;
+}
+
+/// Deprecated: plugins should use the variant taking a TimedValue.
+/// Forwards the \c newValue for \c key received from the plugin to
+/// the upper layers via \c HandleSignalRouter.
void Provider::onPluginValueChanged(QString key, QVariant newValue)
{
QMutexLocker lock(&subscribeLock);
diff --git a/libcontextsubscriber/src/provider.h b/libcontextsubscriber/src/provider.h
index cacfc4d8..482d678b 100644
--- a/libcontextsubscriber/src/provider.h
+++ b/libcontextsubscriber/src/provider.h
@@ -24,12 +24,12 @@
#include "queuedinvoker.h"
#include "contextproviderinfo.h"
+#include "timedvalue.h"
#include <QObject>
#include <QDBusConnection>
#include <QSet>
#include <QMutex>
-#include <time.h>
class ContextPropertyInfo;
@@ -41,14 +41,6 @@ class DBusNameListener;
class ManagerInterface;
class IProviderPlugin;
-struct TimedValue
-{
- struct timespec time;
- QVariant value;
- TimedValue(const QVariant &value);
-// future bool operator<(const TimedValue &other);
-};
-
class Provider : public QueuedInvoker
{
Q_OBJECT
@@ -58,17 +50,20 @@ public:
bool subscribe(const QString &key);
void unsubscribe(const QString &key);
TimedValue get(const QString &key) const;
+ void clearValues();
signals:
- void subscribeFinished(QString key);
+ void subscribeFinished(Provider *provider, QString key);
void valueChanged(QString key);
private slots:
void onPluginReady();
void onPluginFailed(QString error);
void onPluginSubscribeFinished(QString key);
+ void onPluginSubscribeFinished(QString key, TimedValue value);
void onPluginSubscribeFailed(QString failedKey, QString error);
void onPluginValueChanged(QString key, QVariant newValue);
+ void onPluginValueChanged(QString key, TimedValue newValue);
private:
enum PluginState { INITIALIZING, READY, FAILED };
diff --git a/libcontextsubscriber/src/timedvalue.h b/libcontextsubscriber/src/timedvalue.h
new file mode 100644
index 00000000..15a9a404
--- /dev/null
+++ b/libcontextsubscriber/src/timedvalue.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008, 2009 Nokia Corporation.
+ *
+ * Contact: Marius Vollmer <marius.vollmer@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.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TIMEDVALUE_H
+#define TIMEDVALUE_H
+
+#include <time.h>
+#include <QVariant>
+
+namespace ContextSubscriber {
+
+struct TimedValue
+{
+ quint64 time;
+ QVariant value;
+
+ TimedValue() : time(0), value(QVariant())
+ { }
+ TimedValue(const QVariant &value, quint64 time) : time(time), value(value)
+ { }
+ TimedValue(const QVariant &value) : value(value)
+ {
+ struct timespec t;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ time = t.tv_sec * Q_UINT64_C(1000000000) + t.tv_nsec;
+ }
+ bool operator<(const TimedValue &other)
+ {
+ return time < other.time;
+ }
+};
+
+}
+
+#endif
diff --git a/libcontextsubscriber/unit-tests/handlesignalrouter/propertyhandle.h b/libcontextsubscriber/unit-tests/handlesignalrouter/propertyhandle.h
index bde228f6..24e243e2 100644
--- a/libcontextsubscriber/unit-tests/handlesignalrouter/propertyhandle.h
+++ b/libcontextsubscriber/unit-tests/handlesignalrouter/propertyhandle.h
@@ -31,6 +31,8 @@
namespace ContextSubscriber {
+class Provider;
+
class PropertyHandle : public QObject
{
Q_OBJECT
@@ -38,12 +40,12 @@ class PropertyHandle : public QObject
public:
static PropertyHandle* instance(const QString& key);
void onValueChanged();
- void setSubscribeFinished();
+ void setSubscribeFinished(Provider *);
signals:
// For tests
void onValueChangedCalled(QString);
- void setSubscribeFinishedCalled(QString);
+ void setSubscribeFinishedCalled(Provider *,QString);
public:
PropertyHandle(const QString& key);
diff --git a/libcontextsubscriber/unit-tests/handlesignalrouter/testhandlesignalrouter.cpp b/libcontextsubscriber/unit-tests/handlesignalrouter/testhandlesignalrouter.cpp
index a7073d34..3f674634 100644
--- a/libcontextsubscriber/unit-tests/handlesignalrouter/testhandlesignalrouter.cpp
+++ b/libcontextsubscriber/unit-tests/handlesignalrouter/testhandlesignalrouter.cpp
@@ -78,9 +78,9 @@ void PropertyHandle::onValueChanged()
emit onValueChangedCalled(myKey);
}
-void PropertyHandle::setSubscribeFinished()
+void PropertyHandle::setSubscribeFinished(Provider *prov)
{
- emit setSubscribeFinishedCalled(myKey);
+ emit setSubscribeFinishedCalled(prov, myKey);
}
PropertyHandle* PropertyHandle::instance(const QString& key)
@@ -145,14 +145,14 @@ void HandleSignalRouterUnitTests::routingSignals()
QSignalSpy spy1(mockHandleOne, SIGNAL(onValueChangedCalled(QString)));
QSignalSpy spy2(mockHandleTwo, SIGNAL(onValueChangedCalled(QString)));
QSignalSpy spy3(mockHandleThree, SIGNAL(onValueChangedCalled(QString)));
- QSignalSpy sspy1(mockHandleOne, SIGNAL(setSubscribeFinishedCalled(QString)));
- QSignalSpy sspy2(mockHandleTwo, SIGNAL(setSubscribeFinishedCalled(QString)));
- QSignalSpy sspy3(mockHandleThree, SIGNAL(setSubscribeFinishedCalled(QString)));
+ QSignalSpy sspy1(mockHandleOne, SIGNAL(setSubscribeFinishedCalled(Provider *, QString)));
+ QSignalSpy sspy2(mockHandleTwo, SIGNAL(setSubscribeFinishedCalled(Provider *, QString)));
+ QSignalSpy sspy3(mockHandleThree, SIGNAL(setSubscribeFinishedCalled(Provider *, QString)));
// Test:
// Send a signal to the HandleSignalRouter
handleSignalRouter->onValueChanged("Property.One");
- handleSignalRouter->onSubscribeFinished("Property.One");
+ handleSignalRouter->onSubscribeFinished(0, "Property.One");
// Expected results:
// The mockHandleOne.setValue was called
@@ -163,8 +163,8 @@ void HandleSignalRouterUnitTests::routingSignals()
QCOMPARE(sspy1.count(), 1);
parameters = sspy1.takeFirst();
- QCOMPARE(parameters.size(), 1);
- QCOMPARE(parameters.at(0), QVariant("Property.One"));
+ QCOMPARE(parameters.size(), 2);
+ QCOMPARE(parameters.at(1), QVariant("Property.One"));
// The setValue of other mock handles were not called
QCOMPARE(spy2.count(), 0);
@@ -175,7 +175,7 @@ void HandleSignalRouterUnitTests::routingSignals()
// Test:
// Send a signal to the HandleSignalRouter
handleSignalRouter->onValueChanged("Property.Two");
- handleSignalRouter->onSubscribeFinished("Property.Two");
+ handleSignalRouter->onSubscribeFinished(0, "Property.Two");
// Expected results:
// The mockHandleTwo.setValue was called
@@ -185,8 +185,8 @@ void HandleSignalRouterUnitTests::routingSignals()
QCOMPARE(parameters.size(), 1);
QCOMPARE(parameters.at(0), QVariant("Property.Two"));
parameters = sspy2.takeFirst();
- QCOMPARE(parameters.size(), 1);
- QCOMPARE(parameters.at(0), QVariant("Property.Two"));
+ QCOMPARE(parameters.size(), 2);
+ QCOMPARE(parameters.at(1), QVariant("Property.Two"));
// The setValue of other mock handles were not called
QCOMPARE(spy1.count(), 0);
QCOMPARE(spy3.count(), 0);
diff --git a/libcontextsubscriber/unit-tests/propertyhandle/.gitignore b/libcontextsubscriber/unit-tests/propertyhandle/.gitignore
index a0f647c6..e59a3396 100644
--- a/libcontextsubscriber/unit-tests/propertyhandle/.gitignore
+++ b/libcontextsubscriber/unit-tests/propertyhandle/.gitignore
@@ -5,3 +5,5 @@ logging.cpp
logging.h
loggingfeatures.h
contextproviderinfo.h
+timedvalue.h
+
diff --git a/libcontextsubscriber/unit-tests/propertyhandle/Makefile.am b/libcontextsubscriber/unit-tests/propertyhandle/Makefile.am
index 367b3c30..5fbc5acd 100644
--- a/libcontextsubscriber/unit-tests/propertyhandle/Makefile.am
+++ b/libcontextsubscriber/unit-tests/propertyhandle/Makefile.am
@@ -13,7 +13,8 @@ COVERAGE_FILES = propertyhandle.cpp
AM_CXXFLAGS = $(QtDBus_CFLAGS) '-DDEFAULT_CONTEXT_PROVIDERS="@datadir@/contextkit/providers/"'
AM_LDFLAGS = $(QtDBus_LIBS)
# copy these files from the real source
-FROM_SOURCE = propertyhandle.cpp propertyhandle.h loggingfeatures.h contextproviderinfo.h
+FROM_SOURCE = propertyhandle.cpp propertyhandle.h loggingfeatures.h \
+ contextproviderinfo.h timedvalue.h
FROM_SOURCE_DIR = $(srcdir)/../../src
LDADD =
include $(top_srcdir)/am/tests.am
diff --git a/libcontextsubscriber/unit-tests/propertyhandle/provider.h b/libcontextsubscriber/unit-tests/propertyhandle/provider.h
index 850e6cac..15da4f8c 100644
--- a/libcontextsubscriber/unit-tests/propertyhandle/provider.h
+++ b/libcontextsubscriber/unit-tests/propertyhandle/provider.h
@@ -25,23 +25,15 @@
#define PROVIDER_H
#include "contextproviderinfo.h"
+#include "timedvalue.h"
#include <QObject>
#include <QDBusConnection>
#include <QSet>
#include <QString>
-#include <time.h>
namespace ContextSubscriber {
-struct TimedValue
-{
- struct timespec time;
- QVariant value;
- TimedValue(const QVariant &value);
-// future bool operator<(const TimedValue &other);
-};
-
class Provider : public QObject
{
Q_OBJECT
@@ -51,6 +43,7 @@ public:
bool subscribe(const QString &key);
void unsubscribe(const QString &key);
TimedValue get(const QString &key) const;
+ void clearValues();
signals:
void subscribeFinished(QString key);
diff --git a/libcontextsubscriber/unit-tests/propertyhandle/testpropertyhandle.cpp b/libcontextsubscriber/unit-tests/propertyhandle/testpropertyhandle.cpp
index 9ccbaf8e..44f33264 100644
--- a/libcontextsubscriber/unit-tests/propertyhandle/testpropertyhandle.cpp
+++ b/libcontextsubscriber/unit-tests/propertyhandle/testpropertyhandle.cpp
@@ -100,12 +100,6 @@ Provider* mockProvider;
Provider* mockCommanderProvider;
DBusNameListener* mockDBusNameListener;
-// Mock implementation of TimedValue
-TimedValue::TimedValue(const QVariant &value) : value(value)
-{
- clock_gettime(CLOCK_MONOTONIC, &time);
-}
-
// Mock implementation of the Provider
int Provider::instanceCount = 0;
QStringList Provider::instancePluginNames;
@@ -153,6 +147,11 @@ void Provider::unsubscribe(const QString& key)
unsubscribeProviderNames << myName;
}
+void Provider::clearValues()
+{
+ cachedValue = TimedValue(QVariant());
+}
+
void Provider::setValue(const QString &key, const QVariant &value)
{
cachedValue = TimedValue(value);
@@ -374,7 +373,7 @@ void PropertyHandleUnitTests::subscriptionPendingAndFinished()
QVERIFY(propertyHandle->isSubscribePending());
// finished
- propertyHandle->setSubscribeFinished();
+ propertyHandle->setSubscribeFinished(mockProvider);
// Expected results:
// The subscription is no longer marked as pending
@@ -868,9 +867,12 @@ void PropertyHandleUnitTests::commandingDisabled()
emit mockDBusNameListener->nameAppeared();
// Expected results:
- // The PropertyHandle ignores the Commander
- QCOMPARE(Provider::unsubscribeCount, 0);
- QCOMPARE(Provider::subscribeCount, 0);
+ // The PropertyHandle unsubscribes from and resubscribes to the same key,
+ // practically ignoring commander appearance.
+ QCOMPARE(Provider::unsubscribeCount, 1);
+ QCOMPARE(Provider::subscribeCount, 1);
+ QVERIFY(Provider::subscribeKeys == Provider::unsubscribeKeys);
+ QVERIFY(Provider::subscribeProviderNames == Provider::unsubscribeProviderNames);
// Setup:
// Clear the logs from the subscription
@@ -882,9 +884,11 @@ void PropertyHandleUnitTests::commandingDisabled()
emit mockDBusNameListener->nameDisappeared();
// Expected results:
- // The PropertyHandle ignores the Commander
- QCOMPARE(Provider::unsubscribeCount, 0);
- QCOMPARE(Provider::subscribeCount, 0);
+ // Same thing as above.
+ QCOMPARE(Provider::unsubscribeCount, 1);
+ QCOMPARE(Provider::subscribeCount, 1);
+ QVERIFY(Provider::subscribeKeys == Provider::unsubscribeKeys);
+ QVERIFY(Provider::subscribeProviderNames == Provider::unsubscribeProviderNames);
}
} // end namespace
diff --git a/libcontextsubscriber/unit-tests/provider/.gitignore b/libcontextsubscriber/unit-tests/provider/.gitignore
index 6d1bc189..b9ab0625 100644
--- a/libcontextsubscriber/unit-tests/provider/.gitignore
+++ b/libcontextsubscriber/unit-tests/provider/.gitignore
@@ -6,3 +6,4 @@ sconnect.h
logging.cpp
logging.h
loggingfeatures.h
+timedvalue.h
diff --git a/libcontextsubscriber/unit-tests/provider/Makefile.am b/libcontextsubscriber/unit-tests/provider/Makefile.am
index d672092e..11f664ec 100644
--- a/libcontextsubscriber/unit-tests/provider/Makefile.am
+++ b/libcontextsubscriber/unit-tests/provider/Makefile.am
@@ -15,7 +15,7 @@ AM_CXXFLAGS = $(QtDBus_CFLAGS) \
AM_LDFLAGS = $(QtDBus_LIBS)
# copy these files from the real source
FROM_SOURCE = provider.cpp provider.h iproviderplugin.h \
- loggingfeatures.h contextproviderinfo.h
+ loggingfeatures.h contextproviderinfo.h timedvalue.h
FROM_SOURCE_DIR = $(srcdir)/../../src
LDADD =
include $(top_srcdir)/am/tests.am
diff --git a/libcontextsubscriber/unit-tests/provider/contextkitplugin.h b/libcontextsubscriber/unit-tests/provider/contextkitplugin.h
index 39159c35..5d91b360 100644
--- a/libcontextsubscriber/unit-tests/provider/contextkitplugin.h
+++ b/libcontextsubscriber/unit-tests/provider/contextkitplugin.h
@@ -24,11 +24,13 @@
#ifndef CONTEXTKITPLUGIN_H
#define CONTEXTKITPLUGIN_H
+#include "iproviderplugin.h"
+#include "timedvalue.h"
+
#include <QString>
#include <QDBusConnection>
#include <QSet>
#include <QVariant>
-#include "iproviderplugin.h"
extern "C" {
ContextSubscriber::IProviderPlugin* contextKitPluginFactory(QString constructionString);
@@ -47,8 +49,10 @@ signals:
void ready();
void failed(QString error);
void subscribeFinished(QString key);
+ void subscribeFinished(QString key, TimedValue value);
void subscribeFailed(QString failedKey, QString error);
void valueChanged(QString key, QVariant value);
+ void valueChanged(QString key, TimedValue value);
private:
QSet<QString> subscribeRequested;
diff --git a/libcontextsubscriber/unit-tests/provider/handlesignalrouter.h b/libcontextsubscriber/unit-tests/provider/handlesignalrouter.h
index 070fa440..75ae2628 100644
--- a/libcontextsubscriber/unit-tests/provider/handlesignalrouter.h
+++ b/libcontextsubscriber/unit-tests/provider/handlesignalrouter.h
@@ -38,7 +38,7 @@ public:
public slots:
void onValueChanged(QString key);
- void onSubscribeFinished(QString key);
+ void onSubscribeFinished(Provider *provider, QString key);
};
} // end namespace
diff --git a/libcontextsubscriber/unit-tests/provider/testprovider.cpp b/libcontextsubscriber/unit-tests/provider/testprovider.cpp
index d51c4b0a..c39d45cc 100644
--- a/libcontextsubscriber/unit-tests/provider/testprovider.cpp
+++ b/libcontextsubscriber/unit-tests/provider/testprovider.cpp
@@ -74,7 +74,7 @@ void HandleSignalRouter::onValueChanged(QString key)
{
}
-void HandleSignalRouter::onSubscribeFinished(QString key)
+void HandleSignalRouter::onSubscribeFinished(Provider *provider, QString key)
{
}
@@ -283,17 +283,18 @@ void ProviderUnitTests::pluginSubscriptionFinishes()
emit pluginInstances[conStr]->ready(); // set the plugin to ready
provider->callAllMethodsInQueue();
- QSignalSpy spy(provider, SIGNAL(subscribeFinished(QString)));
+ QSignalSpy spy(provider, SIGNAL(subscribeFinished(Provider *, QString)));
provider->subscribe("test.key1");
provider->subscribe("test.key2");
provider->callAllMethodsInQueue();
emit pluginInstances[conStr]->subscribeFinished("test.key1");
emit pluginInstances[conStr]->subscribeFailed("test.key2", "error");
QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); // signal delivery is queued
- QCOMPARE((QList<QList<QVariant> >)spy,
- QList<QList<QVariant> >()
- << (QList<QVariant>() << "test.key1")
- << (QList<QVariant>() << "test.key2"));
+ QCOMPARE(spy.size(), 2);
+ QCOMPARE(spy[0].size(), 2);
+ QCOMPARE(spy[1].size(), 2);
+ QCOMPARE(spy[0][1], QVariant("test.key1"));
+ QCOMPARE(spy[1][1], QVariant("test.key2"));
}
void ProviderUnitTests::pluginValueChanges()
diff --git a/libcontextsubscriber/update-contextkit-providers/Makefile.am b/libcontextsubscriber/update-contextkit-providers/Makefile.am
index b0524b7e..4dde0332 100644
--- a/libcontextsubscriber/update-contextkit-providers/Makefile.am
+++ b/libcontextsubscriber/update-contextkit-providers/Makefile.am
@@ -10,9 +10,9 @@ AM_LDFLAGS = $(QtXml_LIBS) $(QtCore_LIBS)
# library dependency hack for seamless make in update-contextkit-providers/
update_contextkit_providers_LDADD = ../src/libcontextsubscriber.la
-../src/libcontextsubscriber.la:
+../src/libcontextsubscriber.la: FORCE
$(MAKE) -C ../src libcontextsubscriber.la
-.PHONY: ../src/libcontextsubscriber.la
+.PHONY: FORCE
# moccing
# Note: enable these 2 lines when there is something to mock
diff --git a/m4/dolt.m4 b/m4/dolt.m4
new file mode 100644
index 00000000..8f94582f
--- /dev/null
+++ b/m4/dolt.m4
@@ -0,0 +1,177 @@
+dnl dolt, a replacement for libtool
+dnl Copyright © 2007-2008 Josh Triplett <josh@freedesktop.org>
+dnl Copying and distribution of this file, with or without modification,
+dnl are permitted in any medium without royalty provided the copyright
+dnl notice and this notice are preserved.
+dnl
+dnl To use dolt, invoke the DOLT macro immediately after the libtool macros.
+dnl Optionally, copy this file into acinclude.m4, to avoid the need to have it
+dnl installed when running autoconf on your project.
+
+AC_DEFUN([DOLT], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+# dolt, a replacement for libtool
+# Josh Triplett <josh@freedesktop.org>
+AC_PATH_PROG(DOLT_BASH, bash)
+AC_MSG_CHECKING([if dolt supports this host])
+dolt_supported=yes
+if test x$DOLT_BASH = x; then
+ dolt_supported=no
+fi
+if test x$GCC != xyes; then
+ dolt_supported=no
+fi
+case $host in
+i?86-*-linux*|x86_64-*-linux*|powerpc-*-linux* \
+|amd64-*-freebsd*|i?86-*-freebsd*|ia64-*-freebsd*)
+ pic_options='-fPIC'
+ ;;
+i?86-apple-darwin*)
+ pic_options='-fno-common'
+ ;;
+*)
+ dolt_supported=no
+ ;;
+esac
+if test x$dolt_supported = xno ; then
+ AC_MSG_RESULT([no, falling back to libtool])
+ LTCOMPILE='$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(COMPILE)'
+ LTCXXCOMPILE='$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXXCOMPILE)'
+else
+ AC_MSG_RESULT([yes, replacing libtool])
+
+dnl Start writing out doltcompile.
+ cat <<__DOLTCOMPILE__EOF__ >doltcompile
+#!$DOLT_BASH
+__DOLTCOMPILE__EOF__
+ cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
+args=("$[]@")
+for ((arg=0; arg<${#args@<:@@@:>@}; arg++)) ; do
+ if test x"${args@<:@$arg@:>@}" = x-o ; then
+ objarg=$((arg+1))
+ break
+ fi
+done
+if test x$objarg = x ; then
+ echo 'Error: no -o on compiler command line' 1>&2
+ exit 1
+fi
+lo="${args@<:@$objarg@:>@}"
+obj="${lo%.lo}"
+if test x"$lo" = x"$obj" ; then
+ echo "Error: libtool object file name \"$lo\" does not end in .lo" 1>&2
+ exit 1
+fi
+objbase="${obj##*/}"
+__DOLTCOMPILE__EOF__
+
+dnl Write out shared compilation code.
+ if test x$enable_shared = xyes; then
+ cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
+libobjdir="${obj%$objbase}.libs"
+if test ! -d "$libobjdir" ; then
+ mkdir_out="$(mkdir "$libobjdir" 2>&1)"
+ mkdir_ret=$?
+ if test "$mkdir_ret" -ne 0 && test ! -d "$libobjdir" ; then
+ echo "$mkdir_out" 1>&2
+ exit $mkdir_ret
+ fi
+fi
+pic_object="$libobjdir/$objbase.o"
+args@<:@$objarg@:>@="$pic_object"
+__DOLTCOMPILE__EOF__
+ cat <<__DOLTCOMPILE__EOF__ >>doltcompile
+"\${args@<:@@@:>@}" $pic_options -DPIC || exit \$?
+__DOLTCOMPILE__EOF__
+ fi
+
+dnl Write out static compilation code.
+dnl Avoid duplicate compiler output if also building shared objects.
+ if test x$enable_static = xyes; then
+ cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
+non_pic_object="$obj.o"
+args@<:@$objarg@:>@="$non_pic_object"
+__DOLTCOMPILE__EOF__
+ if test x$enable_shared = xyes; then
+ cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
+"${args@<:@@@:>@}" >/dev/null 2>&1 || exit $?
+__DOLTCOMPILE__EOF__
+ else
+ cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
+"${args@<:@@@:>@}" || exit $?
+__DOLTCOMPILE__EOF__
+ fi
+ fi
+
+dnl Write out the code to write the .lo file.
+dnl The second line of the .lo file must match "^# Generated by .*libtool"
+ cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
+{
+echo "# $lo - a libtool object file"
+echo "# Generated by doltcompile, not libtool"
+__DOLTCOMPILE__EOF__
+
+ if test x$enable_shared = xyes; then
+ cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
+echo "pic_object='.libs/${objbase}.o'"
+__DOLTCOMPILE__EOF__
+ else
+ cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
+echo pic_object=none
+__DOLTCOMPILE__EOF__
+ fi
+
+ if test x$enable_static = xyes; then
+ cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
+echo "non_pic_object='${objbase}.o'"
+__DOLTCOMPILE__EOF__
+ else
+ cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
+echo non_pic_object=none
+__DOLTCOMPILE__EOF__
+ fi
+
+ cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
+} > "$lo"
+__DOLTCOMPILE__EOF__
+
+dnl Done writing out doltcompile; substitute it for libtool compilation.
+ chmod +x doltcompile
+ LTCOMPILE='$(top_builddir)/doltcompile $(COMPILE)'
+ LTCXXCOMPILE='$(top_builddir)/doltcompile $(CXXCOMPILE)'
+
+dnl automake ignores LTCOMPILE and LTCXXCOMPILE when it has separate CFLAGS for
+dnl a target, so write out a libtool wrapper to handle that case.
+dnl Note that doltlibtool does not handle inferred tags or option arguments
+dnl without '=', because automake does not use them.
+ cat <<__DOLTLIBTOOL__EOF__ > doltlibtool
+#!$DOLT_BASH
+__DOLTLIBTOOL__EOF__
+ cat <<'__DOLTLIBTOOL__EOF__' >>doltlibtool
+top_builddir_slash="${0%%doltlibtool}"
+: ${top_builddir_slash:=./}
+args=()
+modeok=false
+tagok=false
+for arg in "$[]@"; do
+ case "$arg" in
+ --mode=compile) modeok=true ;;
+ --tag=CC|--tag=CXX) tagok=true ;;
+ *) args@<:@${#args[@]}@:>@="$arg" ;;
+ esac
+done
+if $modeok && $tagok ; then
+ . ${top_builddir_slash}doltcompile "${args@<:@@@:>@}"
+else
+ exec ${top_builddir_slash}libtool "$[]@"
+fi
+__DOLTLIBTOOL__EOF__
+
+dnl Done writing out doltlibtool; substitute it for libtool.
+ chmod +x doltlibtool
+ LIBTOOL='$(top_builddir)/doltlibtool'
+fi
+AC_SUBST(LTCOMPILE)
+AC_SUBST(LTCXXCOMPILE)
+# end dolt
+])
diff --git a/python/ContextKit/cltool.py b/python/ContextKit/cltool.py
index 0535b88c..fc0fcc42 100644
--- a/python/ContextKit/cltool.py
+++ b/python/ContextKit/cltool.py
@@ -49,9 +49,19 @@ class CLTool:
def expectAll(self, fileno, _exp_l, timeout, wantdump = True):
exp_l = list(_exp_l)
stream = 0
- if fileno == self.STDOUT: stream = self.__process.stdout
- if fileno == self.STDERR: stream = self.__process.stderr
- if stream == 0: return False
+ if fileno == self.STDOUT:
+ stream = self.__process.stdout
+ elif fileno == self.STDERR:
+ stream = self.__process.stderr
+ else: return False
+
+ if not stream:
+ self.__io.append((fileno, "----- WAS NOT ABLE TO START THE PROGRAM -----"))
+ if wantdump:
+ self.printio()
+ print "Expected:"
+ pprint(exp_l)
+ return False
# set the stream to nonblocking
fd = stream.fileno()
diff --git a/sandbox/context-proxy b/sandbox/context-proxy
new file mode 100755
index 00000000..2b6a366b
--- /dev/null
+++ b/sandbox/context-proxy
@@ -0,0 +1,112 @@
+#!/usr/bin/python
+
+from sys import stderr, stdin
+from subprocess import Popen, PIPE
+from select import select
+import re
+import os
+
+class Program:
+ def __init__(self, cline):
+ d = dict(os.environ)
+ d.update({"CONTEXT_CLI_DISABLE_TYPE_CHECK": "1",
+ "CONTEXT_CLI_IGNORE_COMMANDER": "1"})
+
+ self.__process = Popen(cline, stdin=PIPE, stdout=PIPE, stderr=PIPE,
+ env = d)
+
+ def send(self, string):
+ print >>self.__process.stdin, string
+ self.__process.stdin.flush()
+
+ def outfd(self):
+ return self.__process.stdout.fileno()
+
+ def readline(self):
+ return self.__process.stdout.readline()
+
+ def ready(self):
+ raise NotImplementedError
+
+class Listen(Program):
+ def __init__(self, *properties):
+ Program.__init__(self, ["context-listen"] + list(properties))
+
+ def ready(self):
+ global provide
+ line = self.readline()
+ if line:
+ print >>stderr, "LISTEN:", line,
+ match = re.match("(.*?) = (.*?):(.*)\n", line)
+ if match:
+ property = match.group(1)
+ type = ""
+ if match.group(2) == "QString":
+ type = "string"
+ elif match.group(2) == "int":
+ type = "int"
+ elif match.group(2) == "bool":
+ type = "truth"
+ elif match.group(2) == "double":
+ type = "double"
+ else:
+ raise RuntimeError("unknown type from client: " + match.group(2))
+ value = match.group(3)
+ provide.send("add " + type + " " + property + " " + value)
+ match = re.match("(.*?) is Unknown\n", line)
+ if match:
+ property = match.group(1)
+ provide.send("add " + type + " " + property)
+ provide.send("unset " + property)
+
+ return True
+ else:
+ raise RuntimeError("context-listen terminated")
+
+class Provide(Program):
+ def __init__(self):
+ Program.__init__(self, ["context-provide-internal"])
+
+ def ready(self):
+ line = self.readline()
+ if line:
+ print "PROVIDE:", line,
+ return True
+ else:
+ raise RuntimeError("context-provide terminated")
+
+class UserInput():
+ def outfd(self):
+ return stdin.fileno()
+
+ def ready(self):
+ line = self.readline()
+ if line:
+ match = re.match("(.*?) (.*)\n", line)
+ command = match.group(1)
+ return True
+ else:
+ exit(0)
+
+class Select:
+ def __init__(self, *tools):
+ self.map = dict(map(lambda t: (t.outfd(), t), tools))
+ self.rlist = map(lambda t: t.outfd(), tools)
+
+ def select(self):
+ ret = select(self.rlist, [], [])[0]
+ for i in ret:
+ stderr.flush()
+ if not self.map[i].ready():
+ self.rlist.remove(i)
+ del self.map[i]
+
+listen = Listen("test.a", "test.b")
+provide = Provide()
+provide.send("start")
+s = Select(listen, provide)
+
+while True:
+ s.select()
+ if not s.rlist:
+ break
diff --git a/libcontextsubscriber/sandbox/messaging-to-self/main.cpp b/sandbox/messaging-to-self/main.cpp
index aafda83c..aafda83c 100644
--- a/libcontextsubscriber/sandbox/messaging-to-self/main.cpp
+++ b/sandbox/messaging-to-self/main.cpp
diff --git a/libcontextsubscriber/sandbox/messaging-to-self/messaging-to-self.pro b/sandbox/messaging-to-self/messaging-to-self.pro
index bafbb027..bafbb027 100644
--- a/libcontextsubscriber/sandbox/messaging-to-self/messaging-to-self.pro
+++ b/sandbox/messaging-to-self/messaging-to-self.pro
diff --git a/libcontextsubscriber/sandbox/messaging-to-self/myobject.h b/sandbox/messaging-to-self/myobject.h
index 155ebf3b..155ebf3b 100644
--- a/libcontextsubscriber/sandbox/messaging-to-self/myobject.h
+++ b/sandbox/messaging-to-self/myobject.h
diff --git a/libcontextsubscriber/sandbox/messaging-to-self/mythread.h b/sandbox/messaging-to-self/mythread.h
index 4170ccf8..4170ccf8 100644
--- a/libcontextsubscriber/sandbox/messaging-to-self/mythread.h
+++ b/sandbox/messaging-to-self/mythread.h
diff --git a/libcontextsubscriber/sandbox/messaging-to-self/queuedinvoker.cpp b/sandbox/messaging-to-self/queuedinvoker.cpp
index 85dbb7d1..85dbb7d1 100644
--- a/libcontextsubscriber/sandbox/messaging-to-self/queuedinvoker.cpp
+++ b/sandbox/messaging-to-self/queuedinvoker.cpp
diff --git a/libcontextsubscriber/sandbox/messaging-to-self/queuedinvoker.h b/sandbox/messaging-to-self/queuedinvoker.h
index 8f81f26e..8f81f26e 100644
--- a/libcontextsubscriber/sandbox/messaging-to-self/queuedinvoker.h
+++ b/sandbox/messaging-to-self/queuedinvoker.h
diff --git a/libcontextsubscriber/multithreading-tests/Makefile.am b/sandbox/multithreading-tests/Makefile.am
index 8da6191d..8da6191d 100644
--- a/libcontextsubscriber/multithreading-tests/Makefile.am
+++ b/sandbox/multithreading-tests/Makefile.am
diff --git a/libcontextsubscriber/multithreading-tests/new-property-in-thread/.gitignore b/sandbox/multithreading-tests/new-property-in-thread/.gitignore
index 4390dc85..4390dc85 100644
--- a/libcontextsubscriber/multithreading-tests/new-property-in-thread/.gitignore
+++ b/sandbox/multithreading-tests/new-property-in-thread/.gitignore
diff --git a/libcontextsubscriber/multithreading-tests/new-property-in-thread/Makefile.am b/sandbox/multithreading-tests/new-property-in-thread/Makefile.am
index 6e80e6d8..59dc63a7 100644
--- a/libcontextsubscriber/multithreading-tests/new-property-in-thread/Makefile.am
+++ b/sandbox/multithreading-tests/new-property-in-thread/Makefile.am
@@ -7,9 +7,10 @@ LIBS += $(QtCore_LIBS)
# library dependency hack for seamless make in cli/
AM_CXXFLAGS += -I$(srcdir)/../../src
run_test_LDADD = ../../src/libcontextsubscriber.la
-../../src/libcontextsubscriber.la:
+
+../../src/libcontextsubscriber.la: FORCE
$(MAKE) -C ../../src libcontextsubscriber.la
-.PHONY: ../../src/libcontextsubscriber.la
+.PHONY: FORCE
# moccing
nodist_run_test_SOURCES = mocs.cpp
diff --git a/libcontextsubscriber/multithreading-tests/new-property-in-thread/main.cpp b/sandbox/multithreading-tests/new-property-in-thread/main.cpp
index 3ab015fb..3ab015fb 100644
--- a/libcontextsubscriber/multithreading-tests/new-property-in-thread/main.cpp
+++ b/sandbox/multithreading-tests/new-property-in-thread/main.cpp
diff --git a/libcontextsubscriber/multithreading-tests/new-property-in-thread/thread.h b/sandbox/multithreading-tests/new-property-in-thread/thread.h
index dd9951b3..dd9951b3 100644
--- a/libcontextsubscriber/multithreading-tests/new-property-in-thread/thread.h
+++ b/sandbox/multithreading-tests/new-property-in-thread/thread.h
diff --git a/libcontextsubscriber/multithreading-tests/old-property-in-thread/.gitignore b/sandbox/multithreading-tests/old-property-in-thread/.gitignore
index 4390dc85..4390dc85 100644
--- a/libcontextsubscriber/multithreading-tests/old-property-in-thread/.gitignore
+++ b/sandbox/multithreading-tests/old-property-in-thread/.gitignore
diff --git a/libcontextsubscriber/multithreading-tests/stress-test/Makefile.am b/sandbox/multithreading-tests/old-property-in-thread/Makefile.am
index 6e80e6d8..59dc63a7 100644
--- a/libcontextsubscriber/multithreading-tests/stress-test/Makefile.am
+++ b/sandbox/multithreading-tests/old-property-in-thread/Makefile.am
@@ -7,9 +7,10 @@ LIBS += $(QtCore_LIBS)
# library dependency hack for seamless make in cli/
AM_CXXFLAGS += -I$(srcdir)/../../src
run_test_LDADD = ../../src/libcontextsubscriber.la
-../../src/libcontextsubscriber.la:
+
+../../src/libcontextsubscriber.la: FORCE
$(MAKE) -C ../../src libcontextsubscriber.la
-.PHONY: ../../src/libcontextsubscriber.la
+.PHONY: FORCE
# moccing
nodist_run_test_SOURCES = mocs.cpp
diff --git a/libcontextsubscriber/multithreading-tests/old-property-in-thread/main.cpp b/sandbox/multithreading-tests/old-property-in-thread/main.cpp
index c21c9d7f..c21c9d7f 100644
--- a/libcontextsubscriber/multithreading-tests/old-property-in-thread/main.cpp
+++ b/sandbox/multithreading-tests/old-property-in-thread/main.cpp
diff --git a/libcontextsubscriber/multithreading-tests/old-property-in-thread/thread.h b/sandbox/multithreading-tests/old-property-in-thread/thread.h
index ec84afdf..ec84afdf 100644
--- a/libcontextsubscriber/multithreading-tests/old-property-in-thread/thread.h
+++ b/sandbox/multithreading-tests/old-property-in-thread/thread.h
diff --git a/libcontextsubscriber/multithreading-tests/single-thread/.gitignore b/sandbox/multithreading-tests/single-thread/.gitignore
index 4390dc85..4390dc85 100644
--- a/libcontextsubscriber/multithreading-tests/single-thread/.gitignore
+++ b/sandbox/multithreading-tests/single-thread/.gitignore
diff --git a/libcontextsubscriber/multithreading-tests/single-thread/Makefile.am b/sandbox/multithreading-tests/single-thread/Makefile.am
index 3cec50b8..010bc826 100644
--- a/libcontextsubscriber/multithreading-tests/single-thread/Makefile.am
+++ b/sandbox/multithreading-tests/single-thread/Makefile.am
@@ -7,9 +7,10 @@ LIBS += $(QtCore_LIBS)
# library dependency hack for seamless make in cli/
AM_CXXFLAGS += -I$(srcdir)/../../src
run_test_LDADD = ../../src/libcontextsubscriber.la
-../../src/libcontextsubscriber.la:
+
+../../src/libcontextsubscriber.la: FORCE
$(MAKE) -C ../../src libcontextsubscriber.la
-.PHONY: ../../src/libcontextsubscriber.la
+.PHONY: FORCE
# moccing
nodist_run_test_SOURCES = mocs.cpp
diff --git a/libcontextsubscriber/multithreading-tests/single-thread/listener.h b/sandbox/multithreading-tests/single-thread/listener.h
index 9980f62a..9980f62a 100644
--- a/libcontextsubscriber/multithreading-tests/single-thread/listener.h
+++ b/sandbox/multithreading-tests/single-thread/listener.h
diff --git a/libcontextsubscriber/multithreading-tests/single-thread/main.cpp b/sandbox/multithreading-tests/single-thread/main.cpp
index 16dd2f65..16dd2f65 100644
--- a/libcontextsubscriber/multithreading-tests/single-thread/main.cpp
+++ b/sandbox/multithreading-tests/single-thread/main.cpp
diff --git a/libcontextsubscriber/multithreading-tests/stress-test/.gitignore b/sandbox/multithreading-tests/stress-test/.gitignore
index e08dedad..e08dedad 100644
--- a/libcontextsubscriber/multithreading-tests/stress-test/.gitignore
+++ b/sandbox/multithreading-tests/stress-test/.gitignore
diff --git a/libcontextsubscriber/multithreading-tests/stress-test/1provider.cdb b/sandbox/multithreading-tests/stress-test/1provider.cdb
index 58655ef3..58655ef3 100644
--- a/libcontextsubscriber/multithreading-tests/stress-test/1provider.cdb
+++ b/sandbox/multithreading-tests/stress-test/1provider.cdb
Binary files differ
diff --git a/libcontextsubscriber/multithreading-tests/stress-test/2providers.cdb b/sandbox/multithreading-tests/stress-test/2providers.cdb
index 98324d4c..98324d4c 100644
--- a/libcontextsubscriber/multithreading-tests/stress-test/2providers.cdb
+++ b/sandbox/multithreading-tests/stress-test/2providers.cdb
Binary files differ
diff --git a/libcontextsubscriber/multithreading-tests/old-property-in-thread/Makefile.am b/sandbox/multithreading-tests/stress-test/Makefile.am
index 6e80e6d8..59dc63a7 100644
--- a/libcontextsubscriber/multithreading-tests/old-property-in-thread/Makefile.am
+++ b/sandbox/multithreading-tests/stress-test/Makefile.am
@@ -7,9 +7,10 @@ LIBS += $(QtCore_LIBS)
# library dependency hack for seamless make in cli/
AM_CXXFLAGS += -I$(srcdir)/../../src
run_test_LDADD = ../../src/libcontextsubscriber.la
-../../src/libcontextsubscriber.la:
+
+../../src/libcontextsubscriber.la: FORCE
$(MAKE) -C ../../src libcontextsubscriber.la
-.PHONY: ../../src/libcontextsubscriber.la
+.PHONY: FORCE
# moccing
nodist_run_test_SOURCES = mocs.cpp
diff --git a/libcontextsubscriber/multithreading-tests/stress-test/main.cpp b/sandbox/multithreading-tests/stress-test/main.cpp
index d7c334bd..d7c334bd 100644
--- a/libcontextsubscriber/multithreading-tests/stress-test/main.cpp
+++ b/sandbox/multithreading-tests/stress-test/main.cpp
diff --git a/libcontextsubscriber/multithreading-tests/stress-test/provider.py b/sandbox/multithreading-tests/stress-test/provider.py
index 748929a4..748929a4 100755
--- a/libcontextsubscriber/multithreading-tests/stress-test/provider.py
+++ b/sandbox/multithreading-tests/stress-test/provider.py
diff --git a/libcontextsubscriber/multithreading-tests/stress-test/runme.sh b/sandbox/multithreading-tests/stress-test/runme.sh
index a2aa73d6..a2aa73d6 100755
--- a/libcontextsubscriber/multithreading-tests/stress-test/runme.sh
+++ b/sandbox/multithreading-tests/stress-test/runme.sh
diff --git a/libcontextsubscriber/multithreading-tests/stress-test/thread.h b/sandbox/multithreading-tests/stress-test/thread.h
index 44cbf7c8..44cbf7c8 100644
--- a/libcontextsubscriber/multithreading-tests/stress-test/thread.h
+++ b/sandbox/multithreading-tests/stress-test/thread.h
diff --git a/libcontextsubscriber/multithreading-tests/using-backend-from-thread/.gitignore b/sandbox/multithreading-tests/using-backend-from-thread/.gitignore
index 4390dc85..4390dc85 100644
--- a/libcontextsubscriber/multithreading-tests/using-backend-from-thread/.gitignore
+++ b/sandbox/multithreading-tests/using-backend-from-thread/.gitignore
diff --git a/libcontextsubscriber/multithreading-tests/using-backend-from-thread/Makefile.am b/sandbox/multithreading-tests/using-backend-from-thread/Makefile.am
index b5883842..b4cf1a5d 100644
--- a/libcontextsubscriber/multithreading-tests/using-backend-from-thread/Makefile.am
+++ b/sandbox/multithreading-tests/using-backend-from-thread/Makefile.am
@@ -7,9 +7,10 @@ LIBS += $(QtCore_LIBS) $(QtDBus_LIBS)
# library dependency hack for seamless make in cli/
AM_CXXFLAGS += -I$(srcdir)/../../src
run_test_LDADD = ../../src/libcontextsubscriber.la
-../../src/libcontextsubscriber.la:
+
+../../src/libcontextsubscriber.la: FORCE
$(MAKE) -C ../../src libcontextsubscriber.la
-.PHONY: ../../src/libcontextsubscriber.la
+.PHONY: FORCE
# moccing
nodist_run_test_SOURCES = mocs.cpp
diff --git a/libcontextsubscriber/multithreading-tests/using-backend-from-thread/main.cpp b/sandbox/multithreading-tests/using-backend-from-thread/main.cpp
index a6a7c8aa..a6a7c8aa 100644
--- a/libcontextsubscriber/multithreading-tests/using-backend-from-thread/main.cpp
+++ b/sandbox/multithreading-tests/using-backend-from-thread/main.cpp
diff --git a/libcontextsubscriber/multithreading-tests/using-backend-from-thread/thread.h b/sandbox/multithreading-tests/using-backend-from-thread/thread.h
index cd77a298..cd77a298 100644
--- a/libcontextsubscriber/multithreading-tests/using-backend-from-thread/thread.h
+++ b/sandbox/multithreading-tests/using-backend-from-thread/thread.h
diff --git a/libcontextsubscriber/multithreading-tests/wait-for-subscription-only-in-thread/.gitignore b/sandbox/multithreading-tests/wait-for-subscription-only-in-thread/.gitignore
index 4390dc85..4390dc85 100644
--- a/libcontextsubscriber/multithreading-tests/wait-for-subscription-only-in-thread/.gitignore
+++ b/sandbox/multithreading-tests/wait-for-subscription-only-in-thread/.gitignore
diff --git a/libcontextsubscriber/multithreading-tests/wait-for-subscription-only-in-thread/Makefile.am b/sandbox/multithreading-tests/wait-for-subscription-only-in-thread/Makefile.am
index 6e80e6d8..59dc63a7 100644
--- a/libcontextsubscriber/multithreading-tests/wait-for-subscription-only-in-thread/Makefile.am
+++ b/sandbox/multithreading-tests/wait-for-subscription-only-in-thread/Makefile.am
@@ -7,9 +7,10 @@ LIBS += $(QtCore_LIBS)
# library dependency hack for seamless make in cli/
AM_CXXFLAGS += -I$(srcdir)/../../src
run_test_LDADD = ../../src/libcontextsubscriber.la
-../../src/libcontextsubscriber.la:
+
+../../src/libcontextsubscriber.la: FORCE
$(MAKE) -C ../../src libcontextsubscriber.la
-.PHONY: ../../src/libcontextsubscriber.la
+.PHONY: FORCE
# moccing
nodist_run_test_SOURCES = mocs.cpp
diff --git a/libcontextsubscriber/multithreading-tests/wait-for-subscription-only-in-thread/main.cpp b/sandbox/multithreading-tests/wait-for-subscription-only-in-thread/main.cpp
index 1a1727b7..1a1727b7 100644
--- a/libcontextsubscriber/multithreading-tests/wait-for-subscription-only-in-thread/main.cpp
+++ b/sandbox/multithreading-tests/wait-for-subscription-only-in-thread/main.cpp
diff --git a/libcontextsubscriber/multithreading-tests/wait-for-subscription-only-in-thread/thread.h b/sandbox/multithreading-tests/wait-for-subscription-only-in-thread/thread.h
index e92af6f2..e92af6f2 100644
--- a/libcontextsubscriber/multithreading-tests/wait-for-subscription-only-in-thread/thread.h
+++ b/sandbox/multithreading-tests/wait-for-subscription-only-in-thread/thread.h
diff --git a/libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/.gitignore b/sandbox/multithreading-tests/wait-for-subscription-thread/.gitignore
index 4390dc85..4390dc85 100644
--- a/libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/.gitignore
+++ b/sandbox/multithreading-tests/wait-for-subscription-thread/.gitignore
diff --git a/sandbox/multithreading-tests/wait-for-subscription-thread/Makefile.am b/sandbox/multithreading-tests/wait-for-subscription-thread/Makefile.am
new file mode 100644
index 00000000..59dc63a7
--- /dev/null
+++ b/sandbox/multithreading-tests/wait-for-subscription-thread/Makefile.am
@@ -0,0 +1,18 @@
+noinst_PROGRAMS = run-test
+run_test_SOURCES = main.cpp thread.h
+
+AM_CXXFLAGS = $(QtCore_CFLAGS)
+LIBS += $(QtCore_LIBS)
+
+# library dependency hack for seamless make in cli/
+AM_CXXFLAGS += -I$(srcdir)/../../src
+run_test_LDADD = ../../src/libcontextsubscriber.la
+
+../../src/libcontextsubscriber.la: FORCE
+ $(MAKE) -C ../../src libcontextsubscriber.la
+.PHONY: FORCE
+
+# moccing
+nodist_run_test_SOURCES = mocs.cpp
+QT_TOMOC = $(filter %.h, $(run_test_SOURCES))
+include $(top_srcdir)/am/qt.am
diff --git a/libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/main.cpp b/sandbox/multithreading-tests/wait-for-subscription-thread/main.cpp
index 44390e2d..44390e2d 100644
--- a/libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/main.cpp
+++ b/sandbox/multithreading-tests/wait-for-subscription-thread/main.cpp
diff --git a/libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/thread.h b/sandbox/multithreading-tests/wait-for-subscription-thread/thread.h
index 7766fe68..7766fe68 100644
--- a/libcontextsubscriber/multithreading-tests/wait-for-subscription-thread/thread.h
+++ b/sandbox/multithreading-tests/wait-for-subscription-thread/thread.h
diff --git a/spec/ContextKit.xml b/spec/ContextKit.xml
new file mode 100644
index 00000000..da6a70ba
--- /dev/null
+++ b/spec/ContextKit.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<node name="/org/maemo/contextkit/Some/Property"
+ xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
+ <interface name="org.maemo.contextkit.Property">
+ <method name="Subscribe">
+ <tp:docstring>
+ Subscribes to the context property.
+ </tp:docstring>
+ <arg name="value" type="av" tp:type="Maybe_Variant" direction="out">
+ <tp:docstring>
+ The actual value at the of subscription.
+ </tp:docstring>
+ </arg>
+ <arg name="timestamp" type="t" direction="out">
+ <tp:docstring>
+ The timestamp of the value.
+ </tp:docstring>
+ </arg>
+ </method>
+ <method name="Unsubscribe">
+ <tp:docstring>
+ Unsubscribes from the property.
+ </tp:docstring>
+ </method>
+ <method name="Get">
+ <tp:docstring>
+ Returns the actual value from the provider without subscribing to it.
+ </tp:docstring>
+ <arg name="value" type="av" tp:type="Maybe_Variant" direction="out"/>
+ <arg name="timestamp" type="t" direction="out"/>
+ </method>
+ <signal name="Changed">
+ <tp:docstring>
+ Emitted when the value changed and there are at least one subscribed client.
+ </tp:docstring>
+ <arg name="value" type="av" tp:type="Maybe_Variant"/>
+ <arg name="timestamp" type="t"/>
+ </signal>
+ </interface>
+</node>
diff --git a/spec/Makefile.am b/spec/Makefile.am
index e22b2413..6450fcac 100644
--- a/spec/Makefile.am
+++ b/spec/Makefile.am
@@ -17,7 +17,8 @@ SPEC_TOOLS = spec-to-introspect.xsl \
INTERFACES = \
Manager.xml \
- Subscriber.xml
+ Subscriber.xml \
+ ContextKit.xml
SPEC_FILES = \
$(INTERFACES) \
diff --git a/spec/all.xml b/spec/all.xml
index a73b1dcb..c2132a60 100644
--- a/spec/all.xml
+++ b/spec/all.xml
@@ -25,5 +25,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
<xi:include href="Manager.xml"/>
<xi:include href="Subscriber.xml"/>
+<xi:include href="ContextKit.xml"/>
<xi:include href="generic-types.xml"/>
</tp:spec>
diff --git a/spec/generic-types.xml b/spec/generic-types.xml
index f2bd4940..f3ab3227 100644
--- a/spec/generic-types.xml
+++ b/spec/generic-types.xml
@@ -7,6 +7,12 @@
<tp:member type="v" name="Value"/>
</tp:mapping>
+ <tp:simple-type name="Maybe_Variant" type="av">
+ <tp:docstring>A list of variants where empty list represents
+ unknown, otherwise it represents the same variant as the contained
+ first variant. This hack is needed because D-Bus doesn't support
+ null values on the wire.</tp:docstring>
+ </tp:simple-type>
</tp:generic-types>