Merge lp:geis/client-arch into lp:geis

Proposed by Stephen M. Webb
Status: Merged
Merged at revision: 166
Proposed branch: lp:geis/client-arch
Merge into: lp:geis
Diff against target: 9842 lines (+7414/-649)
90 files modified
.bzrignore (+7/-1)
Makefile.am (+1/-0)
configure.ac (+4/-1)
include/geis/geis.h (+11/-8)
libs/Makefile.am (+1/-1)
libs/geis-dbus/Makefile.am (+41/-0)
libs/geis-dbus/geis_dbus.h (+37/-8)
libs/geis-dbus/geis_dbus_attr.c (+178/-0)
libs/geis-dbus/geis_dbus_attr.h (+57/-0)
libs/geis-dbus/geis_dbus_class.c (+126/-0)
libs/geis-dbus/geis_dbus_class.h (+45/-0)
libs/geis-dbus/geis_dbus_device.c (+152/-0)
libs/geis-dbus/geis_dbus_device.h (+61/-0)
libs/geis-dbus/geis_dbus_dispatcher.c (+486/-0)
libs/geis-dbus/geis_dbus_dispatcher.h (+116/-0)
libs/geis-dbus/geis_dbus_gesture_event.c (+573/-0)
libs/geis-dbus/geis_dbus_gesture_event.h (+55/-0)
libs/geis-dbus/geis_dbus_region.c (+91/-0)
libs/geis-dbus/geis_dbus_region.h (+47/-0)
libs/geis-dbus/geis_dbus_subscription.c (+506/-0)
libs/geis-dbus/geis_dbus_subscription.h (+206/-0)
libutouch-geis/Makefile.am (+5/-0)
libutouch-geis/backend/Makefile.am (+1/-1)
libutouch-geis/backend/dbus/Makefile.am (+34/-0)
libutouch-geis/backend/dbus/geis_dbus_backend.c (+249/-0)
libutouch-geis/backend/dbus/geis_dbus_client.c (+685/-0)
libutouch-geis/backend/dbus/geis_dbus_client.h (+97/-0)
libutouch-geis/backend/dbus/geis_dbus_locator.c (+270/-0)
libutouch-geis/backend/dbus/geis_dbus_locator.h (+62/-0)
libutouch-geis/backend/test_fixture/geis_backend_test_fixture.c (+7/-5)
libutouch-geis/backend/xcb/geis_xcb_backend.c (+10/-8)
libutouch-geis/backend/xcb/geis_xcb_backend_token.c (+4/-4)
libutouch-geis/backend/xcb/grail_gestures.c (+1/-1)
libutouch-geis/geis.c (+166/-158)
libutouch-geis/geis_attr.c (+143/-0)
libutouch-geis/geis_attr.h (+16/-0)
libutouch-geis/geis_backend.c (+2/-0)
libutouch-geis/geis_backend_multiplexor.c (+183/-74)
libutouch-geis/geis_backend_multiplexor.h (+51/-15)
libutouch-geis/geis_backend_protected.h (+2/-2)
libutouch-geis/geis_backend_token.c (+6/-4)
libutouch-geis/geis_backend_token.h (+32/-9)
libutouch-geis/geis_class.c (+2/-2)
libutouch-geis/geis_class.h (+1/-1)
libutouch-geis/geis_device.h (+1/-1)
libutouch-geis/geis_filter.c (+83/-0)
libutouch-geis/geis_filter.h (+51/-0)
libutouch-geis/geis_filter_term.c (+129/-0)
libutouch-geis/geis_filter_term.h (+8/-0)
libutouch-geis/geis_filterable.c (+151/-0)
libutouch-geis/geis_filterable.h (+116/-0)
libutouch-geis/geis_frame.c (+26/-2)
libutouch-geis/geis_frame.h (+27/-0)
libutouch-geis/geis_gesture_flick.c (+1/-1)
libutouch-geis/geis_private.h (+65/-59)
libutouch-geis/geis_subscription.c (+73/-10)
libutouch-geis/geis_subscription.h (+53/-0)
libutouch-geis/geis_timer.c (+5/-4)
libutouch-geis/geis_v1.c (+104/-45)
libutouch-geis/server/Makefile.am (+5/-2)
libutouch-geis/server/geis_dbus_announcer.c (+233/-0)
libutouch-geis/server/geis_dbus_announcer.h (+54/-0)
libutouch-geis/server/geis_dbus_client_proxy.c (+486/-0)
libutouch-geis/server/geis_dbus_client_proxy.h (+60/-0)
libutouch-geis/server/geis_dbus_proxy_box.c (+199/-0)
libutouch-geis/server/geis_dbus_proxy_box.h (+115/-0)
libutouch-geis/server/geis_dbus_server.c (+278/-154)
libutouch-geis/server/geis_dbus_server.h (+70/-30)
python/_geis_bindings/_geis_bindings.c (+3/-2)
python/geis/__init__.py (+6/-4)
testsuite/geis2/check_class.c (+1/-1)
testsuite/geis2/check_config.c (+1/-1)
testsuite/geis2/check_device.c (+1/-1)
testsuite/geis2/check_filter.c (+1/-1)
testsuite/geis2/check_frame.c (+1/-1)
testsuite/geis2/check_geis_new.c (+1/-1)
testsuite/geis2/check_region.c (+1/-1)
testsuite/geis2/check_subscription.c (+1/-1)
testsuite/libutouch-geis/Makefile.am (+1/-0)
testsuite/libutouch-geis/check_backend_multiplexor.c (+6/-2)
testsuite/libutouch-geis/check_backend_token.c (+1/-1)
testsuite/libutouch-geis/check_filter.c (+1/-1)
testsuite/libutouch-geis/check_geis_private.c (+4/-3)
testsuite/libutouch-geis/check_region.c (+1/-1)
testsuite/libutouch-geis/check_subscription.c (+1/-1)
testsuite/libutouch-geis/check_timer.c (+1/-1)
tools/Makefile.am (+1/-1)
tools/geis-server/Makefile.am (+33/-0)
tools/geis-server/geis-server.c (+85/-0)
tools/geisview/geisview (+39/-13)
To merge this branch: bzr merge lp:geis/client-arch
Reviewer Review Type Date Requested Status
Chase Douglas (community) Approve
Review via email: mp+79626@code.launchpad.net

This proposal supersedes a proposal from 2011-10-13.

Description of the change

Adds selectable client-server architecture using a private DBus.

Sets the default back end to DBus and automatically falls back to XCB if the GEIS DBus server is not available.

Handles server disconnects and reconnects gracefully.

A command-line switch can be used with the geisview tool to explicitly select a back end.

Only a simple server test tool supplied, an actual utouchd GEIS server daemon will be developed separately.

To post a comment you must log in.
Revision history for this message
Stephen M. Webb (bregma) wrote : Posted in a previous version of this proposal

Added a trunk synch to resolve some merge conflicts.

Revision history for this message
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal

A ton of code that looks very clean. I really like the changes from an aesthetic point of view. It's obvious that you put a lot of thought into how things should be structured!

Here's what I'm looking for in reviewing this code:

1. Are there any "black box" changes?
2. Does the code look clean? Does it appear to do what is stated in the merge request?
3. Does it work?
4. Are there any issues highlighted by the merge proposal description?

Note that I'm not doing a line by line review. There's too much code to review for that level of detail, and you're a trusted member of the development team.

For item 1, there are no changes in include/. Since there are no api changes, and it's assumed there are no abi changes, this criteria is fulfilled.

For item 2, the code is definitely clean. It does appear to do what is stated in the merge request in whole.

However, I don't see any change in the default backend choice, and I don't see any change in geisview that would cause it to use the new client-server backend. Am I missing something, or was this lost in a merge or rebase? I would prefer to see the default backend change to the client-server backend with a fallback to the xcb backend.

The geis server is under tools/. Is this implementation merely an example, or is it the defacto server that should be used? If it's the latter, I would prefer to move it to the top level. I feel putting it in tools/ gives the wrong impression that it is not an essential part of the project.

For item 3, I'm not ready to give an answer yet since I don't know that geisview is using the new architecture. (On IRC, Stephen explained how to test: tools/geis-server/geis-server and then tools/geisview/geisview).

For item 4, I would like to know what is left out by the statement in the merge proposal: "I think at this point (most) functionality is there." Please detail which functionality is missing?

Overall, I'm extremely happy with the changes, assuming the testing shows it works :). I look forward to merging the branch once these issues are resolved!

review: Needs Information
Revision history for this message
Stephen M. Webb (bregma) wrote : Posted in a previous version of this proposal

On 10/13/2011 04:53 PM, Chase Douglas wrote:
> For item 1, there are no changes in include/. Since there are no api changes, and it's assumed there are no abi changes, this criteria is fulfilled.

There is a backwards-compatible API change in include/geis/geis.h with
the addition of the GEIS_INIT_UTOUCH_DBUS_BACKEND defined constant.

> For item 2, the code is definitely clean. It does appear to do what is stated in the merge request in whole.
>
> However, I don't see any change in the default backend choice, and I don't see any change in geisview that would cause it to use the new client-server backend. Am I missing something, or was this lost in a merge or rebase? I would prefer to see the default backend change to the client-server backend with a fallback to the xcb backend.

This was apparently clobbered by a last-minute merge from trunk with
manual conflict resolution. I will re-add the back end selection to the
geisview tool and make it command-line configurable, and resubmit.

Changing the default back end to the dbus-client is a little premature
until a proper daemon is set up complete with launch scripts (dbus
service?). This should wait until after the round of plugin
refactoring. Changing the default back-end is a one-line change.

> The geis server is under tools/. Is this implementation merely an example, or is it the defacto server that should be used? If it's the latter, I would prefer to move it to the top level. I feel putting it in tools/ gives the wrong impression that it is not an essential part of the project.

The program under tools is a test driver tool. Writing a proper daemon
application with attendant start and stop scripts, logging, and control
options should be a separate task not a part of the internal library
changes designed to enable that task.

All of the changes made under this merge request were made under the
original assumption that the geis server would run as a compiz plugin.
None of them are incompatible with running a standalone server and
neither do they require it.

We should consider making a "utouchd" daemon a separate project from the
utouch-geis library.

> For item 3, I'm not ready to give an answer yet since I don't know that geisview is using the new architecture. (On IRC, Stephen explained how to test: tools/geis-server/geis-server and then tools/geisview/geisview).

I will provide better instructions with the above-mentioned changes to
geisview.

> For item 4, I would like to know what is left out by the statement in the merge proposal: "I think at this point (most) functionality is there." Please detail which functionality is missing?

Yes, quite. The only known functional deficit is proper reconnection
from the client when the server has disconnected and then reconnected
again. After verbal discussions we decided to defer this functionality
to later in the interest of getting the client-server merge completed.

Revision history for this message
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal
Download full text (3.5 KiB)

> On 10/13/2011 04:53 PM, Chase Douglas wrote:
> > For item 1, there are no changes in include/. Since there are no api
> changes, and it's assumed there are no abi changes, this criteria is
> fulfilled.
>
> There is a backwards-compatible API change in include/geis/geis.h with
> the addition of the GEIS_INIT_UTOUCH_DBUS_BACKEND defined constant.

Argh... I see now that although the unmerged revisions list below starts at commit 187, the client-arch commits really start at commit 159. I will need to re-review to include those commits as well.

> > For item 2, the code is definitely clean. It does appear to do what is
> stated in the merge request in whole.
> >
> > However, I don't see any change in the default backend choice, and I don't
> see any change in geisview that would cause it to use the new client-server
> backend. Am I missing something, or was this lost in a merge or rebase? I
> would prefer to see the default backend change to the client-server backend
> with a fallback to the xcb backend.
>
> This was apparently clobbered by a last-minute merge from trunk with
> manual conflict resolution. I will re-add the back end selection to the
> geisview tool and make it command-line configurable, and resubmit.
>
> Changing the default back end to the dbus-client is a little premature
> until a proper daemon is set up complete with launch scripts (dbus
> service?). This should wait until after the round of plugin
> refactoring. Changing the default back-end is a one-line change.

I'm not sure it's premature. The client-arch won't be used unless you have a server running, in which case we can probably assume the user knows what they are doing. The main reason I would like to switch the default is so we can test current clients of geis without having to recompile them. And, it would be switchable merely by running or killing the geis server. I will probably run the tools/ server by default in my installs just so we have some good testing.

> > The geis server is under tools/. Is this implementation merely an example,
> or is it the defacto server that should be used? If it's the latter, I would
> prefer to move it to the top level. I feel putting it in tools/ gives the
> wrong impression that it is not an essential part of the project.
>
> The program under tools is a test driver tool. Writing a proper daemon
> application with attendant start and stop scripts, logging, and control
> options should be a separate task not a part of the internal library
> changes designed to enable that task.
>
> All of the changes made under this merge request were made under the
> original assumption that the geis server would run as a compiz plugin.
> None of them are incompatible with running a standalone server and
> neither do they require it.
>
> We should consider making a "utouchd" daemon a separate project from the
> utouch-geis library.

Ok, that sounds reasonable.

> > For item 4, I would like to know what is left out by the statement in the
> merge proposal: "I think at this point (most) functionality is there." Please
> detail which functionality is missing?
>
> Yes, quite. The only known functional deficit is proper reconnection
> fr...

Read more...

Revision history for this message
Stephen M. Webb (bregma) wrote : Posted in a previous version of this proposal

On 10/13/2011 09:03 PM, Chase Douglas wrote:
>
> Argh... I see now that although the unmerged revisions list below starts at commit 187, the client-arch commits really start at commit 159. I will need to re-review to include those commits as well.

Yeah, it was a big set of changes with a number of synchs with trunk
along the way.

> I'm not sure it's premature. The client-arch won't be used unless you have a server running, in which case we can probably assume the user knows what they are doing. The main reason I would like to switch the default is so we can test current clients of geis without having to recompile them. And, it would be switchable merely by running or killing the geis server. I will probably run the tools/ server by default in my installs just so we have some good testing.

So you're suggesting autodiscovery with fallback. OK, I can do that.
Would like that as part of this merge or should we open a bug to track
that work?

Note that clients would not need any kind of recompile regardless.

>> The only known functional deficit is proper reconnection
>> from the client when the server has disconnected and then reconnected
>> again. After verbal discussions we decided to defer this functionality
>> to later in the interest of getting the client-server merge completed.
>
> Ok, that's reasonable for now. If we merge the branch like this, we should open a bug to track this missing functionality.

Absolutely.

Revision history for this message
Chase Douglas (chasedouglas) wrote :

I've reviewed all the changes at a high level, and I believe my original criteria 1 and 2 are satisfied. For 1, the only change is the naming of the backend macro definitions. In one sense, it's probably a good thing since it will force anyone specifying the XCB backend to rethink their decision. I'm ok with this.

Criteria 4 has been satisfied by commit 198, which resolves the only previously mentioned issue with the implementation.

The only implementation concern I have now is that if you specify the DBus backend, it will fall back to XCB. I think if the backend is specified, it should only succeed or fail. If the backend is left unspecified, we can do defaulting and failovers. After chatting with Stephen on irc, he agreed with the idea, but felt it wasn't worth the hassle for now. Our solution is to ensure documentation matches what it *should* do, and file a bug to resolve this issue for the DBus backend.

I then tried to test it out. geisview worked great with and without a server, and it reconnected to a server that went away and came back anew. Very cool. Unfortunately, geis causes the turbine.qml example in utouch-qml to crash. We need to figure out what is going on there before we merge it.

Stephen, do you know how we can test out the server with unity? Will running unity --replace after starting the server work?

Revision history for this message
Chase Douglas (chasedouglas) wrote :

The crash in utouch-qml was a bug in utouch-qml itself. XCB fallback works properly now.

However, utouch-qml fails to see the gesture events. I see subscriptions and gesture event generation in the server when run with GEIS_DEBUG=3, but the client doesn't see anything. Nothing is output from the client at GEIS_DEBUG=3 when the gestures are performed. This also happens when restarting unity while the server is running.

lp:geis/client-arch updated
199. By Stephen M. Webb

Added full support for filtering by gesture class name with DBus server back end.

Revision history for this message
Stephen M. Webb (bregma) wrote :

Pushed in an additional commit that adds full support for filtering by gesture class name when using the DBus server back end.

Revision history for this message
Chase Douglas (chasedouglas) wrote :

Unity and utouch-qml now work. The only bug I see left to deal with is a client segfault when the client is closed. This only occurs when the dbus server is used. The xcb interface doesn't crash.

lp:geis/client-arch updated
200. By Stephen M. Webb

Fixed a couple of invalid deallocations on exit.

Revision history for this message
Stephen M. Webb (bregma) wrote :

Pushed an additional commit to repair a couple of miplaced free()s on teardown.

Revision history for this message
Chase Douglas (chasedouglas) wrote :

I no longer receive a segfault on client close. This satisfies all my criteria.

I'm approving the merge proposal. Please open a bug about the backend selection default issue.

