aboutsummaryrefslogtreecommitdiff
path: root/libcontextprovider/src/contextc.cpp
blob: 2125479a668c073023fbc8bbce089926989cec2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
/*
 * Copyright (C) 2008 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include "contextc.h"
#include "service.h"
#include "property.h"
#include "group.h"
#include "logging.h"
#include "sconnect.h"
#include "listeners.h"
#include "loggingfeatures.h"

#include <QCoreApplication>

namespace ContextProvider {
}

using namespace ContextProvider;

/*!
    \page CApi C Api

    \brief The libcontextprovider library offers a simple plain-C API to be used
    from any C program.

    \section Usage

    \code
    context_provider_init(DBUS_BUS_SESSION, "org.test.provider");

    context_provider_install_key("Battery.OnBattery", 0, NULL, NULL);
    context_provider_install_key("Battery.ChargePercentage", 0, NULL, NULL);

    context_provider_set_boolean("Battery.OnBattery", 1);
    context_provider_set_integer("Battery.ChargePercentage", 55);
    \endcode

    The above code snippet starts a service at "org.test.provider" with two
    keys ("Battery.OnBattery", "Battery.ChargePercentage") and sets their
    respective values.

    Note: If the provider used other D-Bus bindings than QDBus, the
    service name ("org.test.provider") needs to be unique, i.e., the
    provider process should not register it itself.

    \section Callbacks

    The context_provider_install_key function and context_provider_install_group function
    take arguments specyfying the callback function. The callback is executed when the
    subscription status changes for the key or the key group (first subscriber
    appears or last subscriber goes away). Basing on this info the provider can
    manage it's resources. It's okay also to use the callback function to actually
    set the value.

    \code
    void callback_function_example(int subscribed, void* user_data)
    {
        if (subscribed) {
            // First subscriber appeared.
            // Start ie. pooling the data.
        } else {
            // Last subscribed disappeared.
            // Stop  pooling data, release resources.
        }
    }
    \endcode
*/

static Service *cService;

QList<Listener*> *listeners = NULL;

char argv[] = "libcontextprovider";
char* p= argv;
int argc = 1;
QCoreApplication* app = 0;

/// Initializes and starts the service with a given \a bus_type and a \a bus_name.
/// The \a bus_type can be DBUS_BUS_SESSION or DBUS_BUS_SYSTEM. This function can be
/// called only once till a matching context_provider_stop is called.
int context_provider_init (DBusBusType bus_type, const char* bus_name)
{
    contextDebug() << F_C << bus_name;

    if (QCoreApplication::instance() == 0) {
        // No QCoreApplication created, so crate one.
        // This will also create an event dispatcher (QEventDispatcherGlibPrivate.)
        app = new QCoreApplication(argc, &p);
    }

    if (cService != NULL) {
        contextCritical() << "Service already initialize. You can only initialize one service with C API";
        return 0;
    }

    cService = new Service(bus_type == DBUS_BUS_SESSION
                           ? QDBusConnection::SessionBus
                           : QDBusConnection::SystemBus,
                           bus_name);
    listeners = new QList<Listener*>;

    return 1;
}

/// Stops the currently started service with context_provider_init. After calling
/// this function a new service can be started by calling context_provider_init.
void context_provider_stop (void)
{
    contextDebug() << F_C;
    if (cService) {
        contextDebug() << "Stopping service";

        // Delete all listeners
        if (listeners) {
            foreach (Listener *listener, *listeners)
                delete listener;
        }
        delete listeners; listeners = NULL;

        delete cService;
        cService = NULL;
    }
    // FIXME: Do we need to do something with the QCoreApplication we might have constructed?
}

/// Installs (adds) a \a key to be provided by the service. The callback function \a
/// subscription_changed_cb will be called with the passed user data \a subscription_changed_cb_target
/// when the status of the subscription changes -- when the first subscriber appears or the
/// last subscriber disappears. The \a clear_values_on_subscribe when enabled will automatically
/// clear (set to null/undetermined) the group keys on first subscribe.
void context_provider_install_key (const char* key,
                                   int clear_values_on_subscribe,
                                   ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                   void* subscription_changed_cb_target)
{
    contextDebug() << F_C << key;

    if (! cService) {
        contextCritical() << "Can't install key:" << key << "because no service started.";
        return;
    }

    listeners->append(new PropertyListener(*cService, key,
                                           clear_values_on_subscribe,
                                           subscription_changed_cb, subscription_changed_cb_target));
    cService->restart();
}

/// Installs (adds) a \a key_group to be provided by the service. The \a key_group is a NULL-terminated
/// array containing the keys. The callback function \a subscription_changed_cb will be called with the
/// passed user data \a subscription_changed_cb_target when the status of the subscription changes --
/// when the first subscriber appears or the last subscriber disappears. The \a clear_values_on_subscribe
/// when enabled will automatically clear (set to null/undetermined) the group keys on first subscribe.
void context_provider_install_group (char* const * key_group,
                                     int clear_values_on_subscribe,
                                     ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                     void* subscription_changed_cb_target)
{
    contextDebug() << F_C;

    if (! cService) {
        contextCritical() << "Can't install key group because no service started.";
        return;
    }

    QStringList keys;
    int i = 0;
    while(key_group[i] != NULL) {
        QString key = QString(key_group[i]);

        keys << key;
        i++;
    }

    listeners->append(new GroupListener(*cService, keys,
                                        clear_values_on_subscribe,
                                        subscription_changed_cb, subscription_changed_cb_target));
    cService->restart();
}

/// Sets the \a key to a specified integer \a value.
void context_provider_set_integer (const char* key, int value)
{
    contextDebug() << F_C << key << value;
    if (cService)
        cService->setValue(key, value);
}

/// Sets the \a key to a specified double \a value.
void context_provider_set_double (const char* key, double value)
{
    contextDebug() << F_C << key << value;
    if (cService)
        cService->setValue(key, value);
}

/// Sets the \a key to a specified boolean \a value.
void context_provider_set_boolean (const char* key, int value)
{
    contextDebug() << F_C << key << value;
    if (cService)
        cService->setValue(key, (value != 0));
}

/// Sets the \a key to a specified string \a value.
void context_provider_set_string (const char* key, const char* value)
{
    contextDebug() << F_C << key << value;
    if (cService)
        cService->setValue(key, value);
}

/// Sets the \a key to NULL. In other words - unsets the key.
void context_provider_set_null (const char* key)
{
    contextDebug() << F_C << key;
    if (cService)
        cService->setValue(key, QVariant());
}

/// Sets the value of \a key to the specified \a map.  If \a free_map is TRUE,
/// frees the map, which becomes invalid afterwards.
///
/// \sa context_provider_map_new, context_provider_map_set_*
void context_provider_set_map (const char* key, void* map, int free_map)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    cService->setValue(key, QVariant(*qvm));
    if (free_map)
        delete qvm;
}

/// Creates an opaque map for use with the context_provider_map_set_* family
/// of functions.  Free it with context_provider_map_free().
void *context_provider_map_new ()
{
    return new QVariantMap();
}

/// Free the \a map created by context_provider_map_new().
void context_provider_map_free (void* map)
{
    delete reinterpret_cast<QVariantMap *>(map);
}

/// Sets \a key to the integer \a value in \a map.
void context_provider_map_set_integer(void* map, const char* key, int value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    qvm->insert(key, QVariant(value));
}

/// Sets \a key to the double \a value in \a map.
void context_provider_map_set_double (void* map, const char* key, double value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    qvm->insert(key, QVariant(value));
}

/// Sets \a key to the boolean \a value in \a map.
void context_provider_map_set_boolean(void* map, const char* key, int value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    qvm->insert(key, QVariant(value != 0));
}

/// Sets \a key to the string \a value in \a map.
void context_provider_map_set_string (void* map, const char* key, const char* value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    qvm->insert(key, QVariant(value));
}

/// Sets \a key to the map \a value in \a map.  NOTE: \a value is freed, and
/// becomes invalid after this call.
void context_provider_map_set_map (void* map, const char* key, void* value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    QVariantMap *other = reinterpret_cast<QVariantMap *>(value);
    qvm->insert(key, QVariant(*other));
    delete other;
}

/// Sets \a key to the list \a value in \a map.  NOTE: \a value is freed, and
/// becomes invalid after this call.
void context_provider_map_set_list(void* map, const char* key, void* value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    QVariantList *list = reinterpret_cast<QVariantList *>(value);
    qvm->insert(key, QVariant(*list));
    delete list;
}

/// Sets the value of \a key to the specified \a list.  If \a free_list is
/// TRUE, the list is freed.
///
/// \sa context_provider_list_new, context_provider_list_add_*
void context_provider_set_list(const char* key, void* list, int free_list)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    cService->setValue(key, QVariant(*qvl));
    if (free_list)
        delete qvl;
}

/// Creates an opaque list for use with the context_provider_list_add_* family
/// of functions.  Free it with context_provider_list_free().
void *context_provider_list_new()
{
    return new QVariantList();
}

/// Frees the list created by context_provider_list_new().  Use
/// context_provider_list_free() to free it.
void context_provider_list_free(void* list)
{
    delete reinterpret_cast<QVariantList *>(list);
}

/// Appends the integer \a value to \a list.
void context_provider_list_add_integer(void* list, int value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    qvl->append(QVariant(value));
}

/// Appends the double \a value to \a list.
void context_provider_list_add_double(void* list, double value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    qvl->append(QVariant(value));
}

/// Appends the boolean \a value to \a list.
void context_provider_list_add_boolean(void* list, int value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    qvl->append(QVariant(value != 0));
}

/// Appends the string \a value to \a list.
void context_provider_list_add_string(void* list, const char* value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    qvl->append(QVariant(value));
}

/// Appends the specified map (\a value) to \a list.  NOTE: \a value is freed
/// and becomes invalid after this call.
void context_provider_list_add_map(void* list, void* value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(value);
    qvl->append(QVariant(*qvm));
    delete qvm;
}

/// Appends the specified list \a value to \a list.  NOTE: \a value is freed,
/// and becomes invalid after this call.
void context_provider_list_add_list(void* list, void* value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    QVariantList *vl = reinterpret_cast<QVariantList *>(value);
    qvl->append(QVariant(*vl));
    delete vl;
}