[xpcom] Add a helper interface to carry type information for conversion methods
[browser-dbus-bridge.git] / xpcom-dbusservice / DBusService.cpp
1 /**
2  * Browser D-Bus Bridge, XPCOM version
3  *
4  * Copyright © 2008 Movial Creative Technologies Inc
5  *  Contact: Movial Creative Technologies Inc, <info@movial.com>
6  *  Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
7  *           Kalle Vahlman, <kalle.vahlman@movial.com>
8  *
9  * The contents of this file are subject to the Mozilla Public License
10  * Version 1.1 (the "License"); you may not use this file except in
11  * compliance with the License. You may obtain a copy of the License at
12  * http://www.mozilla.org/MPL/
13  *
14  * Software distributed under the License is distributed on an "AS IS"
15  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
16  * License for the specific language governing rights and limitations
17  * under the License.
18  *
19  * The Original Code is the Browser D-Bus Bridge, XPCOM version.
20  *
21  * The Initial Developer of the Original Code is Movial Creative Technologies
22  * Inc. Portions created by Initial Developer are Copyright (C) 2008
23  * Movial Creative Technologies Inc. All Rights Reserved.
24  *
25  */
26
27 #include <stdio.h>
28 #include <glib.h>
29 #include <dbus/dbus-glib-lowlevel.h>
30 #include <dbus/dbus-glib.h>
31
32
33 #include "nsIGenericFactory.h"
34 #include "nsIInterfaceRequestorUtils.h"
35 #include "nsComponentManagerUtils.h"
36 #include "nsServiceManagerUtils.h"
37
38 #include "nsEmbedString.h"
39 #include "nsIMutableArray.h"
40 #include "nsArrayUtils.h"
41 #include "nsIXPConnect.h"
42
43 #include "IDBusService.h"
44
45 #include "DBusService.h"
46 #include "DBusMethod.h"
47 #include "DBusSignal.h"
48 #include "DBusDataCarrier.h"
49 #include "DBusMarshaling.h"
50
51 #include "bdb-debug.h"
52
53 //
54 // DBusService implementation
55 //
56
57 static
58 DBusHandlerResult _signal_filter(DBusConnection *connection,
59                                  DBusMessage *message,
60                                  void *user_data);
61
62 static DBusService *gDBusService = nsnull;
63
64 NS_IMPL_ISUPPORTS1(DBusService, IDBusService);
65
66 DBusService::DBusService() :
67     mSystemBus(nsnull),
68     mSessionBus(nsnull),
69     mSystemBusHasFilter(PR_FALSE),
70     mSessionBusHasFilter(PR_FALSE),
71     mInsideEmit(PR_FALSE)
72 {
73     BDBLOG(("DBusService::DBusService()\n"));
74     mSystemBusSignalObservers.Init();
75     mSessionBusSignalObservers.Init();
76 }
77
78 DBusService::~DBusService()
79 {
80     BDBLOG(("DBusService::~DBusService()\n"));
81     /* FIXME - check if connections need to be released */
82 }
83
84 NS_IMETHODIMP
85 DBusService::GetSignal(PRUint32 aBusType,
86                        const nsACString& aInterfaceName,
87                        const nsACString& aSignalName,
88                        const nsACString& aSender,
89                        const nsACString& aObjectPath,
90                        IDBusSignal **_retval)
91 {
92     nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr> > *signalObservers = nsnull;
93     *_retval = nsnull;
94
95     GetConnection(aBusType);
96
97     if (aBusType == SYSTEM)
98     {
99         if (!mSystemBusHasFilter)
100         {
101             signalObservers = &mSystemBusSignalObservers;
102             mSystemBusHasFilter = PR_TRUE;
103         }
104     }
105     else if (aBusType == SESSION)
106     {
107         if (!mSessionBusHasFilter)
108         {
109             signalObservers = &mSessionBusSignalObservers;
110             mSessionBusHasFilter = PR_TRUE;
111         }
112     }
113     else
114     {
115         BDBLOG(("DBusService::GetSignal(): unknown bus type %d\n", aBusType));
116         return NS_ERROR_ILLEGAL_VALUE;
117     }
118
119     /* add filter only once for each connection */
120     if (signalObservers)
121         dbus_connection_add_filter(GetConnection(aBusType),
122                                    _signal_filter,
123                                    signalObservers,
124                                    nsnull);
125
126     IDBusSignal *signal = new DBusSignal(this,
127                                          aBusType,
128                                          aInterfaceName,
129                                          aSignalName,
130                                          aSender,
131                                          aObjectPath,
132                                          GetCurrentJSContext());
133
134     NS_ENSURE_TRUE(signal, NS_ERROR_OUT_OF_MEMORY);
135
136     NS_ADDREF(*_retval = signal);
137
138     return NS_OK;
139 }
140
141 NS_IMETHODIMP
142 DBusService::GetMethod(PRUint32 aBusType,
143                        const nsACString& aDestination,
144                        const nsACString& aObjectPath,
145                        const nsACString& aMethodName,
146                        const nsACString& aInterfaceName,
147                        const nsACString& aSignature,
148                        IDBusMethod **_retval)
149 {
150     *_retval = nsnull;
151
152     if (!GetConnection(aBusType))
153     {
154         BDBLOG(("DBusService::GetMethod()): invalid bus type %d\n",
155                aBusType));
156         return NS_ERROR_ILLEGAL_VALUE;
157     }
158
159     if (!dbus_signature_validate(PromiseFlatCString(aSignature).get(), nsnull))
160     {
161         BDBLOG(("DBusService::GetMethod()): invalid method signature '%s'\n",
162                PromiseFlatCString(aSignature).get()));
163         return NS_ERROR_ILLEGAL_VALUE;
164     }
165
166     IDBusMethod *method = new DBusMethod(this,
167                                          aBusType,
168                                          aDestination,
169                                          aObjectPath,
170                                          aMethodName,
171                                          aInterfaceName,
172                                          aSignature,
173                                          GetCurrentJSContext());
174
175     NS_ENSURE_TRUE(method, NS_ERROR_OUT_OF_MEMORY);
176
177     NS_ADDREF(*_retval = method);
178
179     return NS_OK;
180 }
181
182 NS_IMETHODIMP DBusService::EmitSignal(PRUint32 busType,
183                                       const nsACString & objectPath,
184                                       const nsACString & interfaceName,
185                                       const nsACString & signalName,
186                                       const nsACString & aSignature,
187                                       nsIVariant **args,
188                                       PRUint32 count,
189                                       PRBool *_retval)
190 {
191     DBusMessage *msg;
192     DBusMessageIter msg_iter;
193     DBusConnection *conn;
194     nsCAutoString signature;
195
196     conn = GetConnection(busType);
197
198     if (!conn)
199     {
200         BDBLOG(("DBusService::EmitSignal()): invalid bus type %d\n",
201                busType));
202         return NS_ERROR_ILLEGAL_VALUE;
203     }
204
205     if (objectPath.IsEmpty()
206      || interfaceName.IsEmpty()
207      || signalName.IsEmpty())
208     {
209         BDBLOG(("DBusService::EmitSignal()): invalid signal arguments\n"));
210         return NS_ERROR_ILLEGAL_VALUE;
211     }
212
213     msg = dbus_message_new_signal(PromiseFlatCString(objectPath).get(),
214                                   PromiseFlatCString(interfaceName).get(),
215                                   PromiseFlatCString(signalName).get());
216     dbus_message_iter_init_append(msg, &msg_iter);
217
218     if (count > 0)
219     {
220         JSContext *cx = GetCurrentJSContext();
221
222         if (aSignature.Equals(""))
223         {
224             for (PRUint32 i = 0; i < count; i++)
225             {
226                 // no method signature specified, guess argument types
227                 nsCOMPtr<nsIVariant> data = args[i];
228                 nsCAutoString tmpsig;
229
230                 getSignatureFromVariant(cx, data, tmpsig);
231                 BDBLOG(("  aArgs[%02d]       : signature \"%s\"\n",
232                        i,
233                        PromiseFlatCString(tmpsig).get()));
234                 signature.Append(tmpsig);
235
236             }
237         } else {
238             signature.Assign(aSignature);
239         }
240
241         if (dbus_signature_validate(PromiseFlatCString(signature).get(), nsnull))
242         {
243             DBusSignatureIter sig_iter;
244             int current_type;
245             int i = 0;
246
247             BDBLOG(("  signature \"%s\"\n", PromiseFlatCString(signature).get()));
248
249             dbus_signature_iter_init(&sig_iter, PromiseFlatCString(signature).get());
250             while ((current_type = dbus_signature_iter_get_current_type(&sig_iter)) != DBUS_TYPE_INVALID)
251             {
252                 char *element_signature = dbus_signature_iter_get_signature(&sig_iter);
253                 BDBLOG(("  element \"%s\" from signature\n", element_signature));
254                 BDBLOG(("  type %c from signature\n", current_type));
255
256                 addVariantToIter(cx, args[i], &msg_iter, &sig_iter);
257
258                 i++;
259                 dbus_free(element_signature);
260                 dbus_signature_iter_next(&sig_iter);
261             }
262         }
263         else
264         {
265             BDBLOG(("  invalid signature \"%s\"\n", PromiseFlatCString(signature).get()));
266             dbus_message_unref(msg);
267             return NS_ERROR_ILLEGAL_VALUE;
268         }
269     }
270
271     if (dbus_connection_send(conn, msg, NULL))
272     {
273         dbus_message_unref(msg);
274         return NS_OK;
275     }
276         
277     dbus_message_unref(msg);
278     return NS_ERROR_UNEXPECTED;
279 }
280  
281
282 DBusPendingCall *DBusService::SendWithReply(PRUint32 aConnType,
283                                             DBusMessage *aMessage,
284                                             PRUint32 aTimeout)
285 {
286     DBusPendingCall *retval = nsnull;
287     DBusConnection *conn = GetConnection(aConnType);
288
289     if (!conn)
290         return nsnull;
291
292     if (!dbus_connection_send_with_reply(conn,
293                                          aMessage,
294                                          &retval,
295                                          aTimeout))
296         return nsnull;
297
298     return retval;
299 }
300
301 DBusMessage *DBusService::SendWithReplyAndBlock(PRUint32 aConnType,
302                                                 DBusMessage *aMessage,
303                                                 PRUint32 aTimeout,
304                                                 DBusError *aError)
305 {
306     DBusConnection *conn = GetConnection(aConnType);
307
308     if (!conn)
309         return nsnull;
310
311     return dbus_connection_send_with_reply_and_block(conn,
312                                                      aMessage,
313                                                      aTimeout,
314                                                      aError);
315 }
316
317 static
318 DBusHandlerResult _signal_filter(DBusConnection *connection,
319                                  DBusMessage *message,
320                                  void *user_data)
321 {
322     if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
323     {
324         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
325     }
326
327     nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr> > *observerHash =
328         (nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr> > *) user_data;
329
330     BDBLOG(("_signal_filter: %s.%s\n",
331            dbus_message_get_interface(message),
332            dbus_message_get_member(message)));
333
334     nsCAutoString observerKey;
335
336     observerKey.Assign(dbus_message_get_interface(message));
337     observerKey.Append(NS_LITERAL_CSTRING("."));
338     observerKey.Append(dbus_message_get_member(message));
339
340     BDBLOG(("  observerKey: '%s'\n",
341            PromiseFlatCString(observerKey).get()));
342
343     nsTArray<nsWeakPtr> *observerList = nsnull;
344
345     observerHash->Get(observerKey, &observerList);
346     if (observerList)
347     {
348         BDBLOG(("  got observerList\n"));
349         DBusService *service = DBusService::GetSingleton();
350         
351         for (PRUint32 i = 0; i < observerList->Length(); ++i) {
352             nsCAutoString t;
353             nsCOMPtr<IDBusSignal> signal = do_QueryReferent((*observerList)[i]);
354             signal->GetInterfaceName(t);
355             BDBLOG(("    interface : %s\n", PromiseFlatCString(t).get()));
356             signal->GetSignalName(t);
357             BDBLOG(("    signal    : %s\n", PromiseFlatCString(t).get()));
358             signal->GetSender(t);
359             BDBLOG(("    sender    : %s\n", PromiseFlatCString(t).get()));
360             if (!t.IsEmpty() && !t.Equals(dbus_message_get_sender(message)))
361             {
362                 BDBLOG(("    sender does not match\n"));
363                 break;
364             }
365             signal->GetObjectPath(t);
366             BDBLOG(("    object    : %s\n", PromiseFlatCString(t).get()));
367             if (!t.IsEmpty() && !t.Equals(dbus_message_get_path(message)))
368             {
369                 BDBLOG(("    objectPath does not match\n"));
370                 break;
371             }
372
373             /* do callback */
374
375             DBusMessageIter iter;
376             nsCOMPtr<nsIMutableArray> args_array;
377
378             dbus_message_iter_init(message, &iter);
379             JSContext *cx;
380             signal->GetJSContext(&cx);
381             args_array = getArrayFromIter(cx, &iter);
382
383             PRUint32 arg_items;
384             args_array->GetLength(&arg_items);
385             BDBLOG(("  arg_items: %d items\n", arg_items));
386
387             /* arguments are packed as an array into an nsIVariant */
388             nsIVariant **callback_args = new nsIVariant*[arg_items];
389             nsCOMPtr<nsIWritableVariant> args = do_CreateInstance("@mozilla.org/variant;1");
390             for (PRUint32 i = 0; i < arg_items; i++)
391             {
392                 nsCOMPtr<nsIVariant> arg = do_QueryElementAt(args_array, i);
393                 callback_args[i] = arg;
394                 NS_ADDREF(arg);
395             }
396             args->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,
397                              &NS_GET_IID(nsIVariant),
398                              arg_items,
399                              callback_args);
400             for (PRUint32 i = 0; i < arg_items; i++)
401                 NS_RELEASE(callback_args[i]);
402             delete[] callback_args;
403
404             nsCOMPtr<IDBusSignalObserver> callback;
405             signal->GetOnEmit(getter_AddRefs(callback));
406
407             service->SetInsideEmit(TRUE);
408             callback->OnSignal(args);
409             service->SetInsideEmit(FALSE);
410
411         }
412         
413         /* Check if we have queued observer changes */
414         service->CheckSignalObserverQueue();
415         
416         return DBUS_HANDLER_RESULT_HANDLED;
417     }
418     else
419     {
420         BDBLOG(("  no observer found\n"));
421         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
422     }
423 }
424
425 static
426 void BuildRule(IDBusSignal *aSignal, nsACString& aRetval)
427 {
428     nsCAutoString tmp;
429
430     aRetval.Assign(NS_LITERAL_CSTRING("type='signal',interface='"));
431     aSignal->GetInterfaceName(tmp);
432     aRetval.Append(tmp);
433     aRetval.Append(NS_LITERAL_CSTRING("',member='"));
434     aSignal->GetSignalName(tmp);
435     aRetval.Append(tmp);
436     aRetval.Append(NS_LITERAL_CSTRING("'"));
437 }
438
439 void DBusService::CheckSignalObserverQueue()
440 {
441     BDBLOG((__FUNCTION__));
442
443     PRUint32 i = mRemovedSignals.Length();
444     while (i-- > 0)
445     {
446         RemoveSignalObserver(mRemovedSignals[i]);
447         mRemovedSignals.RemoveElementAt(i);
448     }
449     i = mAddedSignals.Length();
450     while (i-- > 0)
451     {
452         AddSignalObserver(mAddedSignals[i]);
453         mAddedSignals.RemoveElementAt(i);
454     }
455 }
456
457 void DBusService::AddSignalObserver(IDBusSignal *aSignal)
458 {
459     nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr> > *signalObservers = nsnull;
460     nsCAutoString observerKey;
461     nsCAutoString tmp;
462
463     if (mInsideEmit)
464     {
465         mAddedSignals.AppendElement(aSignal);
466         return;
467     }
468
469     BDBLOG(("DBusService::AddSignalObserver()\n"));
470
471     aSignal->GetInterfaceName(tmp);
472     BDBLOG(("  aInterface : %s\n", PromiseFlatCString(tmp).get()));
473     observerKey.Assign(tmp);
474     observerKey.Append(".");
475
476     aSignal->GetSignalName(tmp);
477     BDBLOG(("  aSignal    : %s\n", PromiseFlatCString(tmp).get()));
478     observerKey.Append(tmp);
479
480     BDBLOG(("  observerKey: %s\n", PromiseFlatCString(observerKey).get()));
481
482     nsTArray<nsWeakPtr> *observerList = nsnull;
483
484     PRUint32 bus_type = 0;
485     aSignal->GetBusType(&bus_type);
486     if (bus_type == SYSTEM)
487         signalObservers = &mSystemBusSignalObservers;
488     else if (bus_type == SESSION)
489         signalObservers = &mSessionBusSignalObservers;
490     signalObservers->Get(observerKey, &observerList);
491     if (observerList)
492     {
493         /* append to list */
494         BDBLOG(("  got observerList\n"));
495         nsCOMPtr<nsISupportsWeakReference> weakRefable = do_QueryInterface(aSignal);
496         nsWeakPtr weakPtr = getter_AddRefs(NS_GetWeakReference(weakRefable));
497         observerList->AppendElement(weakPtr);
498     }
499     else
500     {
501         /* create a new list */
502         BDBLOG(("  no observerList found\n"));
503         observerList = new nsTArray<nsWeakPtr>;
504         nsCOMPtr<nsISupportsWeakReference> weakRefable = do_QueryInterface(aSignal);
505         nsWeakPtr weakPtr = getter_AddRefs(NS_GetWeakReference(weakRefable));
506         observerList->AppendElement(weakPtr);
507         signalObservers->Put(observerKey, observerList);
508         
509         /* add match rule for interface.signal */
510         PRUint32 busType;
511         nsCAutoString matchRule;
512
513         aSignal->GetBusType(&busType);
514         BuildRule(aSignal, matchRule);
515         BDBLOG(("  new match rule: %s\n", PromiseFlatCString(matchRule).get()));
516         dbus_bus_add_match(GetConnection(busType),
517                            PromiseFlatCString(matchRule).get(),
518                            nsnull);
519     }
520 }
521
522 void DBusService::RemoveSignalObserver(IDBusSignal *aSignal)
523 {
524     nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr> > *signalObservers = nsnull;
525     nsCAutoString observerKey;
526     nsCAutoString tmp;
527
528     if (mInsideEmit)
529     {
530         mRemovedSignals.AppendElement(aSignal);
531         return;
532     }
533
534     BDBLOG(("DBusService::RemoveSignalObserver()\n"));
535
536     aSignal->GetInterfaceName(tmp);
537     BDBLOG(("  aInterface : %s\n", PromiseFlatCString(tmp).get()));
538     observerKey.Assign(tmp);
539     observerKey.Append(".");
540
541     aSignal->GetSignalName(tmp);
542     BDBLOG(("  aSignal    : %s\n", PromiseFlatCString(tmp).get()));
543     observerKey.Append(tmp);
544
545     BDBLOG(("  observerKey: %s\n", PromiseFlatCString(observerKey).get()));
546
547     nsTArray<nsWeakPtr> *observerList = nsnull;
548
549     PRUint32 bus_type = 0;
550     aSignal->GetBusType(&bus_type);
551     if (bus_type == SYSTEM)
552         signalObservers = &mSystemBusSignalObservers;
553     else if (bus_type == SESSION)
554         signalObservers = &mSessionBusSignalObservers;
555     signalObservers->Get(observerKey, &observerList);
556     if (observerList)
557     {
558         BDBLOG(("  got observerList\n"));
559         nsCOMPtr<nsISupportsWeakReference> weakRefable = do_QueryInterface(aSignal);
560         nsWeakPtr weakPtr = getter_AddRefs(NS_GetWeakReference(weakRefable));
561         for (PRUint32 i = 0; i < observerList->Length(); ++i) {
562             nsCAutoString t;
563             nsCAutoString ob;
564             nsCOMPtr<IDBusSignal> signal = do_QueryReferent((*observerList)[i]);
565             signal->GetInterfaceName(t);
566             ob.Assign(t);
567             ob.Append(".");
568             signal->GetSignalName(t);
569             ob.Append(t);
570             BDBLOG(("    signal : %s\n", PromiseFlatCString(ob).get()));
571         }
572         BDBLOG(("  call observerList->RemoveElement\n"));
573         observerList->RemoveElement(weakPtr);
574         for (PRUint32 i = 0; i < observerList->Length(); ++i) {
575             nsCAutoString t;
576             nsCAutoString ob;
577             nsCOMPtr<IDBusSignal> signal = do_QueryReferent((*observerList)[i]);
578             signal->GetInterfaceName(t);
579             ob.Assign(t);
580             ob.Append(".");
581             signal->GetSignalName(t);
582             ob.Append(t);
583             BDBLOG(("    signal : %s\n", PromiseFlatCString(ob).get()));
584         }
585
586         // if list is empty, remove match rule
587         if (observerList->Length() == 0)
588         {
589             PRUint32 busType;
590             nsCAutoString matchRule;
591
592             aSignal->GetBusType(&busType);
593             BuildRule(aSignal, matchRule);
594             BDBLOG(("  remove match rule: %s\n", PromiseFlatCString(matchRule).get()));
595             dbus_bus_remove_match(GetConnection(busType),
596                                   PromiseFlatCString(matchRule).get(),
597                                   nsnull);
598             signalObservers->Remove(observerKey); 
599         }
600         BDBLOG(("  done\n"));
601     }
602     else
603     {
604         BDBLOG(("  ERROR: no observerList found!\n"));
605     }
606 }
607
608 JSContext *DBusService::GetCurrentJSContext()
609 {
610     // try to get a JS context (code borrowed from xpcsample1.cpp)
611
612     // get the xpconnect service
613     nsresult rv;
614     nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
615     if(NS_FAILED(rv))
616         return nsnull;
617     BDBLOG(("    got nsIXPConnect\n"));
618
619     // get the xpconnect native call context
620     nsAXPCNativeCallContext *callContext = nsnull;
621     xpc->GetCurrentNativeCallContext(&callContext);
622     if(!callContext)
623     {
624     BDBLOG(("    callContext :(\n"));
625         return nsnull;
626     }
627     // Get JSContext of current call
628     JSContext* cx;
629     rv = callContext->GetJSContext(&cx);
630     if(NS_FAILED(rv) || !cx)
631         return nsnull;
632     BDBLOG(("    got JSContext\n"));
633
634     return cx;
635 }
636
637 DBusConnection *DBusService::GetConnection(PRUint32 aConnType)
638 {
639     BDBLOG(("DBusService::GetConnection(%d)\n", aConnType));
640
641     if (aConnType == SYSTEM)
642     {
643         if (mSystemBus == nsnull)
644         {
645             mSystemBus = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
646             if (!mSystemBus)
647                 return nsnull;
648             dbus_connection_set_exit_on_disconnect(mSystemBus, PR_FALSE);
649             dbus_connection_setup_with_g_main(mSystemBus, NULL);
650         }
651         return mSystemBus;
652     }
653     else if (aConnType == SESSION)
654     {
655         if (mSessionBus == nsnull)
656         {
657             mSessionBus = dbus_bus_get(DBUS_BUS_SESSION, NULL);
658             if (!mSessionBus)
659                 return nsnull;
660             dbus_connection_set_exit_on_disconnect(mSessionBus, PR_FALSE);
661             dbus_connection_setup_with_g_main(mSessionBus, NULL);
662         }
663         return mSessionBus;
664     }
665     return nsnull;
666 }
667
668 DBusService *
669 DBusService::GetSingleton()
670 {
671     BDBLOG(("DBusService::GetSingleton() called: "));
672
673     if (!gDBusService)
674     {
675         BDBLOG(("creating new DBusService\n"));
676         gDBusService = new DBusService();
677     }
678
679     if (gDBusService)
680     {
681         BDBLOG(("adding reference to existing DBusService\n"));
682         NS_ADDREF(gDBusService);
683     }
684
685     return gDBusService;
686 }
687
688
689
690 //
691 // Module implementation
692 //
693
694 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DBusService, DBusService::GetSingleton);
695 NS_GENERIC_FACTORY_CONSTRUCTOR(DBusDataCarrier);
696
697 static const nsModuleComponentInfo components[] =
698 {
699     {
700         "DBus service",
701         DBUSSERVICE_CID,
702         "@movial.fi/dbus/service;1",
703         DBusServiceConstructor
704     },
705     {
706         "DBus method",
707         DBUSMETHOD_CID,
708         "@movial.fi/dbus/method;1",
709         nsnull
710     },
711     {
712         "DBus signal",
713         DBUSSIGNAL_CID,
714         "@movial.fi/dbus/signal;1",
715         nsnull
716     },
717     {
718         "DBus data carrier",
719         DBUSDATACARRIER_CID,
720         "@movial.fi/dbus/datacarrier;1",
721         DBusDataCarrierConstructor
722     }
723 };
724
725 NS_IMPL_NSGETMODULE(nsDBusServiceModule, components);
726
727 /* vim: set cindent ts=4 et sw=4: */