Great work!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2011-04-18 13:48:35 +0000
3+++ .bzrignore 2011-10-18 19:34:23 +0000
4@@ -6,13 +6,13 @@
5 **/xcb_gesture.[ch]
6 *.deps
7 *.libs
8+*.log
9 *Makefile.in
10 aclocal.m4
11 autom4te.cache
12 config.*
13 configure
14 debian/*.debhelper
15-debian/*.log
16 debian/*.substvars
17 debian/files
18 debian/libutouch-geis-dev
19@@ -28,8 +28,13 @@
20 examples/geis2
21 geis_config.*
22 libtool
23+libtool.m4
24 libutouch-geis.pc
25+ltoptions.m4
26+ltversion.m4
27+lt~obsolete.m4
28 stamp-*
29+TAGS
30 testsuite/geis1/*.log
31 testsuite/geis1/check_geis1_api
32 testsuite/geis2/*.log
33@@ -38,3 +43,4 @@
34 testsuite/libutouch-geis/*.log
35 testsuite/libutouch-geis/*.xml
36 testsuite/libutouch-geis/check_geis2_internals
37+tools/geis-server/geis-server
38
39=== modified file 'Makefile.am'
40--- Makefile.am 2011-04-18 13:47:57 +0000
41+++ Makefile.am 2011-10-18 19:34:23 +0000
42@@ -20,6 +20,7 @@
43
44
45 ACLOCAL_MFLAGS = -I m4
46+AM_MAKEFLAGS = --no-print-directory
47
48 SUBDIRS = include libs libutouch-geis testsuite python tools examples doc
49
50
51=== modified file 'configure.ac'
52--- configure.ac 2011-08-31 19:53:52 +0000
53+++ configure.ac 2011-10-18 19:34:23 +0000
54@@ -95,12 +95,14 @@
55 doc/Makefile
56 include/Makefile
57 libs/Makefile
58+ libs/geis-dbus/Makefile
59 libs/xcb/Makefile
60 libs/xcb/xcb_gesture.xml
61 libutouch-geis/Makefile
62 libutouch-geis/backend/Makefile
63 libutouch-geis/backend/test_fixture/Makefile
64 libutouch-geis/backend/xcb/Makefile
65+ libutouch-geis/backend/dbus/Makefile
66 libutouch-geis/server/Makefile
67 testsuite/Makefile
68 testsuite/libutouch-geis/Makefile
69@@ -110,5 +112,6 @@
70 examples/Makefile
71 python/Makefile
72 tools/Makefile
73- tools/geisview/Makefile])
74+ tools/geisview/Makefile
75+ tools/geis-server/Makefile])
76 AC_OUTPUT
77
78=== modified file 'include/geis/geis.h'
79--- include/geis/geis.h 2011-08-17 04:26:54 +0000
80+++ include/geis/geis.h 2011-10-18 19:34:23 +0000
81@@ -459,18 +459,21 @@
82 * @name Vendor-defined Initialization Arguments
83 *
84 * @par
85- * These initialization arguments are not a part of te GEIS specification and
86+ * These initialization arguments are not a part of the GEIS specification and
87 * may change.
88 *
89 * @{
90 *
91- * @def GEIS_INIT_UTOUCH_MOCK_ENGINE
92- *
93- * @def GEIS_INIT_UTOUCH_XCB
94+ * @def GEIS_INIT_UTOUCH_MOCK_BACKEND
95+ *
96+ * @def GEIS_INIT_UTOUCH_DBUS_BACKEND
97+ *
98+ * @def GEIS_INIT_UTOUCH_XCB_BACKEND
99 */
100
101-#define GEIS_INIT_UTOUCH_MOCK_ENGINE "com.canonical.utouch.mock.engine"
102-#define GEIS_INIT_UTOUCH_XCB "com.canonical.utouch.xcb"
103+#define GEIS_INIT_UTOUCH_MOCK_BACKEND "com.canonical.utouch.backend.mock"
104+#define GEIS_INIT_UTOUCH_DBUS_BACKEND "com.canonical.utouch.backend.dbus"
105+#define GEIS_INIT_UTOUCH_XCB_BACKEND "com.canonical.utouch.backend.xcb"
106
107 /* @} */
108
109@@ -1302,7 +1305,7 @@
110 *
111 * @param[in] gesture_class The gesture class object.
112 *
113- * The reference count of teh object is decremented and, if it reaches zero, the
114+ * The reference count of the object is decremented and, if it reaches zero, the
115 * object is destroyed.
116 */
117 GEIS_API void geis_gesture_class_unref(GeisGestureClass gesture_class);
118@@ -1332,7 +1335,7 @@
119 GEIS_API GeisSize geis_gesture_class_attr_count(GeisGestureClass gesture_class);
120
121 /**
122- * Gets the indicated attribute of teh gesture class.
123+ * Gets the indicated attribute of the gesture class.
124 * @memberof GeisGestureClass
125 *
126 * @param[in] gesture_class The gesture class object.
127
128=== modified file 'libs/Makefile.am'
129--- libs/Makefile.am 2011-01-17 15:03:18 +0000
130+++ libs/Makefile.am 2011-10-18 19:34:23 +0000
131@@ -19,5 +19,5 @@
132 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
133 #
134
135-SUBDIRS = xcb
136+SUBDIRS = xcb geis-dbus
137
138
139=== added directory 'libs/geis-dbus'
140=== added file 'libs/geis-dbus/Makefile.am'
141--- libs/geis-dbus/Makefile.am 1970-01-01 00:00:00 +0000
142+++ libs/geis-dbus/Makefile.am 2011-10-18 19:34:23 +0000
143@@ -0,0 +1,41 @@
144+#
145+# @file libs/geis-dbus/Makefile.am
146+# @brief automake recipe for the uTouch GEIS v2.0 DBus helper library
147+#
148+# Copyright 2011 Canonical, Ltd.
149+#
150+# This file is part of the utouch-geis library. This library is free software;
151+# you can redistribute it and/or modify it under the terms of the GNU Lesser
152+# General Public License as published by the Free Software Foundation; either
153+# version 3 of the License, or (at your option) any later version.
154+#
155+# This library is distributed in the hope that it will be useful, but WITHOUT
156+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
157+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
158+# details.
159+#
160+# You should have received a copy of the GNU Lesser General Public License
161+# along with this program; if not, write to the Free Software Foundation, Inc.,
162+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
163+#
164+
165+noinst_LTLIBRARIES = libgeis-dbus.la
166+
167+dist_libgeis_dbus_la_SOURCES = \
168+ geis_dbus.h \
169+ geis_dbus_attr.h geis_dbus_attr.c \
170+ geis_dbus_class.h geis_dbus_class.c \
171+ geis_dbus_device.h geis_dbus_device.c \
172+ geis_dbus_dispatcher.h geis_dbus_dispatcher.c \
173+ geis_dbus_gesture_event.h geis_dbus_gesture_event.c \
174+ geis_dbus_region.h geis_dbus_region.c \
175+ geis_dbus_subscription.h geis_dbus_subscription.c
176+
177+libgeis_dbus_la_CPPFLAGS = \
178+ -I$(top_srcdir)/libutouch-geis \
179+ $(DBUS_CFLAGS)
180+
181+libgeis_dbus_la_LIBADD = \
182+ $(DBUS_LIBS)
183+
184+
185
186=== renamed file 'libutouch-geis/server/geis_dbus.h' => 'libs/geis-dbus/geis_dbus.h'
187--- libutouch-geis/server/geis_dbus.h 2011-01-31 12:25:35 +0000
188+++ libs/geis-dbus/geis_dbus.h 2011-10-18 19:34:23 +0000
189@@ -1,4 +1,9 @@
190 /**
191+ * @file geis_dbus.h
192+ * @brief Common definitions for the GEIS DBus module(s).
193+ */
194+
195+/*
196 * Copyright 2011 Canonical Ltd.
197 *
198 * This library is free software; you can redistribute it and/or modify it under
199@@ -11,12 +16,36 @@
200 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
201 * details.
202 *
203- * You should have received a copy of the GNU Lesser General Public License
204- * along with this program; if not, write to the Free Software Foundation, Inc.,
205- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
206+ * You should have received a copy of the GNU General Public License
207+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
208 */
209-
210-
211-#define GEIS_DBUS_BUS_NAME "com.canonical.utouch"
212-#define GEIS_REMOTE_FUNCTION "getAddress"
213-
214+#ifndef GEIS_DBUS_H_
215+#define GEIS_DBUS_H_
216+
217+#define GEIS_DBUS_SERVICE_PATH "/com/canonical/utouch/Geis"
218+#define GEIS_DBUS_SERVICE_INTERFACE "com.canonical.utouch.Geis"
219+
220+#define GEIS_DBUS_GET_SERVER_ADDRESS "GetServerAddress"
221+
222+#define GEIS_DBUS_INIT_COMPLETE "InitComplete"
223+
224+#define GEIS_DBUS_DEVICE_AVAILABLE "DeviceAvailable"
225+#define GEIS_DBUS_DEVICE_UNAVAILABLE "DeviceUnavailable"
226+
227+#define GEIS_DBUS_CLASS_AVAILABLE "ClassAvailable"
228+#define GEIS_DBUS_CLASS_UNAVAILABLE "ClassUnavailable"
229+
230+#define GEIS_DBUS_REGION_AVAILABLE "RegionAvailable"
231+#define GEIS_DBUS_REGION_UNAVAILABLE "RegionUnavailable"
232+
233+#define GEIS_DBUS_SUBSCRIPTION_CREATE "SubscriptionCreate"
234+#define GEIS_DBUS_SUBSCRIPTION_ACTIVATE "SubscriptionActivate"
235+#define GEIS_DBUS_SUBSCRIPTION_DEACTIVATE "SubscriptionDeactivate"
236+#define GEIS_DBUS_SUBSCRIPTION_DESTROY "SubscriptionDestroy"
237+
238+#define GEIS_DBUS_GESTURE_EVENT "GestureEvent"
239+
240+#define GEIS_DBUS_ERROR_SUBSCRIPTION_FAIL GEIS_DBUS_SERVICE_INTERFACE \
241+ ".SubscriptionFail"
242+
243+#endif /* GEIS_DBUS_H_ */
244
245=== added file 'libs/geis-dbus/geis_dbus_attr.c'
246--- libs/geis-dbus/geis_dbus_attr.c 1970-01-01 00:00:00 +0000
247+++ libs/geis-dbus/geis_dbus_attr.c 2011-10-18 19:34:23 +0000
248@@ -0,0 +1,178 @@
249+/**
250+ * @file geis_dbus_attr.c
251+ * @brief Implementation of the GEIS DBus attr transport.
252+ */
253+
254+/*
255+ * Copyright 2011 Canonical Ltd.
256+ *
257+ * This library is free software; you can redistribute it and/or modify it under
258+ * the terms of the GNU Lesser General Public License as published by the Free
259+ * Software Foundation; either version 3 of the License, or (at your option) any
260+ * later version.
261+ *
262+ * This library is distributed in the hope that it will be useful, but WITHOUT
263+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
264+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
265+ * details.
266+ *
267+ * You should have received a copy of the GNU General Public License
268+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
269+ */
270+#include "geis_config.h"
271+#include "geis_dbus_attr.h"
272+
273+#include "geis_attr.h"
274+#include "geis_logging.h"
275+
276+
277+/*
278+ * Marshalls a single GEIS attr to an open DBus message container iterator.
279+ */
280+void
281+geis_dbus_attr_marshall(GeisAttr attr, DBusMessageIter *iter)
282+{
283+ DBusMessageIter dict_iter;
284+ GeisString attr_name = geis_attr_name(attr);
285+
286+ dbus_message_iter_open_container(iter,
287+ DBUS_TYPE_STRUCT,
288+ NULL,
289+ &dict_iter);
290+ dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &attr_name);
291+ switch (geis_attr_type(attr))
292+ {
293+ case GEIS_ATTR_TYPE_BOOLEAN:
294+ {
295+ DBusMessageIter variant_iter;
296+ dbus_bool_t val = geis_attr_value_to_boolean(attr);
297+ dbus_message_iter_open_container(&dict_iter,
298+ DBUS_TYPE_VARIANT,
299+ DBUS_TYPE_BOOLEAN_AS_STRING,
300+ &variant_iter);
301+ dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_BOOLEAN, &val);
302+ dbus_message_iter_close_container(&dict_iter, &variant_iter);
303+ break;
304+ }
305+
306+ case GEIS_ATTR_TYPE_FLOAT:
307+ {
308+ DBusMessageIter variant_iter;
309+ double val = geis_attr_value_to_float(attr);
310+ dbus_message_iter_open_container(&dict_iter,
311+ DBUS_TYPE_VARIANT,
312+ DBUS_TYPE_DOUBLE_AS_STRING,
313+ &variant_iter);
314+ dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_DOUBLE, &val);
315+ dbus_message_iter_close_container(&dict_iter, &variant_iter);
316+ break;
317+ }
318+
319+ case GEIS_ATTR_TYPE_INTEGER:
320+ {
321+ DBusMessageIter variant_iter;
322+ dbus_int32_t val = geis_attr_value_to_integer(attr);
323+ dbus_message_iter_open_container(&dict_iter,
324+ DBUS_TYPE_VARIANT,
325+ DBUS_TYPE_INT32_AS_STRING,
326+ &variant_iter);
327+ dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_INT32, &val);
328+ dbus_message_iter_close_container(&dict_iter, &variant_iter);
329+ break;
330+ }
331+
332+ case GEIS_ATTR_TYPE_STRING:
333+ {
334+ DBusMessageIter variant_iter;
335+ GeisString val = geis_attr_value_to_string(attr);
336+ dbus_message_iter_open_container(&dict_iter,
337+ DBUS_TYPE_VARIANT,
338+ DBUS_TYPE_STRING_AS_STRING,
339+ &variant_iter);
340+ dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_STRING, &val);
341+ dbus_message_iter_close_container(&dict_iter, &variant_iter);
342+ break;
343+ }
344+
345+ default:
346+ geis_error("invalid attribute type for DBus");
347+ }
348+ dbus_message_iter_close_container(iter, &dict_iter);
349+}
350+
351+
352+/*
353+ * Unmarshalls a single GEIS attr from a DBus message iterator.
354+ */
355+GeisAttr
356+geis_dbus_attr_unmarshall(DBusMessageIter *iter)
357+{
358+ GeisAttr attr = NULL;
359+ DBusMessageIter dict_iter;
360+
361+ dbus_message_iter_recurse(iter, &dict_iter);
362+ int dtype = dbus_message_iter_get_arg_type(&dict_iter);
363+ if (dtype != DBUS_TYPE_STRING)
364+ {
365+ geis_error("error getting attr name from DBus message");
366+ goto final_exit;
367+ }
368+
369+ char *attr_name;
370+ dbus_message_iter_get_basic(&dict_iter, &attr_name);
371+
372+ dbus_message_iter_next(&dict_iter);
373+ dtype = dbus_message_iter_get_arg_type(&dict_iter);
374+ if (dtype != DBUS_TYPE_VARIANT)
375+ {
376+ geis_error("error getting attr variant from DBus message");
377+ goto final_exit;
378+ }
379+
380+ DBusMessageIter variant_iter;
381+ dbus_message_iter_recurse(&dict_iter, &variant_iter);
382+ int vtype = dbus_message_iter_get_arg_type(&variant_iter);
383+ switch (vtype)
384+ {
385+ case DBUS_TYPE_BOOLEAN:
386+ {
387+ dbus_bool_t val;
388+ dbus_message_iter_get_basic(&variant_iter, &val);
389+ attr = geis_attr_new(attr_name, GEIS_ATTR_TYPE_BOOLEAN, &val);
390+ break;
391+ }
392+
393+ case DBUS_TYPE_DOUBLE:
394+ {
395+ double dval;
396+ dbus_message_iter_get_basic(&variant_iter, &dval);
397+ float fval = dval;
398+ attr = geis_attr_new(attr_name, GEIS_ATTR_TYPE_FLOAT, &fval);
399+ break;
400+ }
401+
402+ case DBUS_TYPE_INT32:
403+ {
404+ dbus_int32_t val;
405+ dbus_message_iter_get_basic(&variant_iter, &val);
406+ attr = geis_attr_new(attr_name, GEIS_ATTR_TYPE_INTEGER, &val);
407+ break;
408+ }
409+
410+ case DBUS_TYPE_STRING:
411+ {
412+ GeisString val;
413+ dbus_message_iter_get_basic(&variant_iter, &val);
414+ attr = geis_attr_new(attr_name, GEIS_ATTR_TYPE_STRING, (void *)val);
415+ break;
416+ }
417+
418+ default:
419+ geis_error("unexpected attr data type from DBus");
420+ break;
421+ }
422+
423+final_exit:
424+ return attr;
425+}
426+
427
428=== added file 'libs/geis-dbus/geis_dbus_attr.h'
429--- libs/geis-dbus/geis_dbus_attr.h 1970-01-01 00:00:00 +0000
430+++ libs/geis-dbus/geis_dbus_attr.h 2011-10-18 19:34:23 +0000
431@@ -0,0 +1,57 @@
432+/**
433+ * @file geis_dbus_attr.h
434+ * @brief Interface for the GEIS DBus attr transport.
435+ */
436+
437+/*
438+ * Copyright 2011 Canonical Ltd.
439+ *
440+ * This library is free software; you can redistribute it and/or modify it under
441+ * the terms of the GNU Lesser General Public License as published by the Free
442+ * Software Foundation; either version 3 of the License, or (at your option) any
443+ * later version.
444+ *
445+ * This library is distributed in the hope that it will be useful, but WITHOUT
446+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
447+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
448+ * details.
449+ *
450+ * You should have received a copy of the GNU General Public License
451+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
452+ */
453+#ifndef GEIS_DBUS_ATTR_H_
454+#define GEIS_DBUS_ATTR_H_
455+
456+#include <dbus/dbus.h>
457+#include "geis/geis.h"
458+
459+
460+/**
461+ * The DBus type signature for a GEIS attrlist entry.
462+ */
463+#define GEIS_DBUS_TYPE_SIGNATURE_ATTR \
464+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING \
465+ DBUS_TYPE_STRING_AS_STRING \
466+ DBUS_TYPE_VARIANT_AS_STRING \
467+ DBUS_STRUCT_END_CHAR_AS_STRING
468+
469+/**
470+ * Marshalls a single GEIS attr to an open DBus message container iterator.
471+ *
472+ * @param[in] attr The GEIS attr.
473+ * @param[in] iter The DBus message iterator.
474+ */
475+void
476+geis_dbus_attr_marshall(GeisAttr attr, DBusMessageIter *iter);
477+
478+/**
479+ * Unmarshalls a single GEIS attr from a DBus message iterator.
480+ *
481+ * @param[in] iter The DBus message iterator.
482+ *
483+ * @returns a GEIS attribute or NULL on error.
484+ */
485+GeisAttr
486+geis_dbus_attr_unmarshall(DBusMessageIter *iter);
487+
488+#endif /* GEIS_DBUS_ATTR_H_ */
489
490=== added file 'libs/geis-dbus/geis_dbus_class.c'
491--- libs/geis-dbus/geis_dbus_class.c 1970-01-01 00:00:00 +0000
492+++ libs/geis-dbus/geis_dbus_class.c 2011-10-18 19:34:23 +0000
493@@ -0,0 +1,126 @@
494+/**
495+ * @file geis_dbus_gesture_class.c
496+ * @brief Implementations of the GEIS DBus gesture_class transport.
497+ */
498+
499+/*
500+ * Copyright 2011 Canonical Ltd.
501+ *
502+ * This library is free software; you can redistribute it and/or modify it under
503+ * the terms of the GNU Lesser General Public License as published by the Free
504+ * Software Foundation; either version 3 of the License, or (at your option) any
505+ * later version.
506+ *
507+ * This library is distributed in the hope that it will be useful, but WITHOUT
508+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
509+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
510+ * details.
511+ *
512+ * You should have received a copy of the GNU Lesser General Public License
513+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
514+ */
515+#include "geis_config.h"
516+#include "geis_dbus_class.h"
517+
518+#include "geis_dbus.h"
519+#include "geis_dbus_attr.h"
520+#include "geis_class.h"
521+#include "geis_logging.h"
522+
523+
524+/*
525+ * Creates a Dbus "gesture_class available" message from a GEIS gesture_class.
526+ *
527+ * The Wire protocol for this message is class_id and class_name followed by
528+ * the list of class attributes.
529+ */
530+DBusMessage *
531+geis_dbus_class_available_message_from_class(GeisGestureClass gesture_class)
532+{
533+ DBusMessage *message = dbus_message_new_signal(GEIS_DBUS_SERVICE_PATH,
534+ GEIS_DBUS_SERVICE_INTERFACE,
535+ GEIS_DBUS_CLASS_AVAILABLE);
536+ DBusMessageIter iter;
537+ dbus_message_iter_init_append(message, &iter);
538+
539+ dbus_int32_t gesture_class_id = geis_gesture_class_id(gesture_class);
540+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &gesture_class_id);
541+
542+ const char *gesture_class_name = geis_gesture_class_name(gesture_class);
543+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &gesture_class_name);
544+
545+ DBusMessageIter array_iter;
546+ dbus_message_iter_open_container(&iter,
547+ DBUS_TYPE_ARRAY,
548+ GEIS_DBUS_TYPE_SIGNATURE_ATTR,
549+ &array_iter);
550+ GeisSize attr_count = geis_gesture_class_attr_count(gesture_class);
551+ for (GeisSize i = 0; i < attr_count; ++i)
552+ {
553+ geis_dbus_attr_marshall(geis_gesture_class_attr(gesture_class, i),
554+ &array_iter);
555+ }
556+ dbus_message_iter_close_container(&iter, &array_iter);
557+ return message;
558+}
559+
560+
561+/*
562+ * Creates GEIS gesture_class from a DBus "gesture_class available" message.
563+ */
564+GeisGestureClass
565+geis_dbus_class_class_from_available_message(DBusMessage *message)
566+{
567+ GeisGestureClass gesture_class = NULL;
568+ DBusMessageIter iter;
569+ dbus_message_iter_init(message, &iter);
570+
571+ int type = dbus_message_iter_get_arg_type(&iter);
572+ if (type != DBUS_TYPE_INT32)
573+ {
574+ geis_error("error getting gesture_class ID from DBus message.");
575+ goto final_exit;
576+ }
577+ dbus_int32_t gesture_class_id;
578+ dbus_message_iter_get_basic(&iter, &gesture_class_id);
579+
580+ dbus_message_iter_next(&iter);
581+ type = dbus_message_iter_get_arg_type(&iter);
582+ if (type != DBUS_TYPE_STRING)
583+ {
584+ geis_error("error getting gesture_class name from DBus message.");
585+ goto final_exit;
586+ }
587+
588+ char *gesture_class_name;
589+ dbus_message_iter_get_basic(&iter, &gesture_class_name);
590+ gesture_class = geis_gesture_class_new(gesture_class_name, gesture_class_id);
591+
592+ dbus_message_iter_next(&iter);
593+ type = dbus_message_iter_get_arg_type(&iter);
594+ if (type != DBUS_TYPE_ARRAY)
595+ {
596+ geis_error("error getting gesture_class attr list from DBus message.");
597+ goto final_exit;
598+ }
599+
600+ DBusMessageIter array_iter;
601+ dbus_message_iter_recurse(&iter, &array_iter);
602+ int atype = dbus_message_iter_get_arg_type(&array_iter);
603+ while (atype == DBUS_TYPE_DICT_ENTRY)
604+ {
605+ GeisAttr attr = geis_dbus_attr_unmarshall(&array_iter);
606+ if (attr)
607+ {
608+ geis_gesture_class_add_attr(gesture_class, attr);
609+ }
610+
611+ dbus_message_iter_next(&array_iter);
612+ atype = dbus_message_iter_get_arg_type(&array_iter);
613+ }
614+
615+final_exit:
616+ return gesture_class;
617+}
618+
619+
620
621=== added file 'libs/geis-dbus/geis_dbus_class.h'
622--- libs/geis-dbus/geis_dbus_class.h 1970-01-01 00:00:00 +0000
623+++ libs/geis-dbus/geis_dbus_class.h 2011-10-18 19:34:23 +0000
624@@ -0,0 +1,45 @@
625+/**
626+ * @file geis_dbus_class.h
627+ * @brief Interface for the GEIS DBus gesture class transport.
628+ */
629+
630+/*
631+ * Copyright 2011 Canonical Ltd.
632+ *
633+ * This library is free software; you can redistribute it and/or modify it under
634+ * the terms of the GNU Lesser General Public License as published by the Free
635+ * Software Foundation; either version 3 of the License, or (at your option) any
636+ * later version.
637+ *
638+ * This library is distributed in the hope that it will be useful, but WITHOUT
639+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
640+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
641+ * details.
642+ *
643+ * You should have received a copy of the GNU General Public License
644+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
645+ */
646+#ifndef GEIS_DBUS_GESTURE_CLASS_H_
647+#define GEIS_DBUS_GESTURE_CLASS_H_
648+
649+#include <dbus/dbus.h>
650+#include "geis/geis.h"
651+
652+
653+/**
654+ * Creates a Dbus "class available" message from a GEIS class.
655+ *
656+ * @param[in] class A GEIS gesture class.
657+ */
658+DBusMessage *
659+geis_dbus_class_available_message_from_class(GeisGestureClass gesture_class);
660+
661+/**
662+ * Creates GEIS class from a DBus "class available" message.
663+ *
664+ * @param[in] message A DBus message.
665+ */
666+GeisGestureClass
667+geis_dbus_class_class_from_available_message(DBusMessage *message);
668+
669+#endif /* GEIS_DBUS_GESTURE_CLASS_H_ */
670
671=== added file 'libs/geis-dbus/geis_dbus_device.c'
672--- libs/geis-dbus/geis_dbus_device.c 1970-01-01 00:00:00 +0000
673+++ libs/geis-dbus/geis_dbus_device.c 2011-10-18 19:34:23 +0000
674@@ -0,0 +1,152 @@
675+/**
676+ * @file geis_dbus_device.c
677+ * @brief Implementations of the GEIS DBus device transport.
678+ */
679+
680+/*
681+ * Copyright 2011 Canonical Ltd.
682+ *
683+ * This library is free software; you can redistribute it and/or modify it under
684+ * the terms of the GNU Lesser General Public License as published by the Free
685+ * Software Foundation; either version 3 of the License, or (at your option) any
686+ * later version.
687+ *
688+ * This library is distributed in the hope that it will be useful, but WITHOUT
689+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
690+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
691+ * details.
692+ *
693+ * You should have received a copy of the GNU Lesser General Public License
694+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
695+ */
696+#include "geis_config.h"
697+#include "geis_dbus_device.h"
698+
699+#include "geis_dbus.h"
700+#include "geis_dbus_attr.h"
701+#include "geis_device.h"
702+#include "geis_logging.h"
703+
704+
705+/*
706+ * Creates a Dbus "device available" message from a GEIS device.
707+ *
708+ * The Wire protocol for this message is device_id and device_name followed by
709+ * the list of device attributes.
710+ */
711+DBusMessage *
712+geis_dbus_device_available_message_from_device(GeisDevice device)
713+{
714+ DBusMessage *message = dbus_message_new_signal(GEIS_DBUS_SERVICE_PATH,
715+ GEIS_DBUS_SERVICE_INTERFACE,
716+ GEIS_DBUS_DEVICE_AVAILABLE);
717+ DBusMessageIter iter;
718+ dbus_message_iter_init_append(message, &iter);
719+
720+ dbus_int32_t device_id = geis_device_id(device);
721+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &device_id);
722+
723+ const char *device_name = geis_device_name(device);
724+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &device_name);
725+
726+ DBusMessageIter array_iter;
727+ dbus_message_iter_open_container(&iter,
728+ DBUS_TYPE_ARRAY,
729+ GEIS_DBUS_TYPE_SIGNATURE_ATTR,
730+ &array_iter);
731+ GeisSize attr_count = geis_device_attr_count(device);
732+ for (GeisSize i = 0; i < attr_count; ++i)
733+ {
734+ geis_dbus_attr_marshall(geis_device_attr(device, i), &array_iter);
735+ }
736+ dbus_message_iter_close_container(&iter, &array_iter);
737+ return message;
738+}
739+
740+
741+/*
742+ * Creates GEIS device from a DBus "device available" message.
743+ */
744+GeisDevice
745+geis_dbus_device_device_from_available_message(DBusMessage *message)
746+{
747+ geis_debug("begins");
748+ GeisDevice device = NULL;
749+ DBusMessageIter iter;
750+ dbus_message_iter_init(message, &iter);
751+
752+ int type = dbus_message_iter_get_arg_type(&iter);
753+ if (type != DBUS_TYPE_INT32)
754+ {
755+ geis_error("error getting device ID from DBus message.");
756+ goto final_exit;
757+ }
758+ dbus_int32_t device_id;
759+ dbus_message_iter_get_basic(&iter, &device_id);
760+
761+ dbus_message_iter_next(&iter);
762+ type = dbus_message_iter_get_arg_type(&iter);
763+ if (type != DBUS_TYPE_STRING)
764+ {
765+ geis_error("error getting device name from DBus message.");
766+ goto final_exit;
767+ }
768+
769+ char *device_name;
770+ dbus_message_iter_get_basic(&iter, &device_name);
771+ device = geis_device_new(device_name, device_id);
772+
773+ dbus_message_iter_next(&iter);
774+ type = dbus_message_iter_get_arg_type(&iter);
775+ if (type != DBUS_TYPE_ARRAY)
776+ {
777+ geis_error("error getting device attr list from DBus message.");
778+ goto final_exit;
779+ }
780+
781+ DBusMessageIter array_iter;
782+ dbus_message_iter_recurse(&iter, &array_iter);
783+ int atype = dbus_message_iter_get_arg_type(&array_iter);
784+ while (atype == DBUS_TYPE_DICT_ENTRY)
785+ {
786+ GeisAttr attr = geis_dbus_attr_unmarshall(&array_iter);
787+ if (attr)
788+ {
789+ geis_device_add_attr(device, attr);
790+ }
791+
792+ dbus_message_iter_next(&array_iter);
793+ atype = dbus_message_iter_get_arg_type(&array_iter);
794+ }
795+
796+final_exit:
797+ geis_debug("ends");
798+ return device;
799+}
800+
801+
802+/*
803+ * Creates a Dbus "device unavailable" message from a GEIS device.
804+ */
805+DBusMessage *
806+geis_dbus_device_unavailable_message_from_device(GeisDevice device GEIS_UNUSED)
807+{
808+ geis_debug("begins");
809+ DBusMessage *message = NULL;
810+ geis_debug("ends");
811+ return message;
812+}
813+
814+
815+/*
816+ * Creates GEIS device from a DBus "device unavailable" message.
817+ */
818+GeisDevice
819+geis_dbus_device_device_from_unavailable_message(DBusMessage *message GEIS_UNUSED)
820+{
821+ geis_debug("begins");
822+ GeisDevice device = NULL;
823+ geis_debug("ends");
824+ return device;
825+}
826+
827
828=== added file 'libs/geis-dbus/geis_dbus_device.h'
829--- libs/geis-dbus/geis_dbus_device.h 1970-01-01 00:00:00 +0000
830+++ libs/geis-dbus/geis_dbus_device.h 2011-10-18 19:34:23 +0000
831@@ -0,0 +1,61 @@
832+/**
833+ * @file geis_dbus_device.h
834+ * @brief Interface for the GEIS DBus device transport.
835+ */
836+
837+/*
838+ * Copyright 2011 Canonical Ltd.
839+ *
840+ * This library is free software; you can redistribute it and/or modify it under
841+ * the terms of the GNU Lesser General Public License as published by the Free
842+ * Software Foundation; either version 3 of the License, or (at your option) any
843+ * later version.
844+ *
845+ * This library is distributed in the hope that it will be useful, but WITHOUT
846+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
847+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
848+ * details.
849+ *
850+ * You should have received a copy of the GNU General Public License
851+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
852+ */
853+#ifndef GEIS_DBUS_DEVICE_H_
854+#define GEIS_DBUS_DEVICE_H_
855+
856+#include <dbus/dbus.h>
857+#include "geis/geis.h"
858+
859+
860+/**
861+ * Creates a Dbus "device available" message from a GEIS device.
862+ *
863+ * @param[in] device A GEIS device.
864+ */
865+DBusMessage *
866+geis_dbus_device_available_message_from_device(GeisDevice device);
867+
868+/**
869+ * Creates GEIS device from a DBus "device available" message.
870+ *
871+ * @param[in] message A DBus message.
872+ */
873+GeisDevice
874+geis_dbus_device_device_from_available_message(DBusMessage *message);
875+
876+/**
877+ * Creates a Dbus "device unavailable" message from a GEIS device.
878+ *
879+ * @param[in] device A GEIS device.
880+ */
881+DBusMessage *
882+geis_dbus_device_unavailable_message_from_device(GeisDevice device);
883+
884+/**
885+ * Creates GEIS device from a DBus "device unavailable" message.
886+ *
887+ * @param[in] message A DBus message.
888+ */
889+GeisDevice
890+geis_dbus_device_device_from_unavailable_message(DBusMessage *message);
891+
892+#endif /* GEIS_DBUS_DEVICE_H_ */
893
894=== added file 'libs/geis-dbus/geis_dbus_dispatcher.c'
895--- libs/geis-dbus/geis_dbus_dispatcher.c 1970-01-01 00:00:00 +0000
896+++ libs/geis-dbus/geis_dbus_dispatcher.c 2011-10-18 19:34:23 +0000
897@@ -0,0 +1,486 @@
898+/**
899+ * @file geis_dbus_dispatcher.c
900+ * @brief Implementation of the GEIS DBus dispatcher.
901+ */
902+
903+/*
904+ * Copyright 2011 Canonical Ltd.
905+ *
906+ * This library is free software; you can redistribute it and/or modify it under
907+ * the terms of the GNU Lesser General Public License as published by the Free
908+ * Software Foundation; either version 3 of the License, or (at your option) any
909+ * later version.
910+ *
911+ * This library is distributed in the hope that it will be useful, but WITHOUT
912+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
913+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
914+ * details.
915+ *
916+ * You should have received a copy of the GNU General Public License
917+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
918+ */
919+#include "geis_config.h"
920+#include "geis_dbus_dispatcher.h"
921+
922+#include "geis_logging.h"
923+#include "geis_private.h"
924+#include <stdio.h>
925+#include <stdlib.h>
926+
927+
928+typedef struct GeisDBusWatch *GeisDBusWatch;
929+typedef struct GeisDBusWatchBag *GeisDBusWatchBag;
930+
931+/*
932+ * Connects a DBusWatch back to a DBusConnection.
933+ *
934+ * This is an intrusive linked list node. See GeisDBusWatchBag.
935+ */
936+struct GeisDBusWatch
937+{
938+ DBusConnection *connection;
939+ DBusWatch *watch;
940+ GeisDBusWatch next;
941+};
942+
943+
944+/*
945+ * Maps file descriptors to watches and connections.
946+ *
947+ * A DBusWatch is assciated with a single file descriptor, but each file
948+ * descriptor may be associated with more than one DBusWatch.
949+ *
950+ * Each DBusConnection has one or more DBusWatch. The DBusWatches are passed
951+ * around without reference to the connection itself, but we often need the
952+ * connection when all we have is the watch.
953+ *
954+ * To make things more complex, the DBusServer does not have a connection
955+ * associated with its watches.
956+ *
957+ * This is a linked list with a free pool.
958+ */
959+struct GeisDBusWatchBag
960+{
961+ GeisDBusWatch front;
962+ GeisDBusWatch back;
963+ GeisDBusWatch pool;
964+};
965+
966+static const int _geis_dbus_watch_bag_initial_size = 4;
967+
968+
969+struct GeisDBusDispatcher
970+{
971+ Geis geis;
972+ GeisDBusWatchBag watches;
973+};
974+
975+
976+/*
977+ * Creates a new empty collection of watches.
978+ *
979+ * The pool is primed with a few empty watches to save time later, on the
980+ * assumption that if you're creating a bag you're going to use it.
981+ */
982+static GeisDBusWatchBag
983+_geis_dbus_watch_bag_new()
984+{
985+ GeisDBusWatchBag bag = calloc(1, sizeof(struct GeisDBusWatchBag));
986+ if (!bag)
987+ {
988+ geis_error("error allocating GeisDBusWatchBag");
989+ goto final_exit;
990+ }
991+
992+ /* Prime the free pool. */
993+ for (int i = 0; i < _geis_dbus_watch_bag_initial_size; ++i)
994+ {
995+ GeisDBusWatch gdbw = calloc(1, sizeof(struct GeisDBusWatch));
996+ if (!gdbw)
997+ {
998+ geis_error("error allocating GeisDBusWatchBag");
999+ goto unwind_pool;
1000+ }
1001+ gdbw->next = bag->pool;
1002+ bag->pool = gdbw;
1003+ }
1004+ goto final_exit;
1005+
1006+unwind_pool:
1007+final_exit:
1008+ return bag;
1009+}
1010+
1011+
1012+/*
1013+ * Destroys a collection of watches.
1014+ *
1015+ * @param[in] bag A collection of %GeisDBusWatches.
1016+ *
1017+ * There should be no need to unref any of the contents of the bag, they can
1018+ * just be freed without consequence.
1019+ */
1020+static void
1021+_geis_dbus_watch_bag_delete(GeisDBusWatchBag bag)
1022+{
1023+ /* Free the pool. */
1024+ GeisDBusWatch gdbw = bag->pool;
1025+ while (gdbw)
1026+ {
1027+ GeisDBusWatch next = gdbw->next;
1028+ free(gdbw);
1029+ gdbw = next;
1030+ }
1031+
1032+ /* Free the in-use watches. */
1033+ gdbw = bag->front;
1034+ while (gdbw)
1035+ {
1036+ GeisDBusWatch next = gdbw->next;
1037+ free(gdbw);
1038+ gdbw = next;
1039+ }
1040+
1041+ free(bag);
1042+}
1043+
1044+
1045+/*
1046+ * Gets an allocated watch from the bag.
1047+ *
1048+ * @param[in] bag A collection of %GeisDBusWatches.
1049+ * @param[in] connection A DBusConnection.
1050+ * @param[in] watch A DBusWatch.
1051+ *
1052+ * A factory function to create a new watch in the collection and return a
1053+ * pointer to it.
1054+ */
1055+static GeisDBusWatch
1056+_geis_dbus_watch_bag_alloc_watch(GeisDBusWatchBag bag,
1057+ DBusConnection *connection,
1058+ DBusWatch *watch)
1059+{
1060+ GeisDBusWatch gdbw = NULL;
1061+
1062+ /* Either pull a free watch off the pool or allocate a new one. */
1063+ if (bag->pool)
1064+ {
1065+ gdbw = bag->pool;
1066+ bag->pool = bag->pool->next;
1067+ }
1068+ else
1069+ {
1070+ gdbw = calloc(1, sizeof(struct GeisDBusWatch));
1071+ if (!gdbw)
1072+ {
1073+ geis_error("error allocating GeisDBusWatchBag");
1074+ goto final_exit;
1075+ }
1076+ }
1077+
1078+ /* Fill in the data bits. */
1079+ gdbw->connection = connection;
1080+ gdbw->watch = watch;
1081+ gdbw->next = NULL;
1082+
1083+ /* Add it to the in-use list. */
1084+ if (!bag->front)
1085+ {
1086+ bag->front = gdbw;
1087+ }
1088+ if (bag->back)
1089+ {
1090+ bag->back->next = gdbw;
1091+ }
1092+ bag->back = gdbw;
1093+
1094+final_exit:
1095+ return gdbw;
1096+}
1097+
1098+
1099+/*
1100+ * Removes a watch from a collection of such beasts.
1101+ *
1102+ * @param[in] bag A collection of %GeisDBusWatches.
1103+ * @param[in] watch The watch to remove.
1104+ */
1105+static void
1106+_geis_dbus_watch_bag_remove_watch(GeisDBusWatchBag bag,
1107+ DBusWatch *watch)
1108+{
1109+ for (GeisDBusWatch gdbw = bag->front, prev = NULL; gdbw; gdbw = gdbw->next)
1110+ {
1111+ if (gdbw->watch == watch)
1112+ {
1113+ if (gdbw == bag->front)
1114+ {
1115+ bag->front = gdbw->next;
1116+ }
1117+ else
1118+ {
1119+ prev->next = gdbw->next;
1120+ }
1121+ if (gdbw == bag->back)
1122+ {
1123+ bag->back = prev;
1124+ }
1125+
1126+ gdbw->next = bag->pool;
1127+ bag->pool = gdbw;
1128+
1129+ break;
1130+ }
1131+ prev = gdbw;
1132+ }
1133+}
1134+
1135+
1136+/*
1137+ * Indicates if a file descriptor is already held in the watch bag.
1138+ *
1139+ * @param[in] bag A collection of %GeisDBusWatches.
1140+ * @param[in] fd A file descriptor.
1141+ * @param[out] flags The DBus watch flags for any enabled watches found.
1142+ *
1143+ * @returns zero if the file descriptor is not in the bag, non-zero otherwise.
1144+ */
1145+static int
1146+_geis_dbus_watch_bag_has_fd(GeisDBusWatchBag bag, int fd, unsigned int *flags)
1147+{
1148+ int has_fd = 0;
1149+ for (GeisDBusWatch gdbw = bag->front; gdbw; gdbw = gdbw->next)
1150+ {
1151+ if (dbus_watch_get_unix_fd(gdbw->watch) == fd)
1152+ {
1153+ has_fd |= ~0;
1154+ if (dbus_watch_get_enabled(gdbw->watch))
1155+ {
1156+ *flags |= dbus_watch_get_flags(gdbw->watch);
1157+ }
1158+ }
1159+ }
1160+ return has_fd;
1161+}
1162+
1163+
1164+/*
1165+ * Finds a DBusWatch in the bag that matches the fd and current activity.
1166+ *
1167+ * @param[in] bag A collection of %GeisDBusWatches.
1168+ * @param[in] fd The file descriptor on which an activity has been detected.
1169+ * @param[in] activity The bitmask of currently detected activity on the fd.
1170+ *
1171+ * A DBusWatch will match if it has the same file descriptor and is watching for
1172+ * (one of) the activity(ies) that has just occurred.
1173+ *
1174+ * Note that writers are implicitly looking for hangups or errors but the DBus
1175+ * library goes into an infinite loop when a hangup has occurred no a write
1176+ * watch, so defer that to a read watch.
1177+ *
1178+ * @returns a GeisDBusWatch or NULL if no matching watch was found.
1179+ */
1180+static GeisDBusWatch
1181+_geis_dbus_watch_bag_find_fd_activity(GeisDBusWatchBag bag,
1182+ int fd,
1183+ GeisBackendMultiplexorActivity activity)
1184+{
1185+ GeisDBusWatch gdbw = NULL;
1186+ for (gdbw = bag->front; gdbw; gdbw = gdbw->next)
1187+ {
1188+ if (dbus_watch_get_unix_fd(gdbw->watch) == fd)
1189+ {
1190+ unsigned int flags = dbus_watch_get_flags(gdbw->watch);
1191+ if ((activity & GEIS_BE_MX_READ_AVAILABLE && flags & DBUS_WATCH_READABLE)
1192+ || (activity & GEIS_BE_MX_WRITE_AVAILABLE && flags & DBUS_WATCH_WRITABLE)
1193+ || (activity & GEIS_BE_MX_HANGUP_DETECTED && flags & DBUS_WATCH_READABLE)
1194+ || (activity & GEIS_BE_MX_ERROR_DETECTED))
1195+ {
1196+ break;
1197+ }
1198+ }
1199+ }
1200+ return gdbw;
1201+}
1202+
1203+
1204+/*
1205+ * A callback function passed to the Geis multiplexor.
1206+ *
1207+ * @param[in] fd The file descriptor on which an activity has been detected.
1208+ * @param[in] activity The bitmask of currently detected activity on the fd.
1209+ * @param[in] context The %GeisDBusDispatcher passed through the multiplexor.
1210+ *
1211+ * This callback gets invoked whenever a requested activity is detected on a
1212+ * regostered DBusWatch file descriptor. It translates the GEIS Multiplexor
1213+ * activity to DBus activity.
1214+ */
1215+static void
1216+_geis_dbus_dispatcher_callback(int fd,
1217+ GeisBackendMultiplexorActivity activity,
1218+ void *context)
1219+{
1220+ GeisDBusDispatcher dispatcher = (GeisDBusDispatcher)context;
1221+ GeisDBusWatch gdb = _geis_dbus_watch_bag_find_fd_activity(dispatcher->watches,
1222+ fd,
1223+ activity);
1224+ if (gdb)
1225+ {
1226+ /* Translate GEIS multiplexor activity to DBus watch flags. */
1227+ unsigned int flags = 0;
1228+ if (activity & GEIS_BE_MX_READ_AVAILABLE) flags |= DBUS_WATCH_READABLE;
1229+ if (activity & GEIS_BE_MX_WRITE_AVAILABLE) flags |= DBUS_WATCH_WRITABLE;
1230+ if (activity & GEIS_BE_MX_HANGUP_DETECTED) flags |= DBUS_WATCH_HANGUP;
1231+ if (activity & GEIS_BE_MX_ERROR_DETECTED) flags |= DBUS_WATCH_ERROR;
1232+ dbus_watch_handle(gdb->watch, flags);
1233+
1234+ if (gdb->connection)
1235+ {
1236+ if (activity & GEIS_BE_MX_HANGUP_DETECTED)
1237+ {
1238+ dbus_connection_close(gdb->connection);
1239+ }
1240+ else
1241+ {
1242+ DBusDispatchStatus s;
1243+ s = dbus_connection_get_dispatch_status(gdb->connection);
1244+ while (DBUS_DISPATCH_DATA_REMAINS == s)
1245+ {
1246+ s = dbus_connection_dispatch(gdb->connection);
1247+ }
1248+ }
1249+ }
1250+ }
1251+}
1252+
1253+
1254+/*
1255+ * Creates a new GEIS DBus dispatcher.
1256+ */
1257+GeisDBusDispatcher
1258+geis_dbus_dispatcher_new(Geis geis)
1259+{
1260+ GeisDBusDispatcher dispatcher = calloc(1, sizeof(struct GeisDBusDispatcher));
1261+ if (!dispatcher)
1262+ {
1263+ geis_error("error allocating GEIS DBus dispatcher.");
1264+ goto final_exit;
1265+ }
1266+
1267+ dispatcher->geis = geis;
1268+ dispatcher->watches = _geis_dbus_watch_bag_new();
1269+ if (!dispatcher->watches)
1270+ {
1271+ geis_error("error creating GEIS DBus dispatcher watches.");
1272+ goto unwind_dispatcher;
1273+ }
1274+
1275+ goto final_exit;
1276+
1277+unwind_dispatcher:
1278+ free(dispatcher);
1279+final_exit:
1280+ return dispatcher;
1281+}
1282+
1283+
1284+/*
1285+ * Destroys an existing %GeisDBusDispatcher object.
1286+ */
1287+void
1288+geis_dbus_dispatcher_delete(GeisDBusDispatcher dispatcher)
1289+{
1290+ _geis_dbus_watch_bag_delete(dispatcher->watches);
1291+ free(dispatcher);
1292+ }
1293+
1294+
1295+/*
1296+ * Registers a new DBusWatch with a %GeisDBusDispatcher object.
1297+ */
1298+void
1299+geis_dbus_dispatcher_register(GeisDBusDispatcher dispatcher,
1300+ DBusConnection *connection,
1301+ DBusWatch *watch)
1302+{
1303+ int watch_fd = dbus_watch_get_unix_fd(watch);
1304+
1305+ /* Calculate all the enabled flags on the fd for all watches. */
1306+ unsigned int flags = 0;
1307+ int has_fd = _geis_dbus_watch_bag_has_fd(dispatcher->watches, watch_fd, &flags);
1308+ _geis_dbus_watch_bag_alloc_watch(dispatcher->watches, connection, watch);
1309+ if (dbus_watch_get_enabled(watch))
1310+ {
1311+ flags |= dbus_watch_get_flags(watch);
1312+ }
1313+
1314+ /* Convert the watch flags to multiplexor activities. */
1315+ GeisBackendMultiplexorActivity activity = 0;
1316+ if (flags & DBUS_WATCH_READABLE) activity |= GEIS_BE_MX_READ_AVAILABLE;
1317+ if (flags & DBUS_WATCH_WRITABLE) activity |= GEIS_BE_MX_WRITE_AVAILABLE;
1318+
1319+ /* Set or adjust the multiplexor seubscription. */
1320+ if (has_fd)
1321+ {
1322+ geis_remultiplex_fd(dispatcher->geis, watch_fd, activity);
1323+ }
1324+ else
1325+ {
1326+ geis_multiplex_fd(dispatcher->geis,
1327+ watch_fd,
1328+ activity,
1329+ _geis_dbus_dispatcher_callback,
1330+ dispatcher);
1331+ }
1332+}
1333+
1334+
1335+/*
1336+ * Unregisters a DBusWatch for events.
1337+ */
1338+void
1339+geis_dbus_dispatcher_unregister(GeisDBusDispatcher dispatcher,
1340+ DBusWatch *watch)
1341+{
1342+ int watch_fd = dbus_watch_get_unix_fd(watch);
1343+ unsigned int flags = 0;
1344+ _geis_dbus_watch_bag_remove_watch(dispatcher->watches, watch);
1345+ if (!_geis_dbus_watch_bag_has_fd(dispatcher->watches, watch_fd, &flags))
1346+ {
1347+ geis_demultiplex_fd(dispatcher->geis, watch_fd);
1348+ }
1349+}
1350+
1351+
1352+/*
1353+ * Marks a DBusWatch as active, maybe.
1354+ */
1355+void
1356+geis_dbus_dispatcher_toggle_watch(GeisDBusDispatcher dispatcher,
1357+ DBusWatch *watch)
1358+{
1359+ int watch_fd = dbus_watch_get_unix_fd(watch);
1360+
1361+ /* Calculate all the enabled flags on the fd for all watches. */
1362+ unsigned int flags = 0;
1363+ _geis_dbus_watch_bag_has_fd(dispatcher->watches, watch_fd, &flags);
1364+ if (dbus_watch_get_enabled(watch))
1365+ {
1366+ flags |= dbus_watch_get_flags(watch);
1367+ }
1368+ else
1369+ {
1370+ flags &= ~dbus_watch_get_flags(watch);
1371+ }
1372+
1373+ /* Convert the watch flags to multiplexor activities. */
1374+ GeisBackendMultiplexorActivity activity = 0;
1375+ if (flags & DBUS_WATCH_READABLE) activity |= GEIS_BE_MX_READ_AVAILABLE;
1376+ if (flags & DBUS_WATCH_WRITABLE) activity |= GEIS_BE_MX_WRITE_AVAILABLE;
1377+
1378+ /* Set or adjust the multiplexor seubscription. */
1379+ geis_remultiplex_fd(dispatcher->geis, watch_fd, activity);
1380+
1381+}
1382+
1383+
1384
1385=== added file 'libs/geis-dbus/geis_dbus_dispatcher.h'
1386--- libs/geis-dbus/geis_dbus_dispatcher.h 1970-01-01 00:00:00 +0000
1387+++ libs/geis-dbus/geis_dbus_dispatcher.h 2011-10-18 19:34:23 +0000
1388@@ -0,0 +1,116 @@
1389+/**
1390+ * @file geis_dbus_dispatcher.h
1391+ * @brief Interface for the GEIS DBus dispatcher.
1392+ *
1393+ * The GEIS DBus dispatcher provides a central dispatch point for all DBus
1394+ * events used internally by GEIS.
1395+ *
1396+ * This header is for internal GEIS use only and contains no client
1397+ * (externally-visible) symbols.
1398+ */
1399+
1400+/*
1401+ * Copyright 2011 Canonical Ltd.
1402+ *
1403+ * This library is free software; you can redistribute it and/or modify it under
1404+ * the terms of the GNU Lesser General Public License as published by the Free
1405+ * Software Foundation; either version 3 of the License, or (at your option) any
1406+ * later version.
1407+ *
1408+ * This library is distributed in the hope that it will be useful, but WITHOUT
1409+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1410+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1411+ * details.
1412+ *
1413+ * You should have received a copy of the GNU General Public License
1414+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1415+ */
1416+#ifndef GEIS_DBUS_DISPATCHER_H_
1417+#define GEIS_DBUS_DISPATCHER_H_
1418+
1419+#include <dbus/dbus.h>
1420+#include "geis/geis.h"
1421+
1422+
1423+/**
1424+ * The %GeisDBusDispatcher centralizes all dispatch for all DBus events used
1425+ * internally by the GEIS client-server mechanism.
1426+ *
1427+ * Geis implements single-threaded ansynchronous dispatch for DBus events, in
1428+ * case a single-threaded client is making use of GEIS. This also simplifies a
1429+ * lot of the internal design of the GEIS DBus service, since no locking or
1430+ * other forms of synchronization are required.
1431+ */
1432+typedef struct GeisDBusDispatcher *GeisDBusDispatcher;
1433+
1434+/**
1435+ * A callback type for the handler function dispatched on DBus events.
1436+ *
1437+ * @todo the parameters of the GeisDispatchCallback must be defined.
1438+ */
1439+typedef void (*GeisDispatchCallback)(void *context);
1440+
1441+
1442+/**
1443+ * Creates a new GEIS DBus dispatcher.
1444+ *
1445+ * @param[in] geis A GEIS instance.
1446+ *
1447+ * Creates a new %GeisDBusDispatcher and registers it with the GEIS API instance
1448+ * so it will be multiplexed and receive event notification.
1449+ *
1450+ * @returns a new %GeisDBusDispatcher object or NULL on failure.
1451+ */
1452+GeisDBusDispatcher
1453+geis_dbus_dispatcher_new(Geis geis);
1454+
1455+/**
1456+ * Destroys an existing %GeisDBusDispatcher object.
1457+ *
1458+ * @param[in] dispatcher A %GeisDBusDispatcher object.
1459+ */
1460+void
1461+geis_dbus_dispatcher_delete(GeisDBusDispatcher dispatcher);
1462+
1463+/**
1464+ * Registers a new DBusWatch with a %GeisDBusDispatcher object.
1465+ *
1466+ * @param[in] dispatcher A %GeisDBusDispatcher object.
1467+ * @param[in] connection A DBus connection.
1468+ * @param[in] watch A DBusWatch om the connection.
1469+ *
1470+ * The @p watch will be registered with the @p dispatcher for future DBus
1471+ * events. The @p watch may or may not be activated, depending on its @a
1472+ * enabled state at the time of registration.
1473+ */
1474+void
1475+geis_dbus_dispatcher_register(GeisDBusDispatcher dispatcher,
1476+ DBusConnection *connection,
1477+ DBusWatch *watch);
1478+
1479+/**
1480+ * Unregisters a DBusWatch for events.
1481+ *
1482+ * @param[in] dispatcher A %GeisDBusDispatcher object.
1483+ * @param[in] watch A DBusWatch.
1484+ */
1485+void
1486+geis_dbus_dispatcher_unregister(GeisDBusDispatcher dispatcher,
1487+ DBusWatch *watch);
1488+
1489+/**
1490+ * Marks a DBusWatch as active or not, depending on its state.
1491+ *
1492+ * @param[in] dispatcher A %GeisDBusDispatcher object.
1493+ * @param[in] watch A pointer to a DBusWatch object.
1494+ *
1495+ * The @p dispatcher will listen for events on the @p watch if its @a is_enabled
1496+ * state is true or not.
1497+ */
1498+void
1499+geis_dbus_dispatcher_toggle_watch(GeisDBusDispatcher dispatcher,
1500+ DBusWatch *watch);
1501+
1502+
1503+
1504+#endif /* GEIS_DBUS_DISPATCHER_H_ */
1505
1506=== added file 'libs/geis-dbus/geis_dbus_gesture_event.c'
1507--- libs/geis-dbus/geis_dbus_gesture_event.c 1970-01-01 00:00:00 +0000
1508+++ libs/geis-dbus/geis_dbus_gesture_event.c 2011-10-18 19:34:23 +0000
1509@@ -0,0 +1,573 @@
1510+/**
1511+ * @file geis_dbus_gesture_event.c
1512+ * @brief Implementation of the GEIS DBus gesture event transport.
1513+ */
1514+
1515+/*
1516+ * Copyright 2011 Canonical Ltd.
1517+ *
1518+ * This library is free software; you can redistribute it and/or modify it under
1519+ * the terms of the GNU Lesser General Public License as published by the Free
1520+ * Software Foundation; either version 3 of the License, or (at your option) any
1521+ * later version.
1522+ *
1523+ * This library is distributed in the hope that it will be useful, but WITHOUT
1524+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1525+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1526+ * details.
1527+ *
1528+ * You should have received a copy of the GNU General Public License
1529+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1530+ */
1531+#include "geis_config.h"
1532+#include "geis_dbus_gesture_event.h"
1533+
1534+#include "geis_attr.h"
1535+#include "geis_dbus.h"
1536+#include "geis_dbus_attr.h"
1537+#include "geis_event.h"
1538+#include "geis_group.h"
1539+#include "geis_logging.h"
1540+#include "geis_private.h"
1541+#include "geis_touch.h"
1542+
1543+/**
1544+ * A frame is marshalled as a dict entry of
1545+ * {id: [array of attrs, array of classes, array of touch ids]}, which is
1546+ * {i(a(sv)aiai))} in DBus terminaology.
1547+ */
1548+#define GEIS_DBUS_TYPE_SIGNATURE_FRAME \
1549+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING \
1550+ DBUS_TYPE_INT32_AS_STRING \
1551+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING \
1552+ DBUS_TYPE_ARRAY_AS_STRING \
1553+ GEIS_DBUS_TYPE_SIGNATURE_ATTR \
1554+ DBUS_TYPE_ARRAY_AS_STRING \
1555+ DBUS_TYPE_INT32_AS_STRING \
1556+ DBUS_TYPE_ARRAY_AS_STRING \
1557+ DBUS_TYPE_INT32_AS_STRING \
1558+ DBUS_STRUCT_END_CHAR_AS_STRING \
1559+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING \
1560+
1561+#define GEIS_DBUS_TYPE_SIGNATURE_FRAMESET \
1562+ DBUS_TYPE_ARRAY_AS_STRING \
1563+ GEIS_DBUS_TYPE_SIGNATURE_FRAME
1564+
1565+
1566+static void
1567+_marshall_touchset(GeisTouchSet touchset, DBusMessageIter *iter)
1568+{
1569+ DBusMessageIter touchset_iter;
1570+ dbus_message_iter_open_container(iter,
1571+ DBUS_TYPE_ARRAY,
1572+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1573+ DBUS_TYPE_INT32_AS_STRING
1574+ DBUS_TYPE_ARRAY_AS_STRING
1575+ GEIS_DBUS_TYPE_SIGNATURE_ATTR
1576+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1577+ &touchset_iter);
1578+ for (GeisSize t = 0; t < geis_touchset_touch_count(touchset); ++t)
1579+ {
1580+ DBusMessageIter touch_iter;
1581+ dbus_message_iter_open_container(&touchset_iter,
1582+ DBUS_TYPE_DICT_ENTRY,
1583+ NULL,
1584+ &touch_iter);
1585+ GeisTouch touch = geis_touchset_touch(touchset, t);
1586+ dbus_int32_t touch_id = geis_touch_id(touch);
1587+
1588+ dbus_message_iter_append_basic(&touch_iter, DBUS_TYPE_INT32, &touch_id);
1589+ DBusMessageIter attr_iter;
1590+ dbus_message_iter_open_container(&touch_iter,
1591+ DBUS_TYPE_ARRAY,
1592+ GEIS_DBUS_TYPE_SIGNATURE_ATTR,
1593+ &attr_iter);
1594+ for (GeisSize a = 0; a < geis_touch_attr_count(touch); ++a)
1595+ {
1596+ geis_dbus_attr_marshall(geis_touch_attr(touch, a), &attr_iter);
1597+ }
1598+ dbus_message_iter_close_container(&touch_iter, &attr_iter);
1599+ dbus_message_iter_close_container(&touchset_iter, &touch_iter);
1600+ }
1601+ dbus_message_iter_close_container(iter, &touchset_iter);
1602+}
1603+
1604+
1605+static void
1606+_unmarshall_touchset(DBusMessageIter *iter, GeisTouchSet touchset)
1607+{
1608+ int dtype = dbus_message_iter_get_arg_type(iter);
1609+ if (dtype != DBUS_TYPE_ARRAY)
1610+ {
1611+ geis_error("malformed GeisEvent touchset");
1612+ }
1613+
1614+ DBusMessageIter touch_iter;
1615+ dbus_message_iter_recurse(iter, &touch_iter);
1616+ for (dtype = dbus_message_iter_get_arg_type(&touch_iter);
1617+ dtype != DBUS_TYPE_INVALID;
1618+ dbus_message_iter_next(&touch_iter),
1619+ dtype = dbus_message_iter_get_arg_type(&touch_iter))
1620+ {
1621+ DBusMessageIter dict_iter;
1622+ dbus_message_iter_recurse(&touch_iter, &dict_iter);
1623+ int type = dbus_message_iter_get_arg_type(&dict_iter);
1624+ if (type != DBUS_TYPE_INT32)
1625+ {
1626+ geis_error("malformed GeisEvent touchset");
1627+ continue;
1628+ }
1629+ dbus_int32_t touch_id;
1630+ dbus_message_iter_get_basic(&dict_iter, &touch_id);
1631+ dbus_message_iter_next(&dict_iter);
1632+ GeisTouch touch = geis_touch_new(touch_id);
1633+
1634+ type = dbus_message_iter_get_arg_type(&dict_iter);
1635+ if (type != DBUS_TYPE_ARRAY)
1636+ {
1637+ geis_error("malformed GeisEvent touchset");
1638+ continue;
1639+ }
1640+
1641+ DBusMessageIter attr_iter;
1642+ dbus_message_iter_recurse(&dict_iter, &attr_iter);
1643+ for (int type = dbus_message_iter_get_arg_type(&attr_iter);
1644+ type != DBUS_TYPE_INVALID;
1645+ dbus_message_iter_next(&attr_iter),
1646+ type = dbus_message_iter_get_arg_type(&attr_iter))
1647+ {
1648+ GeisAttr attr = geis_dbus_attr_unmarshall(&attr_iter);
1649+ geis_touch_add_attr(touch, attr);
1650+ }
1651+ geis_touchset_insert(touchset, touch);
1652+ }
1653+}
1654+
1655+
1656+/**
1657+ * Marshalls a GEIS frame to a DBus message via a message iterator.
1658+ * @param[in] frame The GEIS frame to marshall.
1659+ * @param[in] iter The DBus message iterator.
1660+ *
1661+ * @todo The class set and matrix need to be added.
1662+ */
1663+static void
1664+_marshall_frame(GeisFrame frame, DBusMessageIter *frame_iter)
1665+{
1666+ DBusMessageIter dict_iter;
1667+ dbus_message_iter_open_container(frame_iter,
1668+ DBUS_TYPE_DICT_ENTRY,
1669+ NULL,
1670+ &dict_iter);
1671+
1672+ dbus_int32_t frame_id = geis_frame_id(frame);
1673+ dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_INT32, &frame_id);
1674+
1675+ {
1676+ DBusMessageIter struct_iter;
1677+ dbus_message_iter_open_container(&dict_iter,
1678+ DBUS_TYPE_STRUCT,
1679+ NULL,
1680+ &struct_iter);
1681+ {
1682+ DBusMessageIter attr_iter;
1683+ dbus_message_iter_open_container(&struct_iter,
1684+ DBUS_TYPE_ARRAY,
1685+ GEIS_DBUS_TYPE_SIGNATURE_ATTR,
1686+ &attr_iter);
1687+ for (GeisSize a = 0; a < geis_frame_attr_count(frame); ++a)
1688+ {
1689+ geis_dbus_attr_marshall(geis_frame_attr(frame, a), &attr_iter);
1690+ }
1691+ dbus_message_iter_close_container(&struct_iter, &attr_iter);
1692+ }
1693+ {
1694+ DBusMessageIter class_iter;
1695+ dbus_message_iter_open_container(&struct_iter,
1696+ DBUS_TYPE_ARRAY,
1697+ DBUS_TYPE_INT32_AS_STRING,
1698+ &class_iter);
1699+ for (GeisSize t = 0; t < geis_frame_class_count(frame); ++t)
1700+ {
1701+ GeisGestureClass frame_class = geis_frame_class(frame, t);
1702+ dbus_int32_t class_id = geis_gesture_class_id(frame_class);
1703+ dbus_message_iter_append_basic(&class_iter, DBUS_TYPE_INT32, &class_id);
1704+ }
1705+ dbus_message_iter_close_container(&struct_iter, &class_iter);
1706+ }
1707+ {
1708+ DBusMessageIter touch_iter;
1709+ dbus_message_iter_open_container(&struct_iter,
1710+ DBUS_TYPE_ARRAY,
1711+ DBUS_TYPE_INT32_AS_STRING,
1712+ &touch_iter);
1713+ for (GeisSize t = 0; t < geis_frame_touchid_count(frame); ++t)
1714+ {
1715+ dbus_int32_t touch_id = geis_frame_touchid(frame, t);
1716+ dbus_message_iter_append_basic(&touch_iter, DBUS_TYPE_INT32, &touch_id);
1717+ }
1718+ dbus_message_iter_close_container(&struct_iter, &touch_iter);
1719+ }
1720+ dbus_message_iter_close_container(&dict_iter, &struct_iter);
1721+ }
1722+ dbus_message_iter_close_container(frame_iter, &dict_iter);
1723+}
1724+
1725+
1726+/**
1727+ * Unmarshalls a GEIS frame from a DBus message via a message iterator.
1728+ * @param[in] frame_iter The DBus message iterator.
1729+ * @param[in] group The group the unmarshalled frame will belong to.
1730+ */
1731+static void
1732+_unmarshall_frame(Geis geis, DBusMessageIter *frame_iter, GeisGroup group)
1733+{
1734+ int type = dbus_message_iter_get_arg_type(frame_iter);
1735+ if (type != DBUS_TYPE_DICT_ENTRY)
1736+ {
1737+ geis_error("malformed GeisEvent frame: expected %c, received %c",
1738+ DBUS_TYPE_DICT_ENTRY, type);
1739+ goto final_exit;
1740+ }
1741+ DBusMessageIter dict_iter;
1742+ dbus_message_iter_recurse(frame_iter, &dict_iter);
1743+
1744+ type = dbus_message_iter_get_arg_type(&dict_iter);
1745+ if (type != DBUS_TYPE_INT32)
1746+ {
1747+ geis_error("malformed GeisEvent frame: expected %c, received %c",
1748+ DBUS_TYPE_INT32, type);
1749+ goto final_exit;
1750+ }
1751+ dbus_int32_t frame_id;
1752+ dbus_message_iter_get_basic(&dict_iter, &frame_id);
1753+ GeisFrame frame = geis_frame_new(frame_id);
1754+ geis_group_insert_frame(group, frame);
1755+
1756+ dbus_message_iter_next(&dict_iter);
1757+ type = dbus_message_iter_get_arg_type(&dict_iter);
1758+ if (type != DBUS_TYPE_STRUCT)
1759+ {
1760+ geis_error("malformed GeisEvent frame: expected %c, received %c",
1761+ DBUS_TYPE_STRUCT, type);
1762+ }
1763+ else
1764+ {
1765+ DBusMessageIter struct_iter;
1766+ dbus_message_iter_recurse(&dict_iter, &struct_iter);
1767+
1768+ type = dbus_message_iter_get_arg_type(&struct_iter);
1769+ if (type != DBUS_TYPE_ARRAY)
1770+ {
1771+ geis_error("malformed GeisEvent frame: expected %c, received %c",
1772+ DBUS_TYPE_ARRAY, type);
1773+ }
1774+ else
1775+ {
1776+ DBusMessageIter attr_iter;
1777+ dbus_message_iter_recurse(&struct_iter, &attr_iter);
1778+ for (int type = dbus_message_iter_get_arg_type(&attr_iter);
1779+ type != DBUS_TYPE_INVALID;
1780+ dbus_message_iter_next(&attr_iter),
1781+ type = dbus_message_iter_get_arg_type(&attr_iter))
1782+ {
1783+ GeisAttr attr = geis_dbus_attr_unmarshall(&attr_iter);
1784+ geis_frame_add_attr(frame, attr);
1785+ }
1786+ }
1787+
1788+ dbus_message_iter_next(&struct_iter),
1789+ type = dbus_message_iter_get_arg_type(&struct_iter);
1790+ if (type != DBUS_TYPE_ARRAY)
1791+ {
1792+ geis_error("malformed GeisEvent frame: expected %c, received %c",
1793+ DBUS_TYPE_ARRAY, type);
1794+ }
1795+ else
1796+ {
1797+ DBusMessageIter class_iter;
1798+ dbus_message_iter_recurse(&struct_iter, &class_iter);
1799+ for (int type = dbus_message_iter_get_arg_type(&class_iter);
1800+ type != DBUS_TYPE_INVALID;
1801+ dbus_message_iter_next(&class_iter),
1802+ type = dbus_message_iter_get_arg_type(&class_iter))
1803+ {
1804+ type = dbus_message_iter_get_arg_type(&class_iter);
1805+ if (type != DBUS_TYPE_INT32)
1806+ {
1807+ geis_error("malformed GeisEvent frame: expected %c, received %c",
1808+ DBUS_TYPE_INT32, type);
1809+ break;
1810+ }
1811+
1812+ dbus_int32_t class_id;
1813+ dbus_message_iter_get_basic(&class_iter, &class_id);
1814+ GeisGestureClassBag bag = geis_gesture_classes(geis);
1815+ for (GeisSize i = 0; i < geis_gesture_class_bag_count(bag); ++i)
1816+ {
1817+ GeisGestureClass gesture_class;
1818+ gesture_class = geis_gesture_class_bag_gesture_class(bag, i);
1819+ if (geis_gesture_class_id(gesture_class) == class_id)
1820+ {
1821+ geis_frame_set_is_class(frame, gesture_class);
1822+ break;
1823+ }
1824+ }
1825+ }
1826+ }
1827+
1828+ dbus_message_iter_next(&struct_iter),
1829+ type = dbus_message_iter_get_arg_type(&struct_iter);
1830+ if (type != DBUS_TYPE_ARRAY)
1831+ {
1832+ geis_error("malformed GeisEvent frame: expected %c, received %c",
1833+ DBUS_TYPE_ARRAY, type);
1834+ }
1835+ else
1836+ {
1837+ DBusMessageIter touch_iter;
1838+ dbus_message_iter_recurse(&struct_iter, &touch_iter);
1839+ for (int type = dbus_message_iter_get_arg_type(&touch_iter);
1840+ type != DBUS_TYPE_INVALID;
1841+ dbus_message_iter_next(&touch_iter),
1842+ type = dbus_message_iter_get_arg_type(&touch_iter))
1843+ {
1844+ type = dbus_message_iter_get_arg_type(&touch_iter);
1845+ if (type != DBUS_TYPE_INT32)
1846+ {
1847+ geis_error("malformed GeisEvent frame: expected %c, received %c",
1848+ DBUS_TYPE_INT32, type);
1849+ break;
1850+ }
1851+
1852+ dbus_int32_t touch_id;
1853+ dbus_message_iter_get_basic(&touch_iter, &touch_id);
1854+ geis_frame_add_touchid(frame, touch_id);
1855+ }
1856+ }
1857+ }
1858+
1859+final_exit:
1860+ return;
1861+}
1862+
1863+
1864+/**
1865+ * Marshalls a GEIS groupset to a DBus message via a message iterator.
1866+ * @param[in] groupset The GEIS groupset.
1867+ * @param[in] iter A DBus message iterator.
1868+ */
1869+static void
1870+_marshall_groupset(GeisGroupSet groupset, DBusMessageIter *iter)
1871+{
1872+ DBusMessageIter groupset_iter;
1873+ dbus_message_iter_open_container(iter,
1874+ DBUS_TYPE_ARRAY,
1875+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1876+ DBUS_TYPE_INT32_AS_STRING
1877+ GEIS_DBUS_TYPE_SIGNATURE_FRAMESET
1878+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1879+ &groupset_iter);
1880+ for (GeisSize i = 0; i < geis_groupset_group_count(groupset); ++i)
1881+ {
1882+ GeisGroup group = geis_groupset_group(groupset, i);
1883+ if (!group)
1884+ {
1885+ geis_warning("can not extract group %zu from groupset", i);
1886+ goto final_exit;
1887+ }
1888+ DBusMessageIter group_iter;
1889+ dbus_message_iter_open_container(&groupset_iter,
1890+ DBUS_TYPE_DICT_ENTRY,
1891+ NULL,
1892+ &group_iter);
1893+ dbus_int32_t group_id = geis_group_id(group);
1894+ dbus_message_iter_append_basic(&group_iter, DBUS_TYPE_INT32, &group_id);
1895+ DBusMessageIter frameset_iter;
1896+ dbus_message_iter_open_container(&group_iter,
1897+ DBUS_TYPE_ARRAY,
1898+ GEIS_DBUS_TYPE_SIGNATURE_FRAME,
1899+ &frameset_iter);
1900+ for (GeisSize j = 0; j < geis_group_frame_count(group); ++j)
1901+ {
1902+ GeisFrame frame = geis_group_frame(group, j);
1903+ if (!frame)
1904+ {
1905+ geis_warning("can not extract frame %zu from group", j);
1906+ goto final_exit;
1907+ }
1908+ _marshall_frame(frame, &frameset_iter);
1909+ }
1910+ dbus_message_iter_close_container(&group_iter, &frameset_iter);
1911+ dbus_message_iter_close_container(&groupset_iter, &group_iter);
1912+ }
1913+ dbus_message_iter_close_container(iter, &groupset_iter);
1914+
1915+final_exit:
1916+ return;
1917+}
1918+
1919+
1920+static void
1921+_unmarshall_groupset(Geis geis, DBusMessageIter *iter, GeisGroupSet groupset)
1922+{
1923+ int dtype = dbus_message_iter_get_arg_type(iter);
1924+ if (dtype != DBUS_TYPE_ARRAY)
1925+ {
1926+ geis_error("malformed GeisEvent groupset");
1927+ }
1928+
1929+ DBusMessageIter groupset_iter;
1930+ dbus_message_iter_recurse(iter, &groupset_iter);
1931+ for (dtype = dbus_message_iter_get_arg_type(&groupset_iter);
1932+ dtype != DBUS_TYPE_INVALID;
1933+ dbus_message_iter_next(&groupset_iter),
1934+ dtype = dbus_message_iter_get_arg_type(&groupset_iter))
1935+ {
1936+ DBusMessageIter group_iter;
1937+ dbus_message_iter_recurse(&groupset_iter, &group_iter);
1938+
1939+ int type = dbus_message_iter_get_arg_type(&group_iter);
1940+ if (type != DBUS_TYPE_INT32)
1941+ {
1942+ geis_error("malformed GeisEvent group");
1943+ continue;
1944+ }
1945+ dbus_int32_t group_id;
1946+ dbus_message_iter_get_basic(&group_iter, &group_id);
1947+ GeisGroup group = geis_group_new(group_id);
1948+ geis_groupset_insert(groupset, group);
1949+ dbus_message_iter_next(&group_iter);
1950+
1951+ DBusMessageIter frameset_iter;
1952+ dbus_message_iter_recurse(&group_iter, &frameset_iter);
1953+ for (int ftype = dbus_message_iter_get_arg_type(&frameset_iter);
1954+ ftype != DBUS_TYPE_INVALID;
1955+ dbus_message_iter_next(&frameset_iter),
1956+ ftype = dbus_message_iter_get_arg_type(&frameset_iter))
1957+ {
1958+ _unmarshall_frame(geis, &frameset_iter, group);
1959+ }
1960+ }
1961+}
1962+
1963+
1964+/*
1965+ * Creates a Dbus "gesture event" message from a GEIS gesture event.
1966+ *
1967+ * A gesture event has the following structure.
1968+ * - a numeric event type (begin/update/end)
1969+ * - a set of one or more touches, where each touch has
1970+ * - a touch ID
1971+ * - a set of one or more attrs
1972+ * - a set of one or more gesture groups, where is group has
1973+ * - a group ID
1974+ * - a set of one or more gesture frames, where each frame has
1975+ * - a set of one or more gesture classes
1976+ * - a set of one or more gesture attrs
1977+ * - a zet of one or more touch indexes
1978+ *
1979+ * @todo add the gesture classes
1980+ */
1981+DBusMessage *
1982+geis_dbus_gesture_event_message_from_geis_event(GeisEvent event)
1983+{
1984+ DBusMessage *message = dbus_message_new_signal(GEIS_DBUS_SERVICE_PATH,
1985+ GEIS_DBUS_SERVICE_INTERFACE,
1986+ GEIS_DBUS_GESTURE_EVENT);
1987+ DBusMessageIter iter;
1988+ dbus_message_iter_init_append(message, &iter);
1989+
1990+ dbus_uint32_t event_type = geis_event_type(event);
1991+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &event_type);
1992+
1993+ GeisAttr attr = geis_event_attr_by_name(event, GEIS_EVENT_ATTRIBUTE_TOUCHSET);
1994+ if (!attr)
1995+ {
1996+ geis_error("no touchset for gesture event");
1997+ goto final_exit;
1998+ }
1999+
2000+ GeisTouchSet touchset = geis_attr_value_to_pointer(attr);
2001+ if (!touchset)
2002+ {
2003+ geis_warning("can not convert attr to touchset");
2004+ goto final_exit;
2005+ }
2006+
2007+ _marshall_touchset(touchset, &iter);
2008+
2009+ attr = geis_event_attr_by_name(event, GEIS_EVENT_ATTRIBUTE_GROUPSET);
2010+ if (!attr)
2011+ {
2012+ geis_error("no groupset for gesture event");
2013+ goto final_exit;
2014+ }
2015+
2016+ GeisGroupSet groupset = geis_attr_value_to_pointer(attr);
2017+ if (!groupset)
2018+ {
2019+ geis_warning("can not convert attr to groupset");
2020+ goto final_exit;
2021+ }
2022+
2023+ _marshall_groupset(groupset, &iter);
2024+
2025+final_exit:
2026+ return message;
2027+}
2028+
2029+
2030+/*
2031+ * Indicates if a DBus message is a "gesture event" message.
2032+ */
2033+GeisBoolean
2034+geis_dbus_message_is_gesture_event(DBusMessage *message)
2035+{
2036+ GeisBoolean is_gesture_event_message = GEIS_FALSE;
2037+ if (dbus_message_is_signal(message,
2038+ GEIS_DBUS_SERVICE_INTERFACE,
2039+ GEIS_DBUS_GESTURE_EVENT))
2040+ {
2041+ is_gesture_event_message = GEIS_TRUE;
2042+ }
2043+
2044+ return is_gesture_event_message;
2045+}
2046+
2047+
2048+/*
2049+ * Creates GEIS event from a DBus "gesture_event" message.
2050+ */
2051+GeisEvent
2052+geis_dbus_gesture_event_from_message(Geis geis, DBusMessage *message)
2053+{
2054+ DBusMessageIter iter;
2055+ dbus_message_iter_init(message, &iter);
2056+
2057+ dbus_uint32_t event_type;
2058+ dbus_message_iter_get_basic(&iter, &event_type);
2059+ GeisEvent event = geis_event_new(event_type);
2060+
2061+ dbus_message_iter_next(&iter);
2062+ GeisTouchSet touchset = geis_touchset_new();
2063+ _unmarshall_touchset(&iter, touchset);
2064+ GeisAttr touch_attr = geis_attr_new(GEIS_EVENT_ATTRIBUTE_TOUCHSET,
2065+ GEIS_ATTR_TYPE_POINTER,
2066+ touchset);
2067+ geis_attr_set_destructor(touch_attr, (GeisAttrDestructor)geis_touchset_delete);
2068+ geis_event_add_attr(event, touch_attr);
2069+
2070+ dbus_message_iter_next(&iter);
2071+ GeisGroupSet groupset = geis_groupset_new();
2072+ _unmarshall_groupset(geis, &iter, groupset);
2073+ GeisAttr group_attr = geis_attr_new(GEIS_EVENT_ATTRIBUTE_GROUPSET,
2074+ GEIS_ATTR_TYPE_POINTER,
2075+ groupset);
2076+ geis_attr_set_destructor(group_attr, (GeisAttrDestructor)geis_groupset_delete);
2077+ geis_event_add_attr(event, group_attr);
2078+
2079+ return event;
2080+}
2081+
2082+
2083
2084=== added file 'libs/geis-dbus/geis_dbus_gesture_event.h'
2085--- libs/geis-dbus/geis_dbus_gesture_event.h 1970-01-01 00:00:00 +0000
2086+++ libs/geis-dbus/geis_dbus_gesture_event.h 2011-10-18 19:34:23 +0000
2087@@ -0,0 +1,55 @@
2088+/**
2089+ * @file geis_dbus_gesture_event.h
2090+ * @brief Interface for the GEIS DBus gesture event transport.
2091+ */
2092+
2093+/*
2094+ * Copyright 2011 Canonical Ltd.
2095+ *
2096+ * This library is free software; you can redistribute it and/or modify it under
2097+ * the terms of the GNU Lesser General Public License as published by the Free
2098+ * Software Foundation; either version 3 of the License, or (at your option) any
2099+ * later version.
2100+ *
2101+ * This library is distributed in the hope that it will be useful, but WITHOUT
2102+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2103+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
2104+ * details.
2105+ *
2106+ * You should have received a copy of the GNU General Public License
2107+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2108+ */
2109+#ifndef GEIS_DBUS_GESTURE_EVENT_H_
2110+#define GEIS_DBUS_GESTURE_EVENT_H_
2111+
2112+#include <dbus/dbus.h>
2113+#include "geis/geis.h"
2114+
2115+
2116+/**
2117+ * Creates a Dbus "gesture event" message from a GEIS gesture event.
2118+ *
2119+ * @param[in] event A GEIS event.
2120+ */
2121+DBusMessage *
2122+geis_dbus_gesture_event_message_from_geis_event(GeisEvent event);
2123+
2124+/**
2125+ * Indicates if a DBus message is a "gesture event" message.
2126+ *
2127+ * @param[in] message A DBus message.
2128+ */
2129+GeisBoolean
2130+geis_dbus_message_is_gesture_event(DBusMessage *message);
2131+
2132+/**
2133+ * Creates GEIS event from a DBus "gesture_event" message.
2134+ *
2135+ * @param[in] message A DBus message.
2136+ */
2137+GeisEvent
2138+geis_dbus_gesture_event_from_message(Geis geis, DBusMessage *message);
2139+
2140+
2141+#endif /* GEIS_DBUS_GESTURE_EVENT_H_ */
2142+
2143
2144=== added file 'libs/geis-dbus/geis_dbus_region.c'
2145--- libs/geis-dbus/geis_dbus_region.c 1970-01-01 00:00:00 +0000
2146+++ libs/geis-dbus/geis_dbus_region.c 2011-10-18 19:34:23 +0000
2147@@ -0,0 +1,91 @@
2148+/**
2149+ * @file geis_dbus_region.c
2150+ * @brief Implementations of the GEIS DBus region transport.
2151+ */
2152+
2153+/*
2154+ * Copyright 2011 Canonical Ltd.
2155+ *
2156+ * This library is free software; you can redistribute it and/or modify it under
2157+ * the terms of the GNU Lesser General Public License as published by the Free
2158+ * Software Foundation; either version 3 of the License, or (at your option) any
2159+ * later version.
2160+ *
2161+ * This library is distributed in the hope that it will be useful, but WITHOUT
2162+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2163+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
2164+ * details.
2165+ *
2166+ * You should have received a copy of the GNU Lesser General Public License
2167+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2168+ */
2169+#include "geis_config.h"
2170+#include "geis_dbus_region.h"
2171+
2172+#include "geis_dbus.h"
2173+#include "geis_logging.h"
2174+
2175+
2176+/*
2177+ * Creates a Dbus "region available" message from a GEIS region.
2178+ */
2179+DBusMessage *
2180+geis_dbus_region_available_message_from_region(GeisFilterableAttribute fa)
2181+{
2182+ DBusMessage *message = dbus_message_new_signal(GEIS_DBUS_SERVICE_PATH,
2183+ GEIS_DBUS_SERVICE_INTERFACE,
2184+ GEIS_DBUS_REGION_AVAILABLE);
2185+ DBusMessageIter iter;
2186+ dbus_message_iter_init_append(message, &iter);
2187+
2188+ const char *attr_name = fa->name;
2189+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &attr_name);
2190+
2191+ dbus_int32_t attr_type = fa->type;
2192+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &attr_type);
2193+
2194+
2195+ return message;
2196+}
2197+
2198+
2199+/*
2200+ * Creates GEIS region filterable attribute from a DBus "region available"
2201+ * message.
2202+ */
2203+GeisFilterableAttribute
2204+geis_dbus_region_from_region_available_message(DBusMessage *message)
2205+{
2206+ geis_debug("begins");
2207+ static struct GeisFilterableAttribute attr;
2208+ DBusMessageIter iter;
2209+ dbus_message_iter_init(message, &iter);
2210+
2211+ int type = dbus_message_iter_get_arg_type(&iter);
2212+ if (type != DBUS_TYPE_STRING)
2213+ {
2214+ geis_error("error getting attr name name from DBus message.");
2215+ goto final_exit;
2216+ }
2217+ char *attr_name;
2218+ dbus_message_iter_get_basic(&iter, &attr_name);
2219+ dbus_message_iter_next(&iter);
2220+
2221+ type = dbus_message_iter_get_arg_type(&iter);
2222+ if (type != DBUS_TYPE_INT32)
2223+ {
2224+ geis_error("error getting attr type from DBus message.");
2225+ goto final_exit;
2226+ }
2227+ dbus_int32_t attr_type;
2228+ dbus_message_iter_get_basic(&iter, &attr_type);
2229+
2230+ attr.name = attr_name;
2231+ attr.type = attr_type;
2232+
2233+final_exit:
2234+ geis_debug("ends");
2235+ return &attr;
2236+}
2237+
2238+
2239
2240=== added file 'libs/geis-dbus/geis_dbus_region.h'
2241--- libs/geis-dbus/geis_dbus_region.h 1970-01-01 00:00:00 +0000
2242+++ libs/geis-dbus/geis_dbus_region.h 2011-10-18 19:34:23 +0000
2243@@ -0,0 +1,47 @@
2244+/**
2245+ * @file geis_dbus_region.h
2246+ * @brief Interface for the GEIS DBus region transport.
2247+ */
2248+
2249+/*
2250+ * Copyright 2011 Canonical Ltd.
2251+ *
2252+ * This library is free software; you can redistribute it and/or modify it under
2253+ * the terms of the GNU Lesser General Public License as published by the Free
2254+ * Software Foundation; either version 3 of the License, or (at your option) any
2255+ * later version.
2256+ *
2257+ * This library is distributed in the hope that it will be useful, but WITHOUT
2258+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2259+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
2260+ * details.
2261+ *
2262+ * You should have received a copy of the GNU General Public License
2263+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2264+ */
2265+#ifndef GEIS_DBUS_REGION_H_
2266+#define GEIS_DBUS_REGION_H_
2267+
2268+#include <dbus/dbus.h>
2269+#include "geis/geis.h"
2270+#include "geis_filterable.h"
2271+
2272+
2273+/**
2274+ * Creates a Dbus "region available" message from a GEIS region.
2275+ *
2276+ * @param[in] fa A GEIS region filterable attribute.
2277+ */
2278+DBusMessage *
2279+geis_dbus_region_available_message_from_region(GeisFilterableAttribute fa);
2280+
2281+/**
2282+ * Creates GEIS region filterable attribute from a DBus "region available"
2283+ * message.
2284+ *
2285+ * @param[in] message A DBus message.
2286+ */
2287+GeisFilterableAttribute
2288+geis_dbus_region_from_region_available_message(DBusMessage *message);
2289+
2290+#endif /* GEIS_DBUS_REGION_H_ */
2291
2292=== added file 'libs/geis-dbus/geis_dbus_subscription.c'
2293--- libs/geis-dbus/geis_dbus_subscription.c 1970-01-01 00:00:00 +0000
2294+++ libs/geis-dbus/geis_dbus_subscription.c 2011-10-18 19:34:23 +0000
2295@@ -0,0 +1,506 @@
2296+/**
2297+ * @file geis_dbus_subscription.c
2298+ * @brief Implementation of the GEIS DBus subscription transport.
2299+ */
2300+
2301+/*
2302+ * Copyright 2011 Canonical Ltd.
2303+ *
2304+ * This library is free software; you can redistribute it and/or modify it under
2305+ * the terms of the GNU Lesser General Public License as published by the Free
2306+ * Software Foundation; either version 3 of the License, or (at your option) any
2307+ * later version.
2308+ *
2309+ * This library is distributed in the hope that it will be useful, but WITHOUT
2310+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2311+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
2312+ * details.
2313+ *
2314+ * You should have received a copy of the GNU General Public License
2315+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2316+ */
2317+#include "geis_config.h"
2318+#include "geis_dbus_subscription.h"
2319+
2320+#include "geis_dbus.h"
2321+#include "geis_dbus_attr.h"
2322+#include "geis_filter_term.h"
2323+#include "geis_logging.h"
2324+#include "geis_subscription.h"
2325+#include <stdint.h>
2326+
2327+
2328+/*
2329+ * A filter term is marshalled as a (facility, operation, value) tuple.
2330+ * That would be a (ii(sv)) in DBusspeak.
2331+ */
2332+#define GEIS_DBUS_TYPE_SIGNATURE_TERM \
2333+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING \
2334+ DBUS_TYPE_INT32_AS_STRING \
2335+ DBUS_TYPE_INT32_AS_STRING \
2336+ GEIS_DBUS_TYPE_SIGNATURE_ATTR \
2337+ DBUS_STRUCT_END_CHAR_AS_STRING
2338+
2339+/*
2340+ * A term list is an array of terms, as in a(ii(sv)).
2341+ */
2342+#define GEIS_DBUS_TYPE_SIGNATURE_TERM_LIST \
2343+ DBUS_TYPE_ARRAY_AS_STRING \
2344+ GEIS_DBUS_TYPE_SIGNATURE_TERM
2345+
2346+/*
2347+ * A filter is a named array of filter terms.
2348+ * That's a {sa(ii(sv))} in the DBus tongue.
2349+ */
2350+#define GEIS_DBUS_TYPE_SIGNATURE_FILTER \
2351+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING \
2352+ DBUS_TYPE_STRING_AS_STRING \
2353+ GEIS_DBUS_TYPE_SIGNATURE_TERM_LIST \
2354+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
2355+
2356+
2357+/**
2358+ * Adds filter terms to a DBus message.
2359+ *
2360+ * @param[in] filter The filter for which terms will be marshalled.
2361+ * @param[in] filter_iter A DBus message output iterator.
2362+ */
2363+static void
2364+_geis_dbus_marshall_subscription_filter_terms(GeisFilter filter,
2365+ DBusMessageIter *filter_iter)
2366+{
2367+ DBusMessageIter term_list_iter;
2368+ dbus_message_iter_open_container(filter_iter,
2369+ DBUS_TYPE_ARRAY,
2370+ GEIS_DBUS_TYPE_SIGNATURE_TERM,
2371+ &term_list_iter);
2372+ for (GeisSize i = 0; i < geis_filter_term_count(filter); ++i)
2373+ {
2374+ GeisFilterTerm term = geis_filter_term(filter, i);
2375+ dbus_int32_t facility = geis_filter_term_facility(term);
2376+ dbus_int32_t operation = geis_filter_term_operation(term);
2377+ GeisAttr attr = geis_filter_term_attr(term);
2378+
2379+ DBusMessageIter term_iter;
2380+ dbus_message_iter_open_container(&term_list_iter,
2381+ DBUS_TYPE_STRUCT,
2382+ NULL,
2383+ &term_iter);
2384+ dbus_message_iter_append_basic(&term_iter, DBUS_TYPE_INT32, &facility);
2385+ dbus_message_iter_append_basic(&term_iter, DBUS_TYPE_INT32, &operation);
2386+ geis_dbus_attr_marshall(attr, &term_iter);
2387+ dbus_message_iter_close_container(&term_list_iter, &term_iter);
2388+ }
2389+ dbus_message_iter_close_container(filter_iter, &term_list_iter);
2390+}
2391+
2392+
2393+/**
2394+ * Squeezes the filters on a subscription into the DBus wire protocol.
2395+ *
2396+ * @param[in] sub A %GeisSubscription
2397+ * @param[in] msg_iter The open output iterator for a DBus message.
2398+ *
2399+ * The filters are marshalled as an array of DBus dict entries.
2400+ */
2401+static void
2402+_geis_dbus_marshall_subscription_filters(GeisSubscription subscription,
2403+ DBusMessageIter *msg_iter)
2404+{
2405+ DBusMessageIter filter_list_iter;
2406+
2407+ dbus_message_iter_open_container(msg_iter,
2408+ DBUS_TYPE_ARRAY,
2409+ GEIS_DBUS_TYPE_SIGNATURE_FILTER,
2410+ &filter_list_iter);
2411+
2412+ for (GeisFilterIterator it = geis_subscription_filter_begin(subscription);
2413+ it != geis_subscription_filter_end(subscription);
2414+ it = geis_subscription_filter_next(subscription, it))
2415+ {
2416+ const char *filter_name = geis_filter_name(*it);
2417+
2418+ DBusMessageIter filter_iter;
2419+ dbus_message_iter_open_container(&filter_list_iter,
2420+ DBUS_TYPE_DICT_ENTRY,
2421+ NULL,
2422+ &filter_iter);
2423+ dbus_message_iter_append_basic(&filter_iter, DBUS_TYPE_STRING, &filter_name);
2424+ _geis_dbus_marshall_subscription_filter_terms(*it, &filter_iter);
2425+ dbus_message_iter_close_container(&filter_list_iter, &filter_iter);
2426+ }
2427+ dbus_message_iter_close_container(msg_iter, &filter_list_iter);
2428+}
2429+
2430+
2431+static void
2432+_geis_dbus_unmarshall_filter_terms(GeisFilter filter,
2433+ DBusMessageIter *filter_iter)
2434+{
2435+ DBusMessageIter term_list_iter;
2436+ dbus_message_iter_recurse(filter_iter, &term_list_iter);
2437+ for (int dtype = dbus_message_iter_get_arg_type(&term_list_iter);
2438+ dtype != DBUS_TYPE_INVALID;
2439+ dbus_message_iter_next(&term_list_iter),
2440+ dtype = dbus_message_iter_get_arg_type(&term_list_iter))
2441+ {
2442+ int ttype = dbus_message_iter_get_arg_type(&term_list_iter);
2443+ if (ttype != DBUS_TYPE_STRUCT)
2444+ {
2445+ geis_error("malformed GeisSubscription term");
2446+ goto final_exit;
2447+ }
2448+
2449+ DBusMessageIter term_iter;
2450+ dbus_message_iter_recurse(&term_list_iter, &term_iter);
2451+
2452+ dbus_int32_t facility;
2453+ dbus_message_iter_get_basic(&term_iter, &facility);
2454+ dbus_message_iter_next(&term_iter);
2455+
2456+ dbus_int32_t operation;
2457+ dbus_message_iter_get_basic(&term_iter, &operation);
2458+ dbus_message_iter_next(&term_iter);
2459+
2460+ GeisAttr attr = geis_dbus_attr_unmarshall(&term_iter);
2461+ GeisFilterTerm term = geis_filter_term_new(facility, operation, attr);
2462+ geis_filter_add_term_internal(filter, term);
2463+ }
2464+
2465+final_exit:
2466+ return;
2467+}
2468+
2469+
2470+/**
2471+ * Unmarshalls a filter from a DBus message.
2472+ *
2473+ * @param[in] geis A GEIS instance.
2474+ * @param[in] filter_iter A DBus message iterator pointing to the filter.
2475+ */
2476+static GeisFilter
2477+_geis_dbus_unmarshall_filter(Geis geis, DBusMessageIter *filter_iter)
2478+{
2479+ GeisFilter filter = NULL;
2480+
2481+ int ftype = dbus_message_iter_get_arg_type(filter_iter);
2482+ if (ftype != DBUS_TYPE_DICT_ENTRY)
2483+ {
2484+ geis_error("malformed GeisSubscription filter");
2485+ goto final_exit;
2486+ }
2487+
2488+ DBusMessageIter dict_iter;
2489+ dbus_message_iter_recurse(filter_iter, &dict_iter);
2490+
2491+ ftype = dbus_message_iter_get_arg_type(&dict_iter);
2492+ if (ftype != DBUS_TYPE_STRING)
2493+ {
2494+ geis_error("malformed GeisSubscription filter");
2495+ goto final_exit;
2496+ }
2497+ GeisString filter_name;
2498+ dbus_message_iter_get_basic(&dict_iter, &filter_name);
2499+ dbus_message_iter_next(&dict_iter);
2500+
2501+ filter = geis_filter_new(geis, filter_name);
2502+
2503+ ftype = dbus_message_iter_get_arg_type(&dict_iter);
2504+ if (ftype != DBUS_TYPE_ARRAY)
2505+ {
2506+ geis_error("malformed GeisSubscription filter");
2507+ goto final_exit;
2508+ }
2509+ _geis_dbus_unmarshall_filter_terms(filter, &dict_iter);
2510+
2511+final_exit:
2512+ return filter;
2513+}
2514+
2515+
2516+/**
2517+ * Unmarshalls a list of filters from a DBus message.
2518+ *
2519+ * @param[in] geis A GEIS instance.
2520+ * @param[in] subscription_iter A DBus message iterator for the subscription.
2521+ * @param[in] subscription A GEIS subsccription.
2522+ *
2523+ * This function unmarshalls filters from a GEIS DBus subscription message and
2524+ * adds them to a existing GEIS subscription.
2525+ */
2526+static void
2527+_geis_dbus_unmarshall_subscription_filters(Geis geis,
2528+ DBusMessageIter *subscription_iter,
2529+ GeisSubscription subscription)
2530+{
2531+ DBusMessageIter filter_list_iter;
2532+ dbus_message_iter_recurse(subscription_iter, &filter_list_iter);
2533+ for (int dtype = dbus_message_iter_get_arg_type(&filter_list_iter);
2534+ dtype != DBUS_TYPE_INVALID;
2535+ dbus_message_iter_next(&filter_list_iter),
2536+ dtype = dbus_message_iter_get_arg_type(&filter_list_iter))
2537+ {
2538+ GeisFilter filter = _geis_dbus_unmarshall_filter(geis, &filter_list_iter);
2539+ if (filter)
2540+ {
2541+ geis_subscription_add_filter(subscription, filter);
2542+ }
2543+ }
2544+}
2545+
2546+
2547+/*
2548+ * Indicates if a DBus message is a GEIS_DBUS_SUBSCRIPTION_CREATE method call.
2549+ */
2550+GeisBoolean
2551+geis_dbus_message_is_subscription_create_call(DBusMessage *message)
2552+{
2553+ return dbus_message_is_method_call(message,
2554+ GEIS_DBUS_SERVICE_INTERFACE,
2555+ GEIS_DBUS_SUBSCRIPTION_CREATE);
2556+}
2557+
2558+
2559+/*
2560+ * Creates a GEIS_DBUS_SUBSCRIPTION_CREATE method call message.
2561+ */
2562+DBusMessage *
2563+geis_dbus_subscription_create_call_message(GeisSubscription subscription)
2564+{
2565+ DBusMessage *message = NULL;
2566+ GeisString sub_name = "dummy";
2567+ dbus_int32_t sub_id = -1;
2568+ dbus_uint32_t sub_flags = 0;
2569+ DBusMessageIter iter;
2570+
2571+ message = dbus_message_new_method_call(GEIS_DBUS_SERVICE_INTERFACE,
2572+ GEIS_DBUS_SERVICE_PATH,
2573+ GEIS_DBUS_SERVICE_INTERFACE,
2574+ GEIS_DBUS_SUBSCRIPTION_CREATE);
2575+
2576+ if (subscription)
2577+ {
2578+ sub_name = geis_subscription_name(subscription);
2579+ sub_id = geis_subscription_id(subscription);
2580+ sub_flags = geis_subscription_flags(subscription);
2581+ }
2582+ dbus_message_iter_init_append(message, &iter);
2583+
2584+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &sub_name);
2585+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &sub_id);
2586+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &sub_flags);
2587+ _geis_dbus_marshall_subscription_filters(subscription, &iter);
2588+
2589+ return message;
2590+}
2591+
2592+
2593+/*
2594+ * Creates a %GeisSubscription from a method call message.
2595+ */
2596+GeisSubscription
2597+geis_dbus_subscription_from_create_call_message(Geis geis, DBusMessage *message)
2598+{
2599+ DBusMessageIter message_iter;
2600+ dbus_message_iter_init(message, &message_iter);
2601+
2602+ GeisString client_sub_name;
2603+ dbus_message_iter_get_basic(&message_iter, &client_sub_name);
2604+ dbus_message_iter_next(&message_iter);
2605+
2606+ dbus_int32_t client_sub_id;
2607+ dbus_message_iter_get_basic(&message_iter, &client_sub_id);
2608+ dbus_message_iter_next(&message_iter);
2609+
2610+ dbus_uint32_t client_sub_flags;
2611+ dbus_message_iter_get_basic(&message_iter, &client_sub_flags);
2612+ dbus_message_iter_next(&message_iter);
2613+
2614+ GeisSubscription subscription = NULL;
2615+ subscription = geis_subscription_new(geis, client_sub_name, client_sub_flags);
2616+ if (!subscription)
2617+ {
2618+ geis_error("error creating proxy subscription");
2619+ goto final_exit;
2620+ }
2621+ intptr_t fudge = client_sub_id;
2622+ geis_subscription_set_pdata(subscription, (GeisPointer)fudge);
2623+
2624+ int dtype = dbus_message_iter_get_arg_type(&message_iter);
2625+ if (dtype != DBUS_TYPE_ARRAY)
2626+ {
2627+ geis_error("malformed GeisSubscription message"
2628+ " (expected type %c, received type %c)",
2629+ DBUS_TYPE_ARRAY, dtype);
2630+ goto final_exit;
2631+ }
2632+
2633+ _geis_dbus_unmarshall_subscription_filters(geis, &message_iter, subscription);
2634+
2635+final_exit:
2636+ return subscription;
2637+}
2638+
2639+
2640+/*
2641+ * Creates a GEIS_DBUS_SUBSCRIPTION_CREATE method return message.
2642+ */
2643+DBusMessage *
2644+geis_dbus_subscription_create_return_message(DBusMessage *message,
2645+ GeisSubscription subscription)
2646+{
2647+ DBusMessage *reply = dbus_message_new_method_return(message);
2648+ intptr_t fudge = (intptr_t)geis_subscription_pdata(subscription);
2649+ dbus_int32_t client_sub_id = fudge;
2650+ dbus_int32_t server_sub_id = geis_subscription_id(subscription);
2651+ dbus_message_append_args(reply,
2652+ DBUS_TYPE_INT32, &client_sub_id,
2653+ DBUS_TYPE_INT32, &server_sub_id,
2654+ DBUS_TYPE_INVALID);
2655+
2656+ return reply;
2657+}
2658+
2659+
2660+/*
2661+ * Indicates if a DBus message is a GEIS_DBUS_SUBSCRIPTION_ACTIVATE message.
2662+ */
2663+GeisBoolean
2664+geis_dbus_message_is_subscription_activate_call(DBusMessage *message)
2665+{
2666+ return dbus_message_is_method_call(message,
2667+ GEIS_DBUS_SERVICE_INTERFACE,
2668+ GEIS_DBUS_SUBSCRIPTION_ACTIVATE);
2669+}
2670+
2671+
2672+/*
2673+ * Creates a GEIS_DBUS_SUBSCRIPTION_ACTIVATE method call message.
2674+ */
2675+DBusMessage *
2676+geis_dbus_subscription_activate_call_message(GeisSubscription subscription)
2677+{
2678+ DBusMessage *message = NULL;
2679+ DBusMessageIter iter;
2680+
2681+ message = dbus_message_new_method_call(GEIS_DBUS_SERVICE_INTERFACE,
2682+ GEIS_DBUS_SERVICE_PATH,
2683+ GEIS_DBUS_SERVICE_INTERFACE,
2684+ GEIS_DBUS_SUBSCRIPTION_ACTIVATE);
2685+ dbus_message_iter_init_append(message, &iter);
2686+
2687+ dbus_int32_t subscription_id = geis_subscription_id(subscription);
2688+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &subscription_id);
2689+ _geis_dbus_marshall_subscription_filters(subscription, &iter);
2690+ return message;
2691+}
2692+
2693+
2694+/*
2695+ * Creates a GEIS_DBUS_SUBSCRIPTION_ACTIVATE method return message.
2696+ */
2697+DBusMessage *
2698+geis_dbus_subscription_activate_return_message(DBusMessage *message,
2699+ GeisSubscription subscription)
2700+{
2701+ DBusMessage *reply = NULL;
2702+ reply = dbus_message_new_method_return(message);
2703+ dbus_int32_t subscription_id = -1;
2704+
2705+ if (subscription)
2706+ {
2707+ subscription_id = geis_subscription_id(subscription);
2708+ }
2709+ dbus_message_append_args(reply,
2710+ DBUS_TYPE_INT32, &subscription_id,
2711+ DBUS_TYPE_INVALID);
2712+ return reply;
2713+}
2714+
2715+
2716+/*
2717+ * Indicates if a DBus message is a GEIS_DBUS_SUBSCRIPTION_DEACTIVATE message.
2718+ */
2719+GeisBoolean
2720+geis_dbus_message_is_subscription_deactivate_call(DBusMessage *message)
2721+{
2722+ return dbus_message_is_method_call(message,
2723+ GEIS_DBUS_SERVICE_INTERFACE,
2724+ GEIS_DBUS_SUBSCRIPTION_DEACTIVATE);
2725+}
2726+
2727+
2728+/*
2729+ * Creates a GEIS_DBUS_SUBSCRIPTION_DEACTIVATE method call message.
2730+ */
2731+DBusMessage *
2732+geis_dbus_subscription_deactivate_call_message(GeisSubscription subscription GEIS_UNUSED)
2733+{
2734+ DBusMessage *message = NULL;
2735+ message = dbus_message_new_method_call(GEIS_DBUS_SERVICE_INTERFACE,
2736+ GEIS_DBUS_SERVICE_PATH,
2737+ GEIS_DBUS_SERVICE_INTERFACE,
2738+ GEIS_DBUS_SUBSCRIPTION_DEACTIVATE);
2739+ return message;
2740+}
2741+
2742+
2743+/**
2744+ */
2745+DBusMessage *
2746+geis_dbus_subscription_deactivate_return_message(DBusMessage *message,
2747+ GeisSubscription subscription)
2748+{
2749+ DBusMessage *reply = NULL;
2750+ reply = dbus_message_new_method_return(message);
2751+ dbus_int32_t subscription_id = geis_subscription_id(subscription);
2752+ dbus_message_append_args(reply,
2753+ DBUS_TYPE_INT32, &subscription_id,
2754+ DBUS_TYPE_INVALID);
2755+ return reply;
2756+}
2757+
2758+
2759+/*
2760+ * Indicates if a DBus message is a GEIS_DBUS_SUBSCRIPTION_DESTROY message.
2761+ */
2762+GeisBoolean
2763+geis_dbus_message_is_subscription_destroy_call(DBusMessage *message)
2764+{
2765+ return dbus_message_is_method_call(message,
2766+ GEIS_DBUS_SERVICE_INTERFACE,
2767+ GEIS_DBUS_SUBSCRIPTION_DESTROY);
2768+}
2769+
2770+
2771+/*
2772+ * Creates a GEIS_DBUS_SUBSCRIPTION_DESTROY method call message.
2773+ */
2774+DBusMessage *
2775+geis_dbus_subscription_destroy_call_message(GeisSubscription subscription)
2776+{
2777+ DBusMessage *message = NULL;
2778+ message = dbus_message_new_method_call(GEIS_DBUS_SERVICE_INTERFACE,
2779+ GEIS_DBUS_SERVICE_PATH,
2780+ GEIS_DBUS_SERVICE_INTERFACE,
2781+ GEIS_DBUS_SUBSCRIPTION_DESTROY);
2782+
2783+ dbus_int32_t server_sub_id = (intptr_t)geis_subscription_pdata(subscription);
2784+ dbus_message_append_args(message,
2785+ DBUS_TYPE_INT32, &server_sub_id,
2786+ DBUS_TYPE_INVALID);
2787+
2788+ return message;
2789+}
2790+
2791+
2792+/*
2793+ * Creates a GEIS_DBUS_SUBSCRIPTION_DESTROY method return message.
2794+ */
2795+DBusMessage *
2796+geis_dbus_subscription_destroy_return_message(DBusMessage *message)
2797+{
2798+ return dbus_message_new_method_return(message);
2799+}
2800+
2801+
2802
2803=== added file 'libs/geis-dbus/geis_dbus_subscription.h'
2804--- libs/geis-dbus/geis_dbus_subscription.h 1970-01-01 00:00:00 +0000
2805+++ libs/geis-dbus/geis_dbus_subscription.h 2011-10-18 19:34:23 +0000
2806@@ -0,0 +1,206 @@
2807+/**
2808+ * @file geis_dbus_subscription.h
2809+ * @brief Interface for the GEIS DBus subscription transport.
2810+ */
2811+
2812+/*
2813+ * Copyright 2011 Canonical Ltd.
2814+ *
2815+ * This library is free software; you can redistribute it and/or modify it under
2816+ * the terms of the GNU Lesser General Public License as published by the Free
2817+ * Software Foundation; either version 3 of the License, or (at your option) any
2818+ * later version.
2819+ *
2820+ * This library is distributed in the hope that it will be useful, but WITHOUT
2821+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2822+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
2823+ * details.
2824+ *
2825+ * You should have received a copy of the GNU General Public License
2826+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2827+ */
2828+#ifndef GEIS_DBUS_SUBSCRIPTION_H_
2829+#define GEIS_DBUS_SUBSCRIPTION_H_
2830+
2831+#include <dbus/dbus.h>
2832+#include "geis/geis.h"
2833+
2834+
2835+/**
2836+ * Indicates if a DBus message is a GEIS_DBUS_SUBSCRIPTION_CREATE method call.
2837+ *
2838+ * @param[in] message A DBus message.
2839+ *
2840+ * This function is used on the server side to identify if a received message is
2841+ * a GEIS_DBUS_SUBSCRIPTION_CREATE method call.
2842+ *
2843+ * @returns GEIS_TRUE if the message is GEIS_DBUS_SUBSCRIPTION_CREATE,
2844+ * GEIS_FALSE otherwise.
2845+ */
2846+GeisBoolean
2847+geis_dbus_message_is_subscription_create_call(DBusMessage *message);
2848+
2849+/**
2850+ * Creates a GEIS_DBUS_SUBSCRIPTION_CREATE method call message.
2851+ *
2852+ * @param[in] subscription A GEIS subscription.
2853+ *
2854+ * This function is used on the client side to create a
2855+ * GEIS_DBUS_SUBSCRIPTION_CREATE method call message from a local
2856+ * %GeisSubscription object.
2857+ *
2858+ * @returns A DBus message object.
2859+ */
2860+DBusMessage *
2861+geis_dbus_subscription_create_call_message(GeisSubscription subscription);
2862+
2863+/**
2864+ * Creates a %GeisSubscription from a GEIS_DBUS_SUBSCRIPTION_CREATE method call
2865+ * message.
2866+ *
2867+ * @param[in] geis A %Geis instance.
2868+ * @param[in] message A DBus message.
2869+ *
2870+ * This function is used on the server side to create a subscription object to
2871+ * proxy the client-side subscription object.
2872+ *
2873+ * @returns a %GeisSubscription or NULL on failure.
2874+ */
2875+GeisSubscription
2876+geis_dbus_subscription_from_create_call_message(Geis geis, DBusMessage *message);
2877+
2878+/**
2879+ * Creates a GEIS_DBUS_SUBSCRIPTION_CREATE method return message.
2880+ *
2881+ * @param[in] message The DBUs method_call message to reply to.
2882+ * @param[in] subscription A GEIS subscription.
2883+ *
2884+ * This function is used on the server side to create a response to a received
2885+ * GEIS_DBUS_SUBSCRIPTION_CREATE method call message.
2886+ *
2887+ * @returns A DBus message object.
2888+ */
2889+DBusMessage *
2890+geis_dbus_subscription_create_return_message(DBusMessage *message,
2891+ GeisSubscription subscription);
2892+
2893+/**
2894+ * Indicates if a DBus message is a GEIS_DBUS_SUBSCRIPTION_ACTIVATE message.
2895+ *
2896+ * @param[in] message A DBus message.
2897+ *
2898+ * @returns GEIS_TRUE if the message is GEIS_DBUS_SUBSCRIPTION_ACTIVATE,
2899+ * GEIS_FALSE otherwise.
2900+ */
2901+GeisBoolean
2902+geis_dbus_message_is_subscription_activate_call(DBusMessage *message);
2903+
2904+/**
2905+ * Creates a GEIS_DBUS_SUBSCRIPTION_ACTIVATE method call message.
2906+ *
2907+ * @param[in] subscription A GEIS subscription.
2908+ *
2909+ * This function is used on the client side to create a
2910+ * GEIS_DBUS_SUBSCRIPTION_ACTIVATE method call message from a local
2911+ * %GeisSubscription object.
2912+ *
2913+ * @returns A DBus message object.
2914+ */
2915+DBusMessage *
2916+geis_dbus_subscription_activate_call_message(GeisSubscription subscription);
2917+
2918+/**
2919+ * Creates a GEIS_DBUS_SUBSCRIPTION_ACTIVATE method return message.
2920+ *
2921+ * @param[in] message The DBUs method_call message to reply to.
2922+ * @param[in] subscription A GEIS subscription.
2923+ *
2924+ * This function is used on the server side to create a response to a received
2925+ * GEIS_DBUS_SUBSCRIPTION_ACTIVATE method call message.
2926+ *
2927+ * @returns A DBus message object.
2928+ */
2929+DBusMessage *
2930+geis_dbus_subscription_activate_return_message(DBusMessage *message,
2931+ GeisSubscription subscription);
2932+
2933+/**
2934+ * Indicates if a DBus message is a GEIS_DBUS_SUBSCRIPTION_DEACTIVATE message.
2935+ *
2936+ * @param[in] message A DBus message.
2937+ *
2938+ * @returns GEIS_TRUE if the message is GEIS_DBUS_SUBSCRIPTION_DEACTIVATE,
2939+ * GEIS_FALSE otherwise.
2940+ */
2941+GeisBoolean
2942+geis_dbus_message_is_subscription_deactivate_call(DBusMessage *message);
2943+
2944+/**
2945+ * Creates a GEIS_DBUS_SUBSCRIPTION_DEACTIVATE method return message.
2946+ *
2947+ * @param[in] message The DBUs method_call message to reply to.
2948+ * @param[in] subscription A GEIS subscription.
2949+ *
2950+ * This function is used on the server side to create a response to a received
2951+ * GEIS_DBUS_SUBSCRIPTION_DEACTIVATE method call message.
2952+ *
2953+ * @returns A DBus message object.
2954+ */
2955+DBusMessage *
2956+geis_dbus_subscription_deactivate_return_message(DBusMessage *message,
2957+ GeisSubscription subscription);
2958+
2959+/**
2960+ * Creates a GEIS_DBUS_SUBSCRIPTION_DEACTIVATE method call message.
2961+ *
2962+ * @param[in] subscription A GEIS subscription.
2963+ *
2964+ * This function is used on the client side to create a
2965+ * GEIS_DBUS_SUBSCRIPTION_DEACTIVATE method call message from a local
2966+ * %GeisSubscription object.
2967+ *
2968+ * @returns A DBus message object.
2969+ */
2970+DBusMessage *
2971+geis_dbus_subscription_deactivate_call_message(GeisSubscription subscription);
2972+
2973+/**
2974+ * Indicates if a DBus message is a GEIS_DBUS_SUBSCRIPTION_DESTROY message.
2975+ *
2976+ * @param[in] message A DBus message.
2977+ *
2978+ * @returns GEIS_TRUE if the message is GEIS_DBUS_SUBSCRIPTION_DESTROY,
2979+ * GEIS_FALSE otherwise.
2980+ */
2981+GeisBoolean
2982+geis_dbus_message_is_subscription_destroy_call(DBusMessage *message);
2983+
2984+/**
2985+ * Creates a GEIS_DBUS_SUBSCRIPTION_DESTROY method call message.
2986+ *
2987+ * @param[in] subscription A GEIS subscription.
2988+ *
2989+ * This function is used on the client side to create a
2990+ * GEIS_DBUS_SUBSCRIPTION_DESTROY method call message from a local
2991+ * %GeisSubscription object.
2992+ *
2993+ * @returns A DBus message object.
2994+ */
2995+DBusMessage *
2996+geis_dbus_subscription_destroy_call_message(GeisSubscription subscription);
2997+
2998+/**
2999+ * Creates a GEIS_DBUS_SUBSCRIPTION_DESTROY method return message.
3000+ *
3001+ * @param[in] message The DBUs method_call message to reply to.
3002+ *
3003+ * This function is used on the server side to create a response to a received
3004+ * GEIS_DBUS_SUBSCRIPTION_DESTROY method call message.
3005+ *
3006+ * @returns A DBus message object.
3007+ */
3008+DBusMessage *
3009+geis_dbus_subscription_destroy_return_message(DBusMessage *message);
3010+
3011+
3012+#endif /* GEIS_DBUS_SUBSCRIPTION_H_ */
3013
3014=== modified file 'libutouch-geis/Makefile.am'
3015--- libutouch-geis/Makefile.am 2011-08-17 15:48:51 +0000
3016+++ libutouch-geis/Makefile.am 2011-10-18 19:34:23 +0000
3017@@ -39,6 +39,7 @@
3018 geis_event.h geis_event.c \
3019 geis_event_queue.h geis_event_queue.c \
3020 geis_filter.h geis_filter.c \
3021+ geis_filterable.h geis_filterable.c \
3022 geis_filter_term.h geis_filter_term.c \
3023 geis_frame.h geis_frame.c \
3024 geis_gesture_flick.h geis_gesture_flick.c \
3025@@ -56,6 +57,8 @@
3026 -I$(top_srcdir) \
3027 -I$(top_srcdir)/include \
3028 -I$(srcdir)/backend \
3029+ -I$(top_srcdir)/libs/geis-dbus \
3030+ $(DBUS_CFLAGS) \
3031 $(GRAIL_CFLAGS)
3032
3033 libutouch_geis_la_LDFLAGS = \
3034@@ -66,8 +69,10 @@
3035
3036 libutouch_geis_la_LIBADD = \
3037 ${builddir}/backend/test_fixture/libutouch-geis-test-fixture.la \
3038+ ${builddir}/backend/dbus/libutouch-geis-dbus-backend.la \
3039 ${builddir}/backend/xcb/libutouch-geis-xcb-backend.la \
3040 ${builddir}/server/libutouch-geis-dbus-server.la \
3041+ $(top_builddir)/libs/geis-dbus/libgeis-dbus.la \
3042 $(top_builddir)/libs/xcb/libxcb-gesture.la
3043
3044 EXTRA_DIST = $(version_script)
3045
3046=== modified file 'libutouch-geis/backend/Makefile.am'
3047--- libutouch-geis/backend/Makefile.am 2011-01-17 14:58:27 +0000
3048+++ libutouch-geis/backend/Makefile.am 2011-10-18 19:34:23 +0000
3049@@ -19,5 +19,5 @@
3050 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3051 #
3052
3053-SUBDIRS = test_fixture xcb
3054+SUBDIRS = test_fixture xcb dbus
3055
3056
3057=== added directory 'libutouch-geis/backend/dbus'
3058=== added file 'libutouch-geis/backend/dbus/Makefile.am'
3059--- libutouch-geis/backend/dbus/Makefile.am 1970-01-01 00:00:00 +0000
3060+++ libutouch-geis/backend/dbus/Makefile.am 2011-10-18 19:34:23 +0000
3061@@ -0,0 +1,34 @@
3062+#
3063+# @file libutouch-geis/backend/xcb/Makefile.am
3064+# @brief automake recipe for the uTouch GEIS v2.0 XCB back end
3065+#
3066+# Copyright 2011 Canonical, Ltd.
3067+#
3068+# This file is part of the utouch-geis library. This library is free software;
3069+# you can redistribute it and/or modify it under the terms of the GNU Lesser
3070+# General Public License as published by the Free Software Foundation; either
3071+# version 3 of the License, or (at your option) any later version.
3072+#
3073+# This library is distributed in the hope that it will be useful, but WITHOUT
3074+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3075+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
3076+# details.
3077+#
3078+# You should have received a copy of the GNU General Public License
3079+# along with this program. If not, see <http://www.gnu.org/licenses/
3080+#
3081+
3082+noinst_LTLIBRARIES = libutouch-geis-dbus-backend.la
3083+
3084+libutouch_geis_dbus_backend_la_SOURCES = \
3085+ geis_dbus_backend.c \
3086+ geis_dbus_client.h geis_dbus_client.c \
3087+ geis_dbus_locator.h geis_dbus_locator.c
3088+
3089+libutouch_geis_dbus_backend_la_CPPFLAGS = \
3090+ -I$(top_srcdir) \
3091+ -I$(top_srcdir)/libs/geis-dbus \
3092+ -I$(top_srcdir)/include \
3093+ -I$(top_srcdir)/libutouch-geis \
3094+ $(DBUS_CFLAGS)
3095+
3096
3097=== added file 'libutouch-geis/backend/dbus/geis_dbus_backend.c'
3098--- libutouch-geis/backend/dbus/geis_dbus_backend.c 1970-01-01 00:00:00 +0000
3099+++ libutouch-geis/backend/dbus/geis_dbus_backend.c 2011-10-18 19:34:23 +0000
3100@@ -0,0 +1,249 @@
3101+/**
3102+ * @file geis_dbus_backend.c
3103+ * @brief GEIS DBus client back end
3104+ */
3105+
3106+/*
3107+ * Copyright 2011 Canonical Ltd.
3108+ *
3109+ * This library is free software; you can redistribute it and/or modify it under
3110+ * the terms of the GNU Lesser General Public License as published by the Free
3111+ * Software Foundation; either version 3 of the License, or (at your option) any
3112+ * later version.
3113+ *
3114+ * This library is distributed in the hope that it will be useful, but WITHOUT
3115+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3116+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
3117+ * details.
3118+ *
3119+ * You should have received a copy of the GNU General Public License
3120+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3121+ */
3122+#include "geis_config.h"
3123+#include "geis_backend.h"
3124+#include "geis_backend_protected.h"
3125+
3126+#include "geis_dbus_client.h"
3127+#include "geis_event.h"
3128+#include "geis_logging.h"
3129+#include "geis_private.h"
3130+
3131+
3132+/**
3133+ * @addtogroup geis_backend_dbus GEIS DBus Back End
3134+ * @ingroup geis_backends
3135+ *
3136+ * A GEIS Back End that is a DBus client, for connecting to a single central
3137+ * GEIS service offering data over the DBus.
3138+ *
3139+ * @{
3140+ */
3141+
3142+/** The opaque DBus Back End type. */
3143+typedef struct GeisDBusBackend *GeisDBusBackend;
3144+
3145+/** The less opaque DBus Back End structure. */
3146+struct GeisDBusBackend
3147+{
3148+ Geis geis;
3149+ GeisDBusClient dbus_client;
3150+};
3151+
3152+/** The DBus Back End token type */
3153+typedef struct GeisDBusToken
3154+{
3155+ struct GeisBackendToken base;
3156+ GeisDBusBackend be;
3157+} *GeisDBusToken;
3158+
3159+
3160+/**
3161+ * Converts from a GeisBackendToken to an XcbBackendToken.
3162+ */
3163+static inline GeisDBusToken
3164+_geis_dbus_token_from_geis_token(GeisBackendToken gbt)
3165+{
3166+ return (GeisDBusToken)gbt;
3167+}
3168+
3169+
3170+/**
3171+ * Allocates memory for a token from a pool.
3172+ */
3173+static GeisDBusToken
3174+_geis_dbus_token_allocate(void)
3175+{
3176+ return calloc(1, sizeof(struct GeisDBusToken));
3177+}
3178+
3179+
3180+/**
3181+ * Returns memory for a token to a pool.
3182+ */
3183+static void
3184+_geis_dbus_token_deallocate(GeisDBusToken gdt)
3185+{
3186+ free(gdt);
3187+}
3188+
3189+
3190+/**
3191+ * Deep-copy-constructs a token.
3192+ */
3193+static GeisBackendToken
3194+_geis_dbus_token_clone(GeisBackendToken original)
3195+{
3196+ return original;
3197+}
3198+
3199+
3200+/**
3201+ * Releases resources for a token.
3202+ *
3203+ * @param[in] token A %GeisDBusToken.
3204+ */
3205+static void
3206+_geis_dbus_token_finalize(GeisBackendToken token GEIS_UNUSED)
3207+{
3208+ GeisDBusToken gdt = _geis_dbus_token_from_geis_token(token);
3209+ _geis_dbus_token_deallocate(gdt);
3210+}
3211+
3212+
3213+/**
3214+ * Composes one token onto another.
3215+ *
3216+ * @param[in,out] lhs
3217+ * @param[in] rhs
3218+ */
3219+static void
3220+_geis_dbus_token_compose(GeisBackendToken lhs GEIS_UNUSED,
3221+ GeisBackendToken rhs GEIS_UNUSED)
3222+{
3223+}
3224+
3225+
3226+/**
3227+ * Activates a DBus back end token.
3228+ *
3229+ * @param[in] token A %GeisDBusToken.
3230+ * @param[in] subscription The subscrition the token will be activated on.
3231+ *
3232+ * Sends a request to the server to activate a subscription with the tokenized
3233+ * content.
3234+ *
3235+ * @returns GEIS_STATUS_SUCCESS.
3236+ */
3237+static GeisStatus
3238+_geis_dbus_token_activate(GeisBackendToken token, GeisSubscription subscription)
3239+{
3240+ GeisDBusToken gdt = _geis_dbus_token_from_geis_token(token);
3241+ geis_dbus_client_subscribe(gdt->be->dbus_client, subscription);
3242+ return GEIS_STATUS_SUCCESS;
3243+}
3244+
3245+
3246+/**
3247+ * Deactivates a DBus back end token.
3248+ *
3249+ * @param[in] token A %GeisDBusToken.
3250+ */
3251+static GeisStatus
3252+_geis_dbus_token_deactivate(GeisBackendToken token, GeisSubscription subscription)
3253+{
3254+ GeisDBusToken gdt = _geis_dbus_token_from_geis_token(token);
3255+ geis_dbus_client_unsubscribe(gdt->be->dbus_client, subscription);
3256+ return GEIS_STATUS_UNKNOWN_ERROR;
3257+}
3258+
3259+
3260+static struct GeisBackendTokenVtable _token_vtbl = {
3261+ _geis_dbus_token_clone,
3262+ _geis_dbus_token_finalize,
3263+ _geis_dbus_token_compose,
3264+ _geis_dbus_token_activate,
3265+ _geis_dbus_token_deactivate,
3266+};
3267+
3268+
3269+/**
3270+ * Constructs a DBus back end.
3271+ *
3272+ * @param[in] mem
3273+ * @param[in] geis
3274+ */
3275+static void
3276+_geis_dbus_backend_construct(void *mem, Geis geis)
3277+{
3278+ GeisDBusBackend gdb = (GeisDBusBackend)mem;
3279+ gdb->geis = geis;
3280+
3281+ gdb->dbus_client = geis_dbus_client_new(geis);
3282+ if (!gdb->dbus_client)
3283+ {
3284+ geis_error("error creating GEIS DBus client");
3285+ goto final_exit;
3286+ }
3287+
3288+final_exit:
3289+ return;
3290+}
3291+
3292+
3293+/**
3294+ * Deconstructs a DBus back end.
3295+ *
3296+ * @param[in] be A %GeisDBusBackend.
3297+ */
3298+static void
3299+_geis_dbus_backend_finalize(GeisBackend be)
3300+{
3301+ GeisDBusBackend gdb = (GeisDBusBackend)be;
3302+ geis_dbus_client_delete(gdb->dbus_client);
3303+}
3304+
3305+
3306+/**
3307+ * Creates DBus-back-end-specific back end token.
3308+ */
3309+static GeisBackendToken
3310+_geis_dbus_backend_create_token(GeisBackend be,
3311+ GeisBackendTokenInitState init_state GEIS_UNUSED)
3312+{
3313+ GeisDBusBackend gdb = (GeisDBusBackend)be;
3314+ GeisDBusToken token = _geis_dbus_token_allocate();
3315+ if (token)
3316+ {
3317+ token->base.vtbl = &_token_vtbl;
3318+ token->be = gdb;
3319+ }
3320+ return (GeisBackendToken)token;
3321+}
3322+
3323+
3324+static struct GeisBackendVtable gdb_vtbl = {
3325+ _geis_dbus_backend_construct,
3326+ _geis_dbus_backend_finalize,
3327+ _geis_dbus_backend_create_token,
3328+};
3329+
3330+
3331+/**
3332+ * Registers the back end with the GEIS back end registry.
3333+ */
3334+static void __attribute__((constructor))
3335+_register_dbus_backend(void)
3336+{
3337+ geis_register_backend(GEIS_INIT_UTOUCH_DBUS_BACKEND,
3338+ sizeof(struct GeisDBusBackend),
3339+ &gdb_vtbl);
3340+}
3341+
3342+
3343+/** A dummy routine to force linkage of this module without dlopening it */
3344+void
3345+geis_include_dbus_backend(void)
3346+{
3347+}
3348+
3349+/** @} */
3350
3351=== added file 'libutouch-geis/backend/dbus/geis_dbus_client.c'
3352--- libutouch-geis/backend/dbus/geis_dbus_client.c 1970-01-01 00:00:00 +0000
3353+++ libutouch-geis/backend/dbus/geis_dbus_client.c 2011-10-18 19:34:23 +0000
3354@@ -0,0 +1,685 @@
3355+/**
3356+ * @file geis_dbus_client.c
3357+ * @brief Implementations of the GEIS DBus client.
3358+ */
3359+
3360+/*
3361+ * Copyright 2011 Canonical Ltd.
3362+ *
3363+ * This library is free software; you can redistribute it and/or modify it under
3364+ * the terms of the GNU Lesser General Public License as published by the Free
3365+ * Software Foundation; either version 3 of the License, or (at your option) any
3366+ * later version.
3367+ *
3368+ * This library is distributed in the hope that it will be useful, but WITHOUT
3369+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3370+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
3371+ * details.
3372+ *
3373+ * You should have received a copy of the GNU General Public License
3374+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3375+ */
3376+#include "geis_config.h"
3377+#include "geis_dbus_client.h"
3378+
3379+#include "geis_dbus.h"
3380+#include "geis_dbus_class.h"
3381+#include "geis_dbus_device.h"
3382+#include "geis_dbus_gesture_event.h"
3383+#include "geis_dbus_locator.h"
3384+#include "geis_dbus_region.h"
3385+#include "geis_dbus_subscription.h"
3386+#include "geis_event.h"
3387+#include "geis_logging.h"
3388+#include "geis_private.h"
3389+#include <stdio.h>
3390+#include <stdlib.h>
3391+
3392+
3393+typedef enum GeisDBusClientState
3394+{
3395+ GEIS_DBUS_CLIENT_DISCONNECTED, /* no server available */
3396+ GEIS_DBUS_CLIENT_INITIALIZING, /* server connected, client initializing */
3397+ GEIS_DBUS_CLIENT_CONNECTING, /* server connected, not initialized */
3398+ GEIS_DBUS_CLIENT_CONNECTED /* server connected, all systems go */
3399+} GeisDBusClientState;
3400+
3401+
3402+struct GeisDBusClient
3403+{
3404+ Geis geis;
3405+ GeisDBusDispatcher dispatcher;
3406+ GeisDBusLocator locator;
3407+ GeisDBusClientState state;
3408+ DBusConnection *connection;
3409+ GeisSubBag subscription_bag;
3410+};
3411+
3412+
3413+/**
3414+ * Handles a device-available message from the server.
3415+ *
3416+ * @param[in] client A %GeisDBusClient.
3417+ * @param[in] message The %DBusMessage.
3418+ */
3419+static void
3420+_client_device_available(GeisDBusClient client, DBusMessage *message)
3421+{
3422+ GeisDevice device = geis_dbus_device_device_from_available_message(message);
3423+ if (device)
3424+ {
3425+ geis_register_device(client->geis, device, 0, NULL);
3426+ }
3427+ else
3428+ {
3429+ geis_error("no device received from remote back end");
3430+ }
3431+}
3432+
3433+
3434+/**
3435+ * Handles a device-unavailable message from the server.
3436+ *
3437+ * @param[in] client A %GeisDBusClient.
3438+ * @param[in] message The %DBusMessage.
3439+ */
3440+static void
3441+_client_device_unavailable(GeisDBusClient client, DBusMessage *message)
3442+{
3443+ GeisDevice device = geis_dbus_device_device_from_unavailable_message(message);
3444+ if (device)
3445+ {
3446+ geis_unregister_device(client->geis, device);
3447+ }
3448+ else
3449+ {
3450+ geis_error("no device received from remote back end");
3451+ }
3452+}
3453+
3454+
3455+/**
3456+ * Handles a class-available message from the server.
3457+ *
3458+ * @param[in] client A %GeisDBusClient.
3459+ * @param[in] message The %DBusMessage.
3460+ */
3461+static void
3462+_client_class_available(GeisDBusClient client, DBusMessage *message)
3463+{
3464+ GeisGestureClass gesture_class;
3465+
3466+ gesture_class = geis_dbus_class_class_from_available_message(message);
3467+ if (gesture_class)
3468+ {
3469+ geis_register_gesture_class(client->geis, gesture_class, 0, NULL);
3470+ }
3471+ else
3472+ {
3473+ geis_error("no gesture class received from remote back end");
3474+ }
3475+}
3476+
3477+
3478+/**
3479+ * Handles a region-available message from the server.
3480+ *
3481+ * @param[in] client A %GeisDBusClient.
3482+ * @param[in] message The %DBusMessage.
3483+ */
3484+static void
3485+_client_region_available(GeisDBusClient client, DBusMessage *message)
3486+{
3487+ GeisFilterableAttribute attr;
3488+
3489+ attr = geis_dbus_region_from_region_available_message(message);
3490+ if (attr)
3491+ {
3492+ attr->add_term_callback = 0;
3493+ attr->add_term_context = 0;
3494+ geis_register_region(client->geis, NULL, 1, attr);
3495+ }
3496+ else
3497+ {
3498+ geis_error("no region attr received from remote back end");
3499+ }
3500+}
3501+
3502+
3503+/**
3504+ * Handles a class-unavailable message from the server.
3505+ *
3506+ * @param[in] client A %GeisDBusClient.
3507+ * @param[in] message The %DBusMessage.
3508+ */
3509+static void
3510+_client_gesture_event(GeisDBusClient client, DBusMessage *message)
3511+{
3512+ GeisEvent event = geis_dbus_gesture_event_from_message(client->geis, message);
3513+ if (!event)
3514+ {
3515+ geis_error("no gesture event received from remote back end");
3516+ }
3517+ else
3518+ {
3519+ geis_post_event(client->geis, event);
3520+ }
3521+}
3522+
3523+
3524+/**
3525+ * Processes an subscription-activate reply from the server.
3526+ *
3527+ * @param[in] pending A DBusPendingCall object.
3528+ * @param[in] user_data The %GeisDBusClient object.
3529+ */
3530+static void
3531+_geis_dbus_client_activate_reply(DBusPendingCall *pending, void *user_data)
3532+{
3533+ GeisDBusClient client GEIS_UNUSED = (GeisDBusClient)user_data;
3534+ DBusMessage *reply = dbus_pending_call_steal_reply(pending);
3535+
3536+ if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(reply))
3537+ {
3538+ const char *s = NULL;
3539+ dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID);
3540+ geis_error("error %s: %s", dbus_message_get_error_name(reply), s);
3541+ }
3542+}
3543+
3544+
3545+/**
3546+ * Processes a subscription-create reply from the server.
3547+ *
3548+ * @param[in] pending A DBusPendingCall object.
3549+ * @param[in] user_data The %GeisDBusClient object.
3550+ */
3551+static void
3552+_geis_dbus_client_subscribe_reply(DBusPendingCall *pending, void *user_data)
3553+{
3554+ GeisDBusClient client = (GeisDBusClient)user_data;
3555+ DBusMessage *reply = dbus_pending_call_steal_reply(pending);
3556+
3557+ if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(reply))
3558+ {
3559+ const char *s = NULL;
3560+ dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID);
3561+ geis_error("error %s: %s", dbus_message_get_error_name(reply), s);
3562+ }
3563+ else
3564+ {
3565+ DBusMessage *msg;
3566+ DBusPendingCall *pending;
3567+ DBusError error = DBUS_ERROR_INIT;
3568+ dbus_int32_t client_sub_id;
3569+ dbus_int32_t server_sub_id;
3570+ GeisSubscription subscription;
3571+
3572+ dbus_message_get_args(reply,
3573+ &error,
3574+ DBUS_TYPE_INT32, &client_sub_id,
3575+ DBUS_TYPE_INT32, &server_sub_id,
3576+ DBUS_TYPE_INVALID);
3577+ if (dbus_error_is_set(&error))
3578+ {
3579+ geis_error("error %s: %s", error.name, error.message);
3580+ dbus_error_free(&error);
3581+ }
3582+
3583+ subscription = geis_subscription_bag_find(client->subscription_bag,
3584+ client_sub_id);
3585+ if (!subscription)
3586+ {
3587+ geis_error("invalid client subcription id %d returned from server",
3588+ client_sub_id);
3589+ }
3590+ else
3591+ {
3592+ geis_subscription_set_pdata(subscription, (GeisPointer)(intptr_t)server_sub_id);
3593+
3594+ msg = geis_dbus_subscription_activate_call_message(subscription);
3595+ dbus_connection_send_with_reply(client->connection, msg, &pending, -1);
3596+ dbus_message_unref(msg);
3597+ if (!pending)
3598+ {
3599+ geis_error("error sending DBus CreateSubscription method call");
3600+ }
3601+ else
3602+ {
3603+ dbus_pending_call_set_notify(pending,
3604+ _geis_dbus_client_activate_reply,
3605+ client, 0);
3606+ }
3607+ }
3608+ }
3609+
3610+ dbus_message_unref(reply);
3611+ dbus_pending_call_unref(pending);
3612+}
3613+
3614+
3615+/**
3616+ * Processes a deactivate-subscription reply from the server.
3617+ *
3618+ * @param[in] pending A DBusPendingCall object.
3619+ * @param[in] user_data The %GeisDBusClient object.
3620+ */
3621+static void
3622+_geis_dbus_client_unsubscribe_reply(DBusPendingCall *pending, void *user_data)
3623+{
3624+ GeisDBusClient client GEIS_UNUSED = (GeisDBusClient)user_data;
3625+ DBusMessage *reply = dbus_pending_call_steal_reply(pending);
3626+
3627+ if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(reply))
3628+ {
3629+ const char *s = NULL;
3630+ dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID);
3631+ geis_error("error %s: %s", dbus_message_get_error_name(reply), s);
3632+ }
3633+ else
3634+ {
3635+ geis_warning("signature=\"%s\"", dbus_message_get_signature(reply));
3636+ geis_warning("path=\"%s\"", dbus_message_get_path(reply));
3637+ geis_warning("interface=\"%s\"", dbus_message_get_interface(reply));
3638+ geis_warning("member=\"%s\"", dbus_message_get_member(reply));
3639+ }
3640+
3641+ dbus_message_unref(reply);
3642+ dbus_pending_call_unref(pending);
3643+}
3644+
3645+
3646+/**
3647+ * Creates a remote subscription.
3648+ */
3649+void
3650+_dbus_client_subscribe(GeisDBusClient client,
3651+ GeisSubscription subscription)
3652+{
3653+ DBusPendingCall *pending_return;
3654+
3655+ GeisSubscription sub = geis_subscription_bag_find(client->subscription_bag,
3656+ geis_subscription_id(subscription));
3657+ if (sub && geis_subscription_pdata(sub))
3658+ {
3659+ geis_warning("subscription already activated!");
3660+ }
3661+ else
3662+ {
3663+ DBusMessage *msg = geis_dbus_subscription_create_call_message(subscription);
3664+ dbus_connection_send_with_reply(client->connection, msg, &pending_return, -1);
3665+ dbus_message_unref(msg);
3666+ if (!pending_return)
3667+ {
3668+ geis_error("error sending DBus CreateSubscription method call");
3669+ }
3670+ else
3671+ {
3672+ dbus_pending_call_set_notify(pending_return,
3673+ _geis_dbus_client_subscribe_reply,
3674+ client, 0);
3675+ }
3676+ }
3677+}
3678+
3679+
3680+/**
3681+ * Re-subscribes all existing sibscriptions when the server appears or
3682+ * reappears.
3683+ */
3684+void
3685+_dbus_client_resubscribe_all(GeisDBusClient client)
3686+{
3687+ GeisSubBagIterator it;
3688+ for (it = geis_subscription_bag_begin(client->subscription_bag);
3689+ it != geis_subscription_bag_end(client->subscription_bag);
3690+ it = geis_subscription_bag_iterator_next(client->subscription_bag, it))
3691+ {
3692+ geis_subscription_set_pdata(*it, 0);
3693+ _dbus_client_subscribe(client, *it);
3694+ }
3695+}
3696+
3697+
3698+/**
3699+ * The DBus message dispatch function for the GEIS DBus client.
3700+ *
3701+ * @param[in] connection The %GeisDBusClient DBus connection.
3702+ * @param[in] message The DBus message received.
3703+ * @param[in] user_data The %GeisDBusClient.
3704+ */
3705+static DBusHandlerResult
3706+_geis_dbus_client_message_handler(DBusConnection *connection GEIS_UNUSED,
3707+ DBusMessage *message,
3708+ void *user_data)
3709+{
3710+ DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3711+ GeisDBusClient client = (GeisDBusClient)user_data;
3712+ int type = dbus_message_get_type(message);
3713+
3714+ if (dbus_message_is_signal(message,
3715+ DBUS_INTERFACE_LOCAL,
3716+ "Disconnected"))
3717+ {
3718+ geis_warning("server disconnected?");
3719+ result = DBUS_HANDLER_RESULT_HANDLED;
3720+ }
3721+ else if (dbus_message_is_signal(message,
3722+ GEIS_DBUS_SERVICE_INTERFACE,
3723+ GEIS_DBUS_DEVICE_AVAILABLE))
3724+ {
3725+ _client_device_available(client, message);
3726+ result = DBUS_HANDLER_RESULT_HANDLED;
3727+ }
3728+ else if (dbus_message_is_signal(message,
3729+ GEIS_DBUS_SERVICE_INTERFACE,
3730+ GEIS_DBUS_DEVICE_UNAVAILABLE))
3731+
3732+ {
3733+ _client_device_unavailable(client, message);
3734+ result = DBUS_HANDLER_RESULT_HANDLED;
3735+ }
3736+ else if (dbus_message_is_signal(message,
3737+ GEIS_DBUS_SERVICE_INTERFACE,
3738+ GEIS_DBUS_CLASS_AVAILABLE))
3739+ {
3740+ _client_class_available(client, message);
3741+ result = DBUS_HANDLER_RESULT_HANDLED;
3742+ }
3743+ else if (dbus_message_is_signal(message,
3744+ GEIS_DBUS_SERVICE_INTERFACE,
3745+ GEIS_DBUS_REGION_AVAILABLE))
3746+ {
3747+ _client_region_available(client, message);
3748+ result = DBUS_HANDLER_RESULT_HANDLED;
3749+ }
3750+ else if (dbus_message_is_signal(message,
3751+ GEIS_DBUS_SERVICE_INTERFACE,
3752+ GEIS_DBUS_INIT_COMPLETE))
3753+ {
3754+ if (client->state == GEIS_DBUS_CLIENT_INITIALIZING)
3755+ {
3756+ geis_post_event(client->geis, geis_event_new(GEIS_EVENT_INIT_COMPLETE));
3757+ }
3758+ client->state = GEIS_DBUS_CLIENT_CONNECTED;
3759+ _dbus_client_resubscribe_all(client);
3760+ result = DBUS_HANDLER_RESULT_HANDLED;
3761+ }
3762+ else if (geis_dbus_message_is_gesture_event(message))
3763+ {
3764+ _client_gesture_event(client, message);
3765+ result = DBUS_HANDLER_RESULT_HANDLED;
3766+ }
3767+ else if (type == DBUS_MESSAGE_TYPE_ERROR)
3768+ {
3769+ const char *str = NULL;
3770+ dbus_message_get_args(message, NULL,
3771+ DBUS_TYPE_STRING, &str,
3772+ DBUS_TYPE_INVALID);
3773+ geis_warning("error %s: %s", dbus_message_get_error_name(message), str);
3774+ }
3775+ else
3776+ {
3777+ geis_warning("unhandled DBus %s received:",
3778+ dbus_message_type_to_string(dbus_message_get_type(message)));
3779+ geis_warning(" signature=\"%s\"", dbus_message_get_signature(message));
3780+ geis_warning(" sender=\"%s\"", dbus_message_get_sender(message));
3781+ geis_warning(" path=\"%s\"",
3782+ dbus_message_get_path(message) ?
3783+ dbus_message_get_path(message) :
3784+ "(no path)");
3785+ geis_warning(" interface=\"%s\"",
3786+ dbus_message_get_interface(message) ?
3787+ dbus_message_get_interface(message) :
3788+ "(no interface)");
3789+ geis_warning(" member=\"%s\"",
3790+ dbus_message_get_member(message) ?
3791+ dbus_message_get_member(message) :
3792+ "(no member)");
3793+ }
3794+ return result;
3795+}
3796+
3797+
3798+/**
3799+ * Adds the client watches to the dispatcher watch list.
3800+ *
3801+ * @param[in] watch A %DBusWatch.
3802+ * @param[in] data The %GeisDBusClientProxy.
3803+ */
3804+static dbus_bool_t
3805+_client_add_watch(DBusWatch *watch, void *data)
3806+{
3807+ dbus_bool_t status = TRUE;
3808+ GeisDBusClient client = (GeisDBusClient)data;
3809+
3810+ geis_dbus_dispatcher_register(client->dispatcher, client->connection, watch);
3811+ return status;
3812+}
3813+
3814+
3815+/**
3816+ * Toggles the enabled/disabled status of the client watches.
3817+ *
3818+ * @param[in] watch A %DBusWatch.
3819+ * @param[in] data The %GeisDBusClientProxy.
3820+ */
3821+static void
3822+_client_toggle_watch(DBusWatch *watch, void *data)
3823+{
3824+ GeisDBusClient client = (GeisDBusClient)data;
3825+
3826+ geis_dbus_dispatcher_toggle_watch(client->dispatcher, watch);
3827+}
3828+
3829+
3830+/**
3831+ * Removes the client watches from the dispatcher watch list.
3832+ *
3833+ * @param[in] watch A %DBusWatch.
3834+ * @param[in] data The %GeisDBusClientProxy.
3835+ */
3836+static void
3837+_client_remove_watch(DBusWatch *watch, void *data)
3838+{
3839+ GeisDBusClient client = (GeisDBusClient)data;
3840+
3841+ geis_dbus_dispatcher_unregister(client->dispatcher, watch);
3842+}
3843+
3844+
3845+/**
3846+ * Connects to the GEIS server once an address is located.
3847+ *
3848+ * @param[in] client A %GeisDBusClient object.
3849+ * @param[in] address The address of the server.
3850+ */
3851+static void
3852+_client_connect(GeisDBusClient client, const char *address)
3853+{
3854+ geis_debug("server address=\"%s\"", address);
3855+ DBusError error = DBUS_ERROR_INIT;
3856+ client->connection = dbus_connection_open(address, &error);
3857+ if (!client->connection || dbus_error_is_set(&error))
3858+ {
3859+ char msg[512];
3860+ snprintf(msg, sizeof(msg), "error %s connecting to server at address %s: %s",
3861+ error.name, address, error.message);
3862+ geis_error("%s", msg);
3863+ dbus_error_free(&error);
3864+ goto final_exit;
3865+ }
3866+
3867+ /* Integrate with the app event loop via the GEIS multiplexor. */
3868+ dbus_connection_set_watch_functions(client->connection,
3869+ _client_add_watch,
3870+ _client_remove_watch,
3871+ _client_toggle_watch,
3872+ client, 0);
3873+
3874+ /* Install a handler for any and all messages. */
3875+ dbus_connection_add_filter(client->connection,
3876+ _geis_dbus_client_message_handler,
3877+ client, 0);
3878+ if (client->state != GEIS_DBUS_CLIENT_INITIALIZING)
3879+ {
3880+ client->state = GEIS_DBUS_CLIENT_CONNECTING;
3881+ }
3882+
3883+final_exit:
3884+ return;
3885+}
3886+
3887+
3888+/*
3889+ * Creates a new GeisDBusClient.
3890+ */
3891+GeisDBusClient
3892+geis_dbus_client_new(Geis geis)
3893+{
3894+ GeisDBusClient client = calloc(1, sizeof(struct GeisDBusClient));
3895+ if (!client)
3896+ {
3897+ goto final_exit;
3898+ }
3899+
3900+ client->geis = geis;
3901+ client->state = GEIS_DBUS_CLIENT_INITIALIZING;
3902+
3903+ client->dispatcher = geis_dbus_dispatcher_new(geis);
3904+ if (!client->dispatcher)
3905+ {
3906+ goto unwind_client;
3907+ }
3908+
3909+ client->locator = geis_dbus_locator_new(client);
3910+ if (!client->locator)
3911+ {
3912+ goto unwind_dispatcher;
3913+ }
3914+
3915+ client->subscription_bag = geis_subscription_bag_new(1);
3916+ if (!client->subscription_bag)
3917+ {
3918+ goto unwind_locator;
3919+ }
3920+
3921+ goto final_exit;
3922+
3923+unwind_locator:
3924+ geis_dbus_locator_delete(client->locator);
3925+unwind_dispatcher:
3926+ geis_dbus_dispatcher_delete(client->dispatcher);
3927+unwind_client:
3928+ free(client);
3929+ client = NULL;
3930+final_exit:
3931+ return client;
3932+}
3933+
3934+
3935+/*
3936+ * Destroys a GeisDBusClient.
3937+ */
3938+void
3939+geis_dbus_client_delete(GeisDBusClient client)
3940+{
3941+ geis_subscription_bag_delete(client->subscription_bag);
3942+ geis_dbus_locator_delete(client->locator);
3943+ if (client->connection)
3944+ {
3945+ dbus_connection_unref(client->connection);
3946+ }
3947+ geis_dbus_dispatcher_delete(client->dispatcher);
3948+ free(client);
3949+}
3950+
3951+
3952+/*
3953+ * Gets the client dispatcher.
3954+ */
3955+GeisDBusDispatcher
3956+geis_dbus_client_dispatcher(GeisDBusClient client)
3957+{
3958+ return client->dispatcher;
3959+}
3960+
3961+
3962+/*
3963+ * Signals the client the server has been located.
3964+ */
3965+void
3966+geis_dbus_client_server_located(GeisDBusClient client)
3967+{
3968+ _client_connect(client, geis_dbus_locator_server_address(client->locator));
3969+}
3970+
3971+
3972+/*
3973+ * Signals the client the server has been dislocated.
3974+ */
3975+void
3976+geis_dbus_client_server_dislocated(GeisDBusClient client)
3977+{
3978+ GeisEvent event = geis_event_new(GEIS_EVENT_ERROR);
3979+ client->state = GEIS_DBUS_CLIENT_DISCONNECTED;
3980+ geis_post_event(client->geis, event);
3981+}
3982+
3983+
3984+/*
3985+ * Requests a subscription on the remote end.
3986+ */
3987+GeisStatus
3988+geis_dbus_client_subscribe(GeisDBusClient client,
3989+ GeisSubscription subscription)
3990+{
3991+ GeisStatus status = GEIS_STATUS_SUCCESS;
3992+
3993+ if (client->state == GEIS_DBUS_CLIENT_CONNECTED)
3994+ {
3995+ _dbus_client_subscribe(client, subscription);
3996+ }
3997+ geis_subscription_bag_insert(client->subscription_bag, subscription);
3998+
3999+ return status;
4000+}
4001+
4002+
4003+/*
4004+ * Destroys a subscription on the remote end.
4005+ */
4006+GeisStatus
4007+geis_dbus_client_unsubscribe(GeisDBusClient client,
4008+ GeisSubscription subscription)
4009+{
4010+ GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR;
4011+ if (geis_subscription_bag_find(client->subscription_bag,
4012+ geis_subscription_id(subscription)))
4013+ {
4014+ DBusMessage *msg;
4015+ DBusPendingCall *pending_return;
4016+
4017+ msg = geis_dbus_subscription_destroy_call_message(subscription);
4018+ dbus_connection_send_with_reply(client->connection, msg, &pending_return, -1);
4019+ dbus_message_unref(msg);
4020+ if (!pending_return)
4021+ {
4022+ geis_error("error sending DBus CreateSubscription method call");
4023+ goto final_exit;
4024+ }
4025+
4026+ dbus_pending_call_set_notify(pending_return,
4027+ _geis_dbus_client_unsubscribe_reply,
4028+ client, 0);
4029+ geis_subscription_bag_remove(client->subscription_bag, subscription);
4030+ status = GEIS_STATUS_SUCCESS;
4031+ }
4032+
4033+final_exit:
4034+ return status;
4035+}
4036+
4037+
4038+
4039+
4040
4041=== added file 'libutouch-geis/backend/dbus/geis_dbus_client.h'
4042--- libutouch-geis/backend/dbus/geis_dbus_client.h 1970-01-01 00:00:00 +0000
4043+++ libutouch-geis/backend/dbus/geis_dbus_client.h 2011-10-18 19:34:23 +0000
4044@@ -0,0 +1,97 @@
4045+/**
4046+ * @file geis_dbus_client.h
4047+ * @brief Interface for the GEIS DBus client.
4048+ *
4049+ * The GEIS DBus client offers remote GEIS functionality over a managed
4050+ * DBus connection.
4051+ *
4052+ * This header is for internal GEIS use only and contains no client
4053+ * (externally-visible) symbols.
4054+ */
4055+
4056+/*
4057+ * Copyright 2011 Canonical Ltd.
4058+ *
4059+ * This library is free software; you can redistribute it and/or modify it under
4060+ * the terms of the GNU Lesser General Public License as published by the Free
4061+ * Software Foundation; either version 3 of the License, or (at your option) any
4062+ * later version.
4063+ *
4064+ * This library is distributed in the hope that it will be useful, but WITHOUT
4065+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4066+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
4067+ * details.
4068+ *
4069+ * You should have received a copy of the GNU General Public License
4070+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4071+ */
4072+#ifndef GEIS_DBUS_CLIENT_H_
4073+#define GEIS_DBUS_CLIENT_H_
4074+
4075+#include "geis/geis.h"
4076+#include "geis_dbus_dispatcher.h"
4077+
4078+
4079+typedef struct GeisDBusClient *GeisDBusClient;
4080+
4081+
4082+/**
4083+ * Creates a new %GeisDBusClient object.
4084+ */
4085+GeisDBusClient
4086+geis_dbus_client_new(Geis geis);
4087+
4088+/**
4089+ * Destroys a %GeisDBusClient.
4090+ *
4091+ * @param[in] client A GeisDBusClient.
4092+ */
4093+void
4094+geis_dbus_client_delete(GeisDBusClient client);
4095+
4096+/**
4097+ * Gets the client dispatcher.
4098+ *
4099+ * @param[in] client A GeisDBusClient.
4100+ */
4101+GeisDBusDispatcher
4102+geis_dbus_client_dispatcher(GeisDBusClient client);
4103+
4104+/**
4105+ * Signals the client the server has been located.
4106+ *
4107+ * @param[in] client A GeisDBusClient.
4108+ */
4109+void
4110+geis_dbus_client_server_located(GeisDBusClient client);
4111+
4112+/**
4113+ * Signals the client the server has been dislocated.
4114+ *
4115+ * @param[in] client A GeisDBusClient.
4116+ */
4117+void
4118+geis_dbus_client_server_dislocated(GeisDBusClient client);
4119+
4120+/**
4121+ * Cerates a subscription on the remote end.
4122+ *
4123+ * @param[in] client The client-side of the DBus connection.
4124+ * @param[in] subscription The local subscription object.
4125+ */
4126+GeisStatus
4127+geis_dbus_client_subscribe(GeisDBusClient client,
4128+ GeisSubscription subscription);
4129+
4130+/**
4131+ * Deactivates a subscription on the remote end.
4132+ *
4133+ * @param[in] client The client-side of the DBus connection.
4134+ * @param[in] subscription The local subscription object.
4135+ */
4136+GeisStatus
4137+geis_dbus_client_unsubscribe(GeisDBusClient client,
4138+ GeisSubscription subscription);
4139+
4140+
4141+#endif /* GEIS_DBUS_CLIENT_H_ */
4142
4143=== added file 'libutouch-geis/backend/dbus/geis_dbus_locator.c'
4144--- libutouch-geis/backend/dbus/geis_dbus_locator.c 1970-01-01 00:00:00 +0000
4145+++ libutouch-geis/backend/dbus/geis_dbus_locator.c 2011-10-18 19:34:23 +0000
4146@@ -0,0 +1,270 @@
4147+/**
4148+ * @file geis_dbus_locator.c
4149+ * @brief Implementation of the GEIS DBus locator.
4150+ */
4151+
4152+/*
4153+ * Copyright 2011 Canonical Ltd.
4154+ *
4155+ * This library is free software; you can redistribute it and/or modify it under
4156+ * the terms of the GNU Lesser General Public License as published by the Free
4157+ * Software Foundation; either version 3 of the License, or (at your option) any
4158+ * later version.
4159+ *
4160+ * This library is distributed in the hope that it will be useful, but WITHOUT
4161+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4162+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
4163+ * details.
4164+ *
4165+ * You should have received a copy of the GNU General Public License
4166+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4167+ */
4168+#include "geis_config.h"
4169+#include "geis_dbus_locator.h"
4170+
4171+#include <dbus/dbus.h>
4172+#include "geis_dbus.h"
4173+#include "geis_logging.h"
4174+#include <stdio.h>
4175+#include <stdlib.h>
4176+#include <string.h>
4177+
4178+
4179+typedef enum GeisDBusLocatorState
4180+{
4181+ GEIS_DBUS_LOCATOR_STATE_INITIALIZING,
4182+ GEIS_DBUS_LOCATOR_STATE_LOCATING,
4183+ GEIS_DBUS_LOCATOR_STATE_WAITING,
4184+ GEIS_DBUS_LOCATOR_STATE_FINALIZING
4185+} GeisDBusLocatorState;
4186+
4187+
4188+struct GeisDBusLocator
4189+{
4190+ GeisDBusClient client;
4191+ GeisDBusLocatorState state;
4192+ DBusConnection *session_bus;
4193+ char *server_address;
4194+ dbus_uint32_t serial;
4195+};
4196+
4197+
4198+/*
4199+ * Performs the act of actually locating the server.
4200+ */
4201+static void
4202+_locator_find_server(GeisDBusLocator locator)
4203+{
4204+ locator->state = GEIS_DBUS_LOCATOR_STATE_LOCATING;
4205+ DBusMessage *msg = dbus_message_new_method_call(GEIS_DBUS_SERVICE_INTERFACE,
4206+ GEIS_DBUS_SERVICE_PATH,
4207+ GEIS_DBUS_SERVICE_INTERFACE,
4208+ GEIS_DBUS_GET_SERVER_ADDRESS);
4209+ dbus_connection_send(locator->session_bus, msg, &locator->serial);
4210+ dbus_message_unref(msg);
4211+}
4212+
4213+
4214+/*
4215+ * A generic message handler function.
4216+ */
4217+static DBusHandlerResult
4218+_locator_message_handler(DBusConnection *connection GEIS_UNUSED,
4219+ DBusMessage *message,
4220+ void *user_data)
4221+{
4222+ DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
4223+ GeisDBusLocator locator = (GeisDBusLocator)user_data;
4224+ int type = dbus_message_get_type(message);
4225+
4226+ if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged"))
4227+ {
4228+ char *name;
4229+ char *old_owner;
4230+ char *new_owner;
4231+ dbus_message_get_args(message, NULL,
4232+ DBUS_TYPE_STRING, &name,
4233+ DBUS_TYPE_STRING, &old_owner,
4234+ DBUS_TYPE_STRING, &new_owner,
4235+ DBUS_TYPE_INVALID);
4236+ if (strlen(old_owner))
4237+ {
4238+ geis_debug("%s has gone away", name);
4239+ geis_dbus_client_server_dislocated(locator->client);
4240+ result = DBUS_HANDLER_RESULT_HANDLED;
4241+ }
4242+ else if (strlen(new_owner))
4243+ {
4244+ geis_debug("%s has appeared", name);
4245+ _locator_find_server(locator);
4246+ result = DBUS_HANDLER_RESULT_HANDLED;
4247+ }
4248+ }
4249+ else if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN)
4250+ {
4251+ if (locator->serial == dbus_message_get_reply_serial(message))
4252+ {
4253+ const char *s = NULL;
4254+ dbus_message_get_args(message, NULL,
4255+ DBUS_TYPE_STRING, &s,
4256+ DBUS_TYPE_INVALID);
4257+ locator->server_address = strdup(s);
4258+ geis_dbus_client_server_located(locator->client);
4259+ result = DBUS_HANDLER_RESULT_HANDLED;
4260+ }
4261+ }
4262+ else if (type == DBUS_MESSAGE_TYPE_ERROR)
4263+ {
4264+ if (dbus_message_is_error(message, DBUS_ERROR_SERVICE_UNKNOWN))
4265+ {
4266+ geis_warning("server not found!");
4267+ geis_dbus_client_server_dislocated(locator->client);
4268+ result = DBUS_HANDLER_RESULT_HANDLED;
4269+ }
4270+ else
4271+ {
4272+ const char *str = NULL;
4273+ dbus_message_get_args(message, NULL,
4274+ DBUS_TYPE_STRING, &str,
4275+ DBUS_TYPE_INVALID);
4276+ geis_warning("error %s: %s", dbus_message_get_error_name(message), str);
4277+ }
4278+ }
4279+
4280+ return result;
4281+}
4282+
4283+
4284+/*
4285+ * Adds the locator watches to the dispatcher watch list.
4286+ */
4287+static dbus_bool_t
4288+_locator_add_watch(DBusWatch *watch, void *data)
4289+{
4290+ dbus_bool_t status = TRUE;
4291+ GeisDBusLocator locator = (GeisDBusLocator)data;
4292+ GeisDBusDispatcher dispatcher = geis_dbus_client_dispatcher(locator->client);
4293+
4294+ geis_dbus_dispatcher_register(dispatcher, locator->session_bus, watch);
4295+ return status;
4296+}
4297+
4298+
4299+/*
4300+ * Toggles the enabled/disabled status of the locator watches.
4301+ */
4302+static void
4303+_locator_toggle_watch(DBusWatch *watch, void *data)
4304+{
4305+ GeisDBusLocator locator = (GeisDBusLocator)data;
4306+ GeisDBusDispatcher dispatcher = geis_dbus_client_dispatcher(locator->client);
4307+
4308+ geis_dbus_dispatcher_toggle_watch(dispatcher, watch);
4309+}
4310+
4311+
4312+/*
4313+ * Removes the locator watches from the dispatcher watch list.
4314+ */
4315+static void
4316+_locator_remove_watch(DBusWatch *watch, void *data)
4317+{
4318+ GeisDBusLocator locator = (GeisDBusLocator)data;
4319+ GeisDBusDispatcher dispatcher = geis_dbus_client_dispatcher(locator->client);
4320+
4321+ geis_dbus_dispatcher_unregister(dispatcher, watch);
4322+}
4323+
4324+
4325+/*
4326+ * Creates a new GeisDBusLocator object.
4327+ */
4328+GeisDBusLocator
4329+geis_dbus_locator_new(GeisDBusClient client)
4330+{
4331+ GeisDBusLocator locator = calloc(1, sizeof(struct GeisDBusLocator));
4332+ if (!locator)
4333+ {
4334+ goto final_exit;
4335+ }
4336+
4337+ locator->client = client;
4338+ locator->state = GEIS_DBUS_LOCATOR_STATE_INITIALIZING;
4339+
4340+ /* Connect to the DBus session bus. */
4341+ DBusError error = DBUS_ERROR_INIT;
4342+ locator->session_bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
4343+ if (!locator->session_bus || dbus_error_is_set(&error))
4344+ {
4345+ char msg[512];
4346+ snprintf(msg, sizeof(msg), "error %s connecting to session bus: %s",
4347+ error.name, error.message);
4348+ geis_error("%s", msg);
4349+ goto unwind_error;
4350+ }
4351+
4352+ /* Integrate with the app event loop via the GEIS multiplexor. */
4353+ dbus_connection_set_watch_functions(locator->session_bus,
4354+ _locator_add_watch,
4355+ _locator_remove_watch,
4356+ _locator_toggle_watch,
4357+ locator, 0);
4358+
4359+ /* Look for server-connect and server-disconnect messages. */
4360+ dbus_bus_add_match(locator->session_bus,
4361+ "type='signal',sender='" DBUS_SERVICE_DBUS "'," \
4362+ "interface='" DBUS_INTERFACE_DBUS "'," \
4363+ "member='NameOwnerChanged'," \
4364+ "arg0='" GEIS_DBUS_SERVICE_INTERFACE "'",
4365+ &error);
4366+ if (dbus_error_is_set(&error))
4367+ {
4368+ char msg[512];
4369+ snprintf(msg, sizeof(msg), "error %s adding match to session bus: %s",
4370+ error.name, error.message);
4371+ geis_error("%s", msg);
4372+ goto unwind_error;
4373+ }
4374+
4375+ /* Install a handler for any and all messages. */
4376+ dbus_connection_add_filter(locator->session_bus,
4377+ _locator_message_handler,
4378+ locator, 0);
4379+
4380+ /* OK, go eh? */
4381+ _locator_find_server(locator);
4382+
4383+unwind_error:
4384+ dbus_error_free(&error);
4385+final_exit:
4386+ return locator;
4387+}
4388+
4389+
4390+/*
4391+ * Destroys a %GeisDBusLocator object.
4392+ */
4393+void
4394+geis_dbus_locator_delete(GeisDBusLocator locator)
4395+{
4396+ if (locator)
4397+ {
4398+ if (locator->server_address)
4399+ {
4400+ free(locator->server_address);
4401+ }
4402+ if (locator->session_bus)
4403+ {
4404+ dbus_connection_unref(locator->session_bus);
4405+ }
4406+ free(locator);
4407+ }
4408+}
4409+
4410+
4411+char *
4412+geis_dbus_locator_server_address(GeisDBusLocator locator)
4413+{
4414+ return locator->server_address;
4415+}
4416+
4417
4418=== added file 'libutouch-geis/backend/dbus/geis_dbus_locator.h'
4419--- libutouch-geis/backend/dbus/geis_dbus_locator.h 1970-01-01 00:00:00 +0000
4420+++ libutouch-geis/backend/dbus/geis_dbus_locator.h 2011-10-18 19:34:23 +0000
4421@@ -0,0 +1,62 @@
4422+/**
4423+ * @file geis_dbus_locator.h
4424+ * @brief Interface for the GEIS DBus locator.
4425+ *
4426+ * The GEIS DBus locator makes the location of the GEIS DBus server available
4427+ * over the DBus session bus.
4428+ *
4429+ * This header is for internal GEIS use only and contains no client
4430+ * (externally-visible) symbols.
4431+ */
4432+
4433+/*
4434+ * Copyright 2011 Canonical Ltd.
4435+ *
4436+ * This library is free software; you can redistribute it and/or modify it under
4437+ * the terms of the GNU Lesser General Public License as published by the Free
4438+ * Software Foundation; either version 3 of the License, or (at your option) any
4439+ * later version.
4440+ *
4441+ * This library is distributed in the hope that it will be useful, but WITHOUT
4442+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4443+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
4444+ * details.
4445+ *
4446+ * You should have received a copy of the GNU General Public License
4447+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4448+ */
4449+#ifndef GEIS_DBUS_LOCATOR_H_
4450+#define GEIS_DBUS_LOCATOR_H_
4451+
4452+#include "geis/geis.h"
4453+#include "geis_dbus_client.h"
4454+
4455+
4456+typedef struct GeisDBusLocator *GeisDBusLocator;
4457+
4458+
4459+/**
4460+ * Creates a new GeisDBusLocator object.
4461+ *
4462+ * @param[in] client A GEIS DBus CLient.
4463+ */
4464+GeisDBusLocator
4465+geis_dbus_locator_new(GeisDBusClient client);
4466+
4467+/**
4468+ * Destroys a %GeisDBusLocator object.
4469+ *
4470+ * @param[in] locator A GeisDBusLocator.
4471+ */
4472+void
4473+geis_dbus_locator_delete(GeisDBusLocator locator);
4474+
4475+/**
4476+ * Gets the currently located server address.
4477+ *
4478+ * @param[in] locator A GeisDBusLocator.
4479+ */
4480+char *
4481+geis_dbus_locator_server_address(GeisDBusLocator locator);
4482+
4483+#endif /* GEIS_DBUS_LOCATOR_H_ */
4484
4485=== modified file 'libutouch-geis/backend/test_fixture/geis_backend_test_fixture.c'
4486--- libutouch-geis/backend/test_fixture/geis_backend_test_fixture.c 2011-08-18 18:14:12 +0000
4487+++ libutouch-geis/backend/test_fixture/geis_backend_test_fixture.c 2011-10-18 19:34:23 +0000
4488@@ -77,8 +77,8 @@
4489 static GeisBackendToken _token_clone(GeisBackendToken);
4490 static void _token_finalize(GeisBackendToken);
4491 static void _token_compose(GeisBackendToken, GeisBackendToken);
4492-static GeisStatus _token_activate(GeisBackendToken);
4493-static GeisStatus _token_deactivate(GeisBackendToken);
4494+static GeisStatus _token_activate(GeisBackendToken, GeisSubscription);
4495+static GeisStatus _token_deactivate(GeisBackendToken, GeisSubscription);
4496
4497 static struct GeisBackendTokenVtable _token_vtbl = {
4498 _token_clone,
4499@@ -361,7 +361,8 @@
4500
4501
4502 GeisStatus
4503-_token_activate(GeisBackendToken gbtoken)
4504+_token_activate(GeisBackendToken gbtoken,
4505+ GeisSubscription subscription GEIS_UNUSED)
4506 {
4507 GeisStatus status = GEIS_STATUS_SUCCESS;
4508 TestBackendToken token = _tbtoken_from_token(gbtoken);
4509@@ -371,7 +372,8 @@
4510
4511
4512 GeisStatus
4513-_token_deactivate(GeisBackendToken gbtoken GEIS_UNUSED)
4514+_token_deactivate(GeisBackendToken gbtoken GEIS_UNUSED,
4515+ GeisSubscription subscription GEIS_UNUSED)
4516 {
4517 GeisStatus status = GEIS_STATUS_SUCCESS;
4518 return status;
4519@@ -381,7 +383,7 @@
4520 __attribute__((constructor))
4521 static void _register_test_fixture()
4522 {
4523- geis_register_backend(GEIS_INIT_UTOUCH_MOCK_ENGINE,
4524+ geis_register_backend(GEIS_INIT_UTOUCH_MOCK_BACKEND,
4525 sizeof(struct GeisBackendTestFixture),
4526 &tf_vtbl);
4527 }
4528
4529=== modified file 'libutouch-geis/backend/xcb/geis_xcb_backend.c'
4530--- libutouch-geis/backend/xcb/geis_xcb_backend.c 2011-09-02 15:52:27 +0000
4531+++ libutouch-geis/backend/xcb/geis_xcb_backend.c 2011-10-18 19:34:23 +0000
4532@@ -105,7 +105,7 @@
4533 static void _construct(void *mem, Geis geis);
4534 static void _finalize(GeisBackend g);
4535 static GeisBackendToken _create_token(GeisBackend be, GeisBackendTokenInitState);
4536-static void _fd_callback(int fd, GeisBackendMultiplexorEvent ev, void *ctx);
4537+static void _fd_callback(int fd, GeisBackendMultiplexorActivity ev, void *ctx);
4538
4539
4540 static struct GeisBackendVtable be_vtbl = {
4541@@ -116,7 +116,7 @@
4542
4543
4544 /* A handy little table to map grail types to geis gesture classes. */
4545-struct GrailTypeToGeisClass
4546+static struct GrailTypeToGeisClass
4547 {
4548 GeisInteger grail_type;
4549 GeisGestureClass geis_class;
4550@@ -156,7 +156,8 @@
4551 { GRAIL_TYPE_MTOUCH, NULL }
4552 };
4553
4554-GeisSize s_grail_type_map_size = sizeof(s_grail_type_map) / sizeof(struct GrailTypeToGeisClass);
4555+static GeisSize s_grail_type_map_size = sizeof(s_grail_type_map)
4556+ / sizeof(struct GrailTypeToGeisClass);
4557
4558 static void
4559 _set_grail_type_class(GeisInteger grail_type, GeisGestureClass geis_class)
4560@@ -653,7 +654,8 @@
4561 }
4562
4563 be->xcb_fd = xcb_get_file_descriptor(be->xcb_connection);
4564- geis_multiplex_fd(be->geis, be->xcb_fd, _fd_callback, be);
4565+ geis_multiplex_fd(be->geis, be->xcb_fd, GEIS_BE_MX_READ_AVAILABLE,
4566+ _fd_callback, be);
4567
4568 be->sub_table = geis_xcb_backend_sub_table_new();
4569
4570@@ -933,9 +935,9 @@
4571
4572 /** @todo implement this */
4573 void
4574-_fd_callback(int fd GEIS_UNUSED,
4575- GeisBackendMultiplexorEvent ev GEIS_UNUSED,
4576- void *ctx)
4577+_fd_callback(int fd GEIS_UNUSED,
4578+ GeisBackendMultiplexorActivity ev GEIS_UNUSED,
4579+ void *ctx)
4580 {
4581 GeisXcbBackend be = (GeisXcbBackend)ctx;
4582 _xcb_dispatch(be);
4583@@ -1022,7 +1024,7 @@
4584 __attribute__((constructor))
4585 static void _register_xcb_backend()
4586 {
4587- geis_register_backend(GEIS_INIT_UTOUCH_XCB,
4588+ geis_register_backend(GEIS_INIT_UTOUCH_XCB_BACKEND,
4589 sizeof(struct GeisXcbBackend),
4590 &be_vtbl);
4591 }
4592
4593=== modified file 'libutouch-geis/backend/xcb/geis_xcb_backend_token.c'
4594--- libutouch-geis/backend/xcb/geis_xcb_backend_token.c 2011-08-29 18:41:20 +0000
4595+++ libutouch-geis/backend/xcb/geis_xcb_backend_token.c 2011-10-18 19:34:23 +0000
4596@@ -55,8 +55,8 @@
4597 static GeisBackendToken _token_clone(GeisBackendToken);
4598 static void _token_finalize(GeisBackendToken);
4599 static void _token_compose(GeisBackendToken, GeisBackendToken);
4600-static GeisStatus _token_activate(GeisBackendToken);
4601-static GeisStatus _token_deactivate(GeisBackendToken);
4602+static GeisStatus _token_activate(GeisBackendToken, GeisSubscription);
4603+static GeisStatus _token_deactivate(GeisBackendToken, GeisSubscription);
4604
4605 static struct GeisBackendTokenVtable _token_vtbl = {
4606 _token_clone,
4607@@ -317,7 +317,7 @@
4608 * various back end subscriptions appropriately.
4609 */
4610 static GeisStatus
4611-_token_activate(GeisBackendToken token)
4612+_token_activate(GeisBackendToken token, GeisSubscription subscripton GEIS_UNUSED)
4613 {
4614 GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR;
4615 XcbBackendToken t = _xcb_token_from_geis_token(token);
4616@@ -338,7 +338,7 @@
4617 * various back end subscriptions appropriately.
4618 */
4619 static GeisStatus
4620-_token_deactivate(GeisBackendToken token)
4621+_token_deactivate(GeisBackendToken token, GeisSubscription sub GEIS_UNUSED)
4622 {
4623 GeisStatus status = GEIS_STATUS_SUCCESS;
4624 XcbBackendToken t = _xcb_token_from_geis_token(token);
4625
4626=== modified file 'libutouch-geis/backend/xcb/grail_gestures.c'
4627--- libutouch-geis/backend/xcb/grail_gestures.c 2011-07-22 15:54:50 +0000
4628+++ libutouch-geis/backend/xcb/grail_gestures.c 2011-10-18 19:34:23 +0000
4629@@ -505,7 +505,7 @@
4630 (char *)grail_class->name);
4631 geis_frame_add_attr(frame, attr);
4632
4633- attr = geis_attr_new("geis gesture class id",
4634+ attr = geis_attr_new(GEIS_CLASS_ATTRIBUTE_ID,
4635 GEIS_ATTR_TYPE_INTEGER,
4636 (void *)&grail_class->geis_class_id);
4637 geis_frame_add_attr(frame, attr);
4638
4639=== modified file 'libutouch-geis/geis.c'
4640--- libutouch-geis/geis.c 2011-08-21 16:28:27 +0000
4641+++ libutouch-geis/geis.c 2011-10-18 19:34:23 +0000
4642@@ -32,6 +32,7 @@
4643 #include "geis_attr.h"
4644 #include "geis_backend.h"
4645 #include "geis_class.h"
4646+#include "server/geis_dbus_server.h" /* @TODO replace me */
4647 #include "geis_device.h"
4648 #include "geis_backend_multiplexor.h"
4649 #include "geis_error.h"
4650@@ -45,16 +46,6 @@
4651
4652
4653 /*
4654- * An internal struct to collect filterable attributes for facilities.
4655- */
4656-typedef struct FilterableAttributeBag
4657-{
4658- GeisFilterableAttribute store;
4659- GeisSize size;
4660- GeisSize count;
4661-} *FilterableAttributeBag;
4662-
4663-/*
4664 * An internal structure to track processing callbacks in some order.
4665 */
4666 typedef struct GeisProcessingEntry *GeisProcessingEntry;
4667@@ -78,6 +69,8 @@
4668 GeisSubBag subscription_bag;
4669 GeisBackendMultiplexor backend_multiplexor;
4670 GeisBackend backend;
4671+ GeisBoolean backend_pending;
4672+ GeisDBusServer server; /* @TODO: replace me */
4673 GeisEventQueue input_event_queue;
4674 int input_event_signal_pipe[2];
4675 GeisProcessingEntry processing_callbacks;
4676@@ -200,12 +193,14 @@
4677 * Filters and transforms raw gesture events into cooked gesture events.
4678 */
4679 static void
4680-_input_event_handler(int fd, GeisBackendMultiplexorEvent mux_ev, void *context)
4681+_input_event_handler(int fd,
4682+ GeisBackendMultiplexorActivity activity,
4683+ void *context)
4684 {
4685 Geis geis = (Geis)context;
4686 GeisProcessingEntry cb;
4687
4688- if (mux_ev == GEIS_BE_MX_READ_AVAILABLE)
4689+ if (activity & GEIS_BE_MX_READ_AVAILABLE)
4690 {
4691 GeisEvent event;
4692
4693@@ -234,6 +229,20 @@
4694 handled = _class_event_handler(geis, event);
4695 break;
4696
4697+ case GEIS_EVENT_INIT_COMPLETE:
4698+ geis->backend_pending = GEIS_FALSE;
4699+ break;
4700+
4701+ case GEIS_EVENT_ERROR:
4702+ if (geis->backend_pending)
4703+ {
4704+ geis->backend = geis_backend_by_name(geis,
4705+ GEIS_INIT_UTOUCH_XCB_BACKEND);
4706+ geis->backend_pending = GEIS_FALSE;
4707+ handled = GEIS_TRUE;
4708+ }
4709+ break;
4710+
4711 default:
4712 break;
4713 }
4714@@ -273,93 +282,6 @@
4715
4716
4717 /*
4718- * Constructs a new filterable attribute bag.
4719- */
4720-static FilterableAttributeBag
4721-_filterable_attribute_bag_new()
4722-{
4723- FilterableAttributeBag bag = calloc(1, sizeof(struct FilterableAttributeBag));
4724- if (!bag)
4725- {
4726- geis_error("failed to allocate filterable attribute bag");
4727- goto final_exit;
4728- }
4729-
4730- bag->size = 2;
4731- bag->count = 0;
4732-
4733- bag->store = calloc(1, sizeof(struct GeisFilterableAttribute));
4734- if (!bag)
4735- {
4736- geis_error("failed to allocate filterable attribute bag store");
4737- goto unwind_bag;
4738- }
4739- goto final_exit;
4740-
4741-unwind_bag:
4742- free(bag);
4743- bag = NULL;
4744-final_exit:
4745- return bag;
4746-}
4747-
4748-
4749-/*
4750- * Destroys a filterable attribute bag.
4751- */
4752-static void
4753-_filterable_attribute_bag_delete(FilterableAttributeBag bag)
4754-{
4755- if (bag)
4756- {
4757- GeisSize i;
4758- for (i = 0; i < bag->count; ++i)
4759- {
4760- free((char *)bag->store[i].name);
4761- }
4762- free(bag->store);
4763- }
4764- free(bag);
4765-}
4766-
4767-
4768-static void
4769-_filterable_attribute_copy(GeisFilterableAttribute src,
4770- GeisFilterableAttribute dst)
4771-{
4772- dst->name = strdup(src->name);
4773- dst->type = src->type;
4774- dst->add_term_callback = src->add_term_callback;
4775- dst->add_term_context = src->add_term_context;
4776-}
4777-
4778-
4779-static void
4780-_filterable_attribute_bag_insert(FilterableAttributeBag bag,
4781- GeisFilterableAttribute fa)
4782-{
4783- GeisSize new_count = bag->count + 1;
4784- if (new_count >= bag->size)
4785- {
4786- GeisSize new_size = bag->size * 2;
4787- GeisSize allocation_size = new_size * sizeof(struct GeisFilterableAttribute);
4788- GeisFilterableAttribute new_store = realloc(bag->store, allocation_size);
4789- if (!new_store)
4790- {
4791- geis_error("failed to reallocate filterable attribute bag store");
4792- }
4793- else
4794- {
4795- bag->store = new_store;
4796- bag->size = new_size;
4797- }
4798- }
4799- _filterable_attribute_copy(fa, &bag->store[bag->count]);
4800- bag->count = new_count;
4801-}
4802-
4803-
4804-/*
4805 * Applies the back end callback to the back end token for each filterable
4806 * attribute with a name matching the argument.
4807 */
4808@@ -371,13 +293,16 @@
4809 void *value)
4810 {
4811 GeisStatus status = GEIS_STATUS_SUCCESS;
4812- GeisSize i;
4813- for (i = 0; i < bag->count; ++i)
4814+ GeisFilterableAttributeBagIter it;
4815+ for (it = geis_filterable_attribute_bag_begin(bag);
4816+ it != geis_filterable_attribute_bag_end(bag);
4817+ it = geis_filterable_attribute_bag_next(bag, it))
4818 {
4819- GeisFilterableAttribute fa = &bag->store[i];
4820- if (0 == strcmp(fa->name, name))
4821+ if (0 == strcmp(it->name, name) && it->add_term_callback)
4822 {
4823- status = fa->add_term_callback(token, fa->add_term_context, name, op, value);
4824+ status = it->add_term_callback(token,
4825+ it->add_term_context,
4826+ name, op, value);
4827 }
4828 }
4829 return status;
4830@@ -389,11 +314,11 @@
4831 */
4832 GeisStatus
4833 geis_filterable_attribute_foreach(Geis geis,
4834- GeisFilterFacility facility,
4835- GeisBackendToken token,
4836- GeisString name,
4837- GeisFilterOperation op,
4838- void *value)
4839+ GeisFilterFacility facility,
4840+ GeisBackendToken token,
4841+ GeisString name,
4842+ GeisFilterOperation op,
4843+ void *value)
4844 {
4845 GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR;
4846 switch (facility)
4847@@ -470,6 +395,7 @@
4848 }
4849 geis_backend_multiplexor_add_fd(geis->backend_multiplexor,
4850 geis->input_event_signal_pipe[0],
4851+ GEIS_BE_MX_READ_AVAILABLE,
4852 _input_event_handler,
4853 geis);
4854
4855@@ -482,7 +408,7 @@
4856 }
4857 geis->output_event_callback = _default_output_event_callback;
4858
4859- geis->class_filterable_attributes = _filterable_attribute_bag_new();
4860+ geis->class_filterable_attributes = geis_filterable_attribute_bag_new();
4861 if (!geis->class_filterable_attributes)
4862 {
4863 geis_error_push(NULL, GEIS_STATUS_UNKNOWN_ERROR);
4864@@ -499,7 +425,7 @@
4865 }
4866 geis->class_event_callback = _default_output_event_callback;
4867
4868- geis->device_filterable_attributes = _filterable_attribute_bag_new();
4869+ geis->device_filterable_attributes = geis_filterable_attribute_bag_new();
4870 if (!geis->device_filterable_attributes)
4871 {
4872 geis_error_push(NULL, GEIS_STATUS_UNKNOWN_ERROR);
4873@@ -516,13 +442,13 @@
4874 }
4875 geis->device_event_callback = _default_output_event_callback;
4876
4877- geis->region_filterable_attributes = _filterable_attribute_bag_new();
4878+ geis->region_filterable_attributes = geis_filterable_attribute_bag_new();
4879 if (!geis->region_filterable_attributes)
4880 {
4881 goto unwind_device_bag;
4882 }
4883
4884- geis->special_filterable_attributes = _filterable_attribute_bag_new();
4885+ geis->special_filterable_attributes = geis_filterable_attribute_bag_new();
4886 if (!geis->special_filterable_attributes)
4887 {
4888 goto unwind_region_attrs;
4889@@ -531,15 +457,15 @@
4890 goto final_exit;
4891
4892 unwind_region_attrs:
4893- _filterable_attribute_bag_delete(geis->region_filterable_attributes);
4894+ geis_filterable_attribute_bag_delete(geis->region_filterable_attributes);
4895 unwind_device_bag:
4896 geis_device_bag_delete(geis->devices);
4897 unwind_device_attrs:
4898- _filterable_attribute_bag_delete(geis->device_filterable_attributes);
4899+ geis_filterable_attribute_bag_delete(geis->device_filterable_attributes);
4900 unwind_class_bag:
4901 geis_gesture_class_bag_delete(geis->gesture_classes);
4902 unwind_class_attrs:
4903- _filterable_attribute_bag_delete(geis->class_filterable_attributes);
4904+ geis_filterable_attribute_bag_delete(geis->class_filterable_attributes);
4905 unwind_output_queue:
4906 geis_event_queue_delete(geis->output_event_queue);
4907 unwind_input_signal_pipe:
4908@@ -564,6 +490,7 @@
4909 {
4910 BACK_END_TYPE_NONE,
4911 BACK_END_TYPE_MOCK_ENGINE,
4912+ BACK_END_TYPE_DBUS,
4913 BACK_END_TYPE_XCB
4914 } BackendType;
4915
4916@@ -580,7 +507,7 @@
4917 {
4918 if (0 == strcmp(init_arg_name, GEIS_INIT_SERVICE_PROVIDER))
4919 {
4920- geis_debug("initializing GEIS server");
4921+ geis->server = geis_dbus_server_new(geis);
4922 }
4923 else if (0 == strcmp(init_arg_name, GEIS_INIT_TRACK_DEVICES))
4924 {
4925@@ -590,7 +517,7 @@
4926 {
4927 /* no longer supported */
4928 }
4929- else if (0 == strcmp(init_arg_name, GEIS_INIT_UTOUCH_MOCK_ENGINE))
4930+ else if (0 == strcmp(init_arg_name, GEIS_INIT_UTOUCH_MOCK_BACKEND))
4931 {
4932 if (back_end_type != BACK_END_TYPE_NONE)
4933 {
4934@@ -598,7 +525,15 @@
4935 }
4936 back_end_type = BACK_END_TYPE_MOCK_ENGINE;
4937 }
4938- else if (0 == strcmp(init_arg_name, GEIS_INIT_UTOUCH_XCB))
4939+ else if (0 == strcmp(init_arg_name, GEIS_INIT_UTOUCH_DBUS_BACKEND))
4940+ {
4941+ if (back_end_type != BACK_END_TYPE_NONE)
4942+ {
4943+ geis_error("multiple back ends requested, only using last request");
4944+ }
4945+ back_end_type = BACK_END_TYPE_DBUS;
4946+ }
4947+ else if (0 == strcmp(init_arg_name, GEIS_INIT_UTOUCH_XCB_BACKEND))
4948 {
4949 if (back_end_type != BACK_END_TYPE_NONE)
4950 {
4951@@ -612,16 +547,22 @@
4952
4953 if (back_end_type == BACK_END_TYPE_MOCK_ENGINE)
4954 {
4955- geis->backend = geis_backend_by_name(geis, GEIS_INIT_UTOUCH_MOCK_ENGINE);
4956- }
4957- else if (back_end_type ==BACK_END_TYPE_XCB)
4958- {
4959- geis->backend = geis_backend_by_name(geis, GEIS_INIT_UTOUCH_XCB);
4960+ geis->backend = geis_backend_by_name(geis, GEIS_INIT_UTOUCH_MOCK_BACKEND);
4961+ }
4962+ else if (back_end_type == BACK_END_TYPE_DBUS)
4963+ {
4964+ geis->backend = geis_backend_by_name(geis, GEIS_INIT_UTOUCH_DBUS_BACKEND);
4965+ geis->backend_pending = GEIS_TRUE;
4966+ }
4967+ else if (back_end_type == BACK_END_TYPE_XCB)
4968+ {
4969+ geis->backend = geis_backend_by_name(geis, GEIS_INIT_UTOUCH_XCB_BACKEND);
4970 }
4971 else
4972 {
4973- geis_warning("back end not specified, defaulting to XCB");
4974- geis->backend = geis_backend_by_name(geis, GEIS_INIT_UTOUCH_XCB);
4975+ geis_warning("back end not specified, defaulting to DBus");
4976+ geis->backend = geis_backend_by_name(geis, GEIS_INIT_UTOUCH_DBUS_BACKEND);
4977+ geis->backend_pending = GEIS_TRUE;
4978 }
4979 if (!geis->backend)
4980 {
4981@@ -681,16 +622,18 @@
4982 }
4983
4984 geis_gesture_flick_delete(geis->flick);
4985- _filterable_attribute_bag_delete(geis->special_filterable_attributes);
4986- _filterable_attribute_bag_delete(geis->region_filterable_attributes);
4987+ geis_filterable_attribute_bag_delete(geis->special_filterable_attributes);
4988+ geis_filterable_attribute_bag_delete(geis->region_filterable_attributes);
4989 geis_device_bag_delete(geis->devices);
4990- _filterable_attribute_bag_delete(geis->device_filterable_attributes);
4991+ geis_filterable_attribute_bag_delete(geis->device_filterable_attributes);
4992 geis_gesture_class_bag_delete(geis->gesture_classes);
4993- _filterable_attribute_bag_delete(geis->class_filterable_attributes);
4994+ geis_filterable_attribute_bag_delete(geis->class_filterable_attributes);
4995 geis_event_queue_delete(geis->output_event_queue);
4996 close(geis->input_event_signal_pipe[0]);
4997 close(geis->input_event_signal_pipe[1]);
4998 geis_event_queue_delete(geis->input_event_queue);
4999+ if (geis->server)
5000+ geis_dbus_server_delete(geis->server);
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: