1 /*******************************************************************************
2 *                         Goggles Music Manager                                *
3 ********************************************************************************
4 *           Copyright (C) 2007-2021 by Sander Jansen. All Rights Reserved      *
5 *                               ---                                            *
6 * This program is free software: you can redistribute it and/or modify         *
7 * it under the terms of the GNU General Public License as published by         *
8 * the Free Software Foundation, either version 3 of the License, or            *
9 * (at your option) any later version.                                          *
10 *                                                                              *
11 * This program is distributed in the hope that it will be useful,              *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of               *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                *
14 * GNU General Public License for more details.                                 *
15 *                                                                              *
16 * You should have received a copy of the GNU General Public License            *
17 * along with this program.  If not, see http://www.gnu.org/licenses.           *
18 ********************************************************************************/
19 #include "gmdefs.h"
20 #include "GMDBus.h"
21 #include "FXThread.h"
22 
23 #ifndef DBUS_MAJOR_VERSION
24 #define DBUS_MAJOR_VERSION 1
25 #endif
26 
27 #ifndef DBUS_MINOR_VERSION
28 #define DBUS_MINOR_VERSION 0
29 #endif
30 
31 #ifndef DBUS_MICRO_VERSION
32 #define DBUS_MICRO_VERSION 0
33 #endif
34 
35 #define DBUSVERSION ((DBUS_MICRO_VERSION) + (DBUS_MINOR_VERSION*1000) + (DBUS_MAJOR_VERSION*100000))
36 #define MKDBUSVERSION(major,minor,release) ((release)+(minor*1000)+(major*100000))
37 
38 
39 /*******************************************************************************************************/
40 /* GLOBAL INIT                                                                                         */
41 /*******************************************************************************************************/
42 
43 class GMDBusTimeout;
44 
45 class GMDBusGlobal {
46 private:
47   FXMutex mutex;
48   FXHash  tm;
49   FXHash  connections;
50 public:
GMDBusGlobal()51   GMDBusGlobal() {
52     dbus_threads_init_default();
53     }
54 
find(DBusConnection * dc)55   GMDBus * find(DBusConnection* dc) {
56     FXScopedMutex lock(mutex);
57     return static_cast<GMDBus*>(connections.at(dc));
58     }
59 
setuphooks()60   void setuphooks() {
61     for (FXint i=0;i<connections.no();i++) {
62       if (!connections.empty(i)) {
63         static_cast<GMDBus*>(connections.data(i))->setup_event_loop();
64         }
65       }
66     }
67 
insert(DBusConnection * dc,GMDBus * fxdc)68   void insert(DBusConnection * dc,GMDBus * fxdc) {
69     FXScopedMutex lock(mutex);
70     connections.insert(dc,fxdc);
71     }
72 
remove(DBusConnection * dc)73   void remove(DBusConnection * dc) {
74     FXScopedMutex lock(mutex);
75     connections.remove(dc);
76     }
77 
find(DBusTimeout * t)78   GMDBusTimeout * find(DBusTimeout*t) {
79     return static_cast<GMDBusTimeout*>(tm.at(t));
80     }
81 
insert(DBusTimeout * t,GMDBusTimeout * f)82   void insert(DBusTimeout*t,GMDBusTimeout*f) {
83     tm.insert(t,f);
84     }
85 
remove(DBusTimeout * t)86   void remove(DBusTimeout*t) {
87     tm.remove(t);
88     }
89   };
90 
91 static GMDBusGlobal fxdbus;
92 
93 class GMDBusTimeout : public FXObject {
94 FXDECLARE(GMDBusTimeout);
95 protected:
96   DBusTimeout* timeout = nullptr;
97   FXuchar      flags = 0;
98 protected:
GMDBusTimeout()99   GMDBusTimeout(){}
100 private:
101   GMDBusTimeout(const GMDBusTimeout*);
102   GMDBusTimeout& operator=(const GMDBusTimeout&);
103 protected:
104   enum {
105     FLAG_CALLBACK  = 0x1,
106     FLAG_REMOVED   = 0x2
107     };
108 public:
109   enum {
110     ID_TIMEOUT = 1
111     };
112 public:
113   long onTimeout(FXObject*,FXSelector,void*);
114 public:
115   GMDBusTimeout(DBusTimeout *t);
116   void add();
117   void remove();
118   ~GMDBusTimeout();
119   };
120 
121 FXDEFMAP(GMDBusTimeout) GMDBusTimeoutMap[]={
122   FXMAPFUNC(SEL_TIMEOUT,GMDBusTimeout::ID_TIMEOUT,GMDBusTimeout::onTimeout),
123   };
124 FXIMPLEMENT(GMDBusTimeout,FXObject,GMDBusTimeoutMap,ARRAYNUMBER(GMDBusTimeoutMap));
125 
126 
127 
GMDBusTimeout(DBusTimeout * t)128 GMDBusTimeout::GMDBusTimeout(DBusTimeout *t) : timeout(t){
129   fxdbus.insert(timeout,this);
130   }
131 
~GMDBusTimeout()132 GMDBusTimeout::~GMDBusTimeout() {
133   fxdbus.remove(timeout);
134   }
135 
add()136 void GMDBusTimeout::add() {
137   flags&=~FLAG_REMOVED;
138   FXApp::instance()->addTimeout(this,GMDBusTimeout::ID_TIMEOUT,TIME_MSEC(dbus_timeout_get_interval(timeout)));
139   }
140 
remove()141 void GMDBusTimeout::remove() {
142   if (flags&FLAG_CALLBACK) {
143     flags|=FLAG_REMOVED;
144     return;
145     }
146   FXApp::instance()->removeTimeout(this,GMDBusTimeout::ID_TIMEOUT);
147   delete this;
148   }
149 
150 
fxdbus_addtimeout(DBusTimeout * timeout,void *)151 static dbus_bool_t fxdbus_addtimeout(DBusTimeout *timeout,void *) {
152   //fxmessage("fxdbus_addtimeout %p\n",timeout);
153   GMDBusTimeout * tm = fxdbus.find(timeout);
154   if (tm==nullptr)
155     tm = new GMDBusTimeout(timeout);
156 
157   tm->add();
158   return true;
159   }
160 
161 
fxdbus_removetimeout(DBusTimeout * timeout,void *)162 static void fxdbus_removetimeout(DBusTimeout *timeout,void *) {
163   //fxmessage("fxdbus_removetimeout %p\n",timeout);
164   GMDBusTimeout * tm = fxdbus.find(timeout);
165   if (tm) tm->remove();
166   }
167 
fxdbus_toggletimeout(DBusTimeout * timeout,void * data)168 static void fxdbus_toggletimeout(DBusTimeout *timeout,void*data) {
169   //fxmessage("fxdbus_toggletimeout %p\n",timeout);
170   if (dbus_timeout_get_enabled(timeout) && dbus_timeout_get_interval(timeout)>0)
171     fxdbus_addtimeout(timeout,data);
172   else
173     fxdbus_removetimeout(timeout,data);
174   }
175 
onTimeout(FXObject *,FXSelector,void *)176 long GMDBusTimeout::onTimeout(FXObject*,FXSelector,void*){
177   //fxmessage("onTimeout() %p {\n",timeout);
178   flags|=FLAG_CALLBACK;
179   dbus_timeout_handle(timeout);
180   if (flags&FLAG_REMOVED) {
181     delete this;
182     //fxmessage("}\n");
183     return 1;
184     }
185   else {
186     if (dbus_timeout_get_enabled(timeout) && dbus_timeout_get_interval(timeout)>0 && !FXApp::instance()->hasTimeout(this,ID_TIMEOUT)){
187       FXApp::instance()->addTimeout(this,GMDBusTimeout::ID_TIMEOUT,TIME_MSEC(dbus_timeout_get_interval(timeout)));
188       }
189     }
190   flags&=~FLAG_CALLBACK;
191   //fxmessage("}\n");
192   return 1;
193   }
194 
195 
196 
197 
198 
199 
200 
201 
202 
203 
204 
205 /*******************************************************************************************************/
206 /* Call Backs                                                                                          */
207 /*******************************************************************************************************/
208 
fxdbus_addwatch(DBusWatch * watch,void * data)209 static dbus_bool_t fxdbus_addwatch(DBusWatch *watch,void * data) {
210   FXTRACE((35,"fxdbus_addwatch()\n"));
211   GMDBus * dc = static_cast<GMDBus*>(data);
212   FXuint mode  = INPUT_EXCEPT;
213   FXuint flags = dbus_watch_get_flags(watch);
214 
215   /// If it's not enabled, we're not going to add it
216   if (!dbus_watch_get_enabled(watch)) return true;
217 
218   if (flags&DBUS_WATCH_READABLE)
219       mode|=INPUT_READ;
220   if (flags&DBUS_WATCH_WRITABLE)
221       mode|=INPUT_WRITE;
222 
223 #if DBUSVERSION == MKDBUSVERSION(1,1,20) || DBUSVERSION >= MKDBUSVERSION(1,2,0)
224   return FXApp::instance()->addInput(dc,GMDBus::ID_HANDLE,(FXInputHandle)dbus_watch_get_unix_fd(watch),mode,watch);
225 #else
226   return FXApp::instance()->addInput(dc,GMDBus::ID_HANDLE,(FXInputHandle)dbus_watch_get_fd(watch),mode,watch);
227 #endif
228 
229   }
230 
fxdbus_removewatch(DBusWatch * watch,void *)231 static void fxdbus_removewatch(DBusWatch *watch,void *) {
232   FXTRACE((35,"fxdbus_removewatch()\n"));
233 /*
234   FXuint mode=INPUT_EXCEPT;
235   unsigned int flags = dbus_watch_get_flags(watch);
236   if (flags&DBUS_WATCH_READABLE)
237       mode|=INPUT_READ;
238   if (flags&DBUS_WATCH_WRITABLE) {
239       mode|=INPUT_WRITE;
240       return;
241       }
242 */
243   FXuint mode=INPUT_READ|INPUT_WRITE|INPUT_EXCEPT;
244 #if DBUSVERSION == MKDBUSVERSION(1,1,20) || DBUSVERSION >= MKDBUSVERSION(1,2,0)
245   FXApp::instance()->removeInput(dbus_watch_get_unix_fd(watch),mode);
246 #else
247   FXApp::instance()->removeInput(dbus_watch_get_fd(watch),mode);
248 #endif
249 
250   }
251 
fxdbus_togglewatch(DBusWatch * watch,void * data)252 static void fxdbus_togglewatch(DBusWatch *watch,void* data) {
253   FXTRACE((35,"fxdbus_togglewatch()\n"));
254   if (dbus_watch_get_enabled(watch))
255     fxdbus_addwatch(watch,data);
256   else
257     fxdbus_removewatch(watch,data);
258   }
259 
fxdbus_wakeup(void *)260 static void fxdbus_wakeup(void *){
261   /// To Do
262   }
263 
264 
265 
266 /*******************************************************************************************************/
267 /* PUBLIC API                                                                                          */
268 /*******************************************************************************************************/
269 
270 FXDEFMAP(GMDBus) GMDBusMap[]={
271   FXMAPFUNC(SEL_IO_READ,GMDBus::ID_HANDLE,GMDBus::onHandleRead),
272   FXMAPFUNC(SEL_IO_WRITE,GMDBus::ID_HANDLE,GMDBus::onHandleWrite),
273   FXMAPFUNC(SEL_IO_EXCEPT,GMDBus::ID_HANDLE,GMDBus::onHandleExcept),
274   FXMAPFUNC(SEL_CHORE,GMDBus::ID_DISPATCH,GMDBus::onDispatch)
275   };
276 
277 FXIMPLEMENT(GMDBus,FXObject,GMDBusMap,ARRAYNUMBER(GMDBusMap));
278 
GMDBus()279 GMDBus::GMDBus() {
280   }
281 
~GMDBus()282 GMDBus::~GMDBus(){
283   if (dc) {
284     fxdbus.remove(dc);
285     dbus_connection_unref(dc);
286     dc=nullptr;
287     FXApp::instance()->removeChore(this,ID_DISPATCH);
288     }
289   }
290 
291 
find(DBusConnection * dc)292 GMDBus * GMDBus::find(DBusConnection * dc) {
293   return fxdbus.find(dc);
294   }
295 
initEventLoop()296 void GMDBus::initEventLoop() {
297   fxdbus.setuphooks();
298   }
299 
300 
open(DBusBusType bustype)301 FXbool GMDBus::open(DBusBusType bustype/*=DBUS_BUS_SESSION*/){
302   FXASSERT(dc==nullptr);
303   dc = dbus_bus_get(bustype,nullptr);
304   if (dc==nullptr) return false;
305   if (fxdbus.find(dc)) {
306     dbus_connection_unref(dc);
307     dc=nullptr;
308     return false;
309     }
310   fxdbus.insert(dc,this);
311   dbus_connection_set_exit_on_disconnect(dc,false);
312   return true;
313   }
314 
315 
connected() const316 FXbool GMDBus::connected() const {
317   if (dc)
318     return dbus_connection_get_is_connected(dc);
319   else
320     return false;
321   }
322 
authenticated() const323 FXbool GMDBus::authenticated() const {
324   if (dc)
325     return dbus_connection_get_is_authenticated(dc);
326   else
327     return false;
328   }
329 
flush()330 void GMDBus::flush() {
331   if (dc) dbus_connection_flush(dc);
332   }
333 
334 
dbusversion()335 FXString GMDBus::dbusversion() {
336 #if (DBUSVERSION == MKDBUSVERSION(1,1,20)) || DBUSVERSION >= MKDBUSVERSION(1,2,0)
337   int major,minor,micro;
338   dbus_get_version(&major,&minor,&micro);
339   return FXString::value("%d.%d.%d",major,minor,micro);
340 #else
341   return FXString("1.0.x");
342 #endif
343   }
344 
345 struct CallTarget{
346   FXObject * target;
347   FXSelector message;
348   };
349 
fxdbus_pendingcallfree(void * memory)350 static void fxdbus_pendingcallfree(void *memory){
351   //fxmessage("fxdbuspendingcallfree\n");
352   if (memory){
353     CallTarget * call = static_cast<CallTarget*>(memory);
354     delete call;
355     }
356   }
357 
fxdbus_pendingcallnotify(DBusPendingCall * pending,void * data)358 static void fxdbus_pendingcallnotify(DBusPendingCall*pending,void*data){
359   DBusMessage * msg = dbus_pending_call_steal_reply(pending);
360   if (msg) {
361     CallTarget * call = static_cast<CallTarget*>(data);
362     if (call && call->target && call->message) {
363       call->target->handle(nullptr,FXSEL(SEL_COMMAND,call->message),msg);
364       }
365     dbus_message_unref(msg);
366     }
367   }
368 
369 
sendWithReply(DBusMessage * msg,FXint timeout,FXObject * tgt,FXSelector sel)370 FXbool GMDBus::sendWithReply(DBusMessage * msg,FXint timeout,FXObject*tgt,FXSelector sel){
371   FXASSERT(msg);
372   DBusPendingCall * pending = nullptr;
373   if (dbus_connection_send_with_reply(dc,msg,&pending,timeout)) {
374     if (pending) {
375       CallTarget * call = new CallTarget;
376       call->target=tgt;
377       call->message=sel;
378       dbus_pending_call_set_notify(pending,fxdbus_pendingcallnotify,(void*)call,fxdbus_pendingcallfree);
379       dbus_pending_call_unref(pending);
380       }
381     dbus_message_unref(msg);
382     return true;
383     }
384   return false;
385   }
386 
387 
send(DBusMessage * msg)388 void GMDBus::send(DBusMessage * msg){
389   FXuint serial;
390   dbus_connection_send(dc,msg,&serial);
391   dbus_message_unref(msg);
392   }
393 
send(DBusMessage * msg,FXuint & serial)394 void GMDBus::send(DBusMessage * msg,FXuint & serial){
395   dbus_connection_send(dc,msg,&serial);
396   dbus_message_unref(msg);
397   }
398 
399 
400 
401 /*******************************************************************************************************/
402 /* MESSAGE HANDLERS                                                                                    */
403 /*******************************************************************************************************/
404 
onHandleRead(FXObject *,FXSelector,void * ptr)405 long GMDBus::onHandleRead(FXObject*,FXSelector,void*ptr){
406   DBusWatch * watch = static_cast<DBusWatch*>(ptr);
407   dbus_watch_handle(watch,DBUS_WATCH_READABLE);
408   FXApp::instance()->addChore(this,ID_DISPATCH);
409   return 0;
410   }
411 
onHandleWrite(FXObject *,FXSelector,void * ptr)412 long GMDBus::onHandleWrite(FXObject*,FXSelector,void*ptr){
413   DBusWatch * watch = static_cast<DBusWatch*>(ptr);
414   dbus_watch_handle(watch,DBUS_WATCH_WRITABLE);
415   return 0;
416   }
417 
onHandleExcept(FXObject *,FXSelector,void * ptr)418 long GMDBus::onHandleExcept(FXObject*,FXSelector,void*ptr){
419   DBusWatch * watch = static_cast<DBusWatch*>(ptr);
420   dbus_watch_handle(watch,DBUS_WATCH_ERROR|DBUS_WATCH_HANGUP);
421   return 0;
422   }
423 
onDispatch(FXObject *,FXSelector,void *)424 long GMDBus::onDispatch(FXObject*,FXSelector,void*){
425   if (dbus_connection_dispatch((DBusConnection*)dc)==DBUS_DISPATCH_DATA_REMAINS) {
426     FXApp::instance()->addChore(this,ID_DISPATCH);
427     }
428   return 0;
429   }
430 
431 
432 /*******************************************************************************************************/
433 /* PROTECTED API                                                                                       */
434 /*******************************************************************************************************/
435 
setup_event_loop()436 void GMDBus::setup_event_loop() {
437   FXASSERT(dc);
438 
439   dbus_connection_set_watch_functions(dc,
440                                       fxdbus_addwatch,
441                                       fxdbus_removewatch,
442                                       fxdbus_togglewatch,
443                                       this,nullptr);
444 
445   dbus_connection_set_timeout_functions(dc,
446                                         fxdbus_addtimeout,
447                                         fxdbus_removetimeout,
448                                         fxdbus_toggletimeout,
449                                         this,nullptr);
450 
451   dbus_connection_set_wakeup_main_function(dc,fxdbus_wakeup,nullptr,nullptr);
452   }
453 
454 
455 
456 
457 
dbus_proxy_filter(DBusConnection *,DBusMessage * msg,void * ptr)458 static DBusHandlerResult dbus_proxy_filter(DBusConnection *,DBusMessage * msg,void * ptr){
459   GMDBusProxy * proxy = static_cast<GMDBusProxy*>(ptr);
460   FXASSERT(proxy);
461   FXuint type = dbus_message_get_type(msg);
462 
463   if (type==DBUS_MESSAGE_TYPE_METHOD_CALL) {
464     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
465     }
466   else if (type==DBUS_MESSAGE_TYPE_METHOD_RETURN || type==DBUS_MESSAGE_TYPE_ERROR) {
467     if (proxy->matchSerial(msg))
468       return DBUS_HANDLER_RESULT_HANDLED;
469     else
470       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
471     }
472   else { /* SIGNALS */
473     DEBUG_DBUS_MESSAGE(msg);
474 
475     if (dbus_message_has_path(msg,DBUS_PATH_DBUS)) {
476       if (dbus_message_is_signal(msg,DBUS_INTERFACE_DBUS,"NameOwnerChanged")) {
477         const FXchar * dbus_name=nullptr;
478         const FXchar * new_owner=nullptr;
479         const FXchar * old_owner=nullptr;
480         if (dbus_message_get_args(msg,nullptr,DBUS_TYPE_STRING,&dbus_name,DBUS_TYPE_STRING,&old_owner,DBUS_TYPE_STRING,&new_owner,DBUS_TYPE_INVALID)) {
481           if (compare(proxy->getName(),dbus_name)==0) {
482             if (new_owner==nullptr || compare(new_owner,"")==0) {
483               proxy->handle(proxy,FXSEL(SEL_DESTROY,0),nullptr);
484               }
485             else if (old_owner==nullptr || compare(old_owner,"")==0){
486               proxy->handle(proxy,FXSEL(SEL_CREATE,0),nullptr);
487               }
488             else {
489               proxy->handle(proxy,FXSEL(SEL_REPLACED,0),nullptr);
490               }
491             return DBUS_HANDLER_RESULT_HANDLED;
492             }
493           }
494         }
495       }
496     /// Make sure it is for us...
497     if (dbus_message_has_path(msg,proxy->getPath().text()) && dbus_message_has_interface(msg,proxy->getInterface().text())) {
498       return proxy->handle(proxy,FXSEL(SEL_SIGNAL,0),msg) ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
499       }
500     }
501   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
502   }
503 
504 
505 
506 struct GMDBusProxyReply {
507   FXObject * target;
508   FXSelector message;
GMDBusProxyReplyGMDBusProxyReply509   GMDBusProxyReply(FXObject * t,FXSelector m) : target(t), message(m) {}
510   };
511 
512 
513 FXDEFMAP(GMDBusProxy) GMDBusProxyMap[]={
514   FXMAPFUNC(SEL_CREATE,   0,GMDBusProxy::onCreate),
515   FXMAPFUNC(SEL_DESTROY,  0,GMDBusProxy::onDestroy),
516   FXMAPFUNC(SEL_REPLACED, 0,GMDBusProxy::onReplaced),
517   FXMAPFUNC(SEL_SIGNAL,   0,GMDBusProxy::onSignal),
518   FXMAPFUNC(SEL_COMMAND,  0,GMDBusProxy::onMethod),
519   };
520 
521 FXIMPLEMENT(GMDBusProxy,FXObject,GMDBusProxyMap,ARRAYNUMBER(GMDBusProxyMap));
522 
523 
GMDBusProxy()524 GMDBusProxy::GMDBusProxy() {
525   }
526 
~GMDBusProxy()527 GMDBusProxy::~GMDBusProxy()  {
528   FXString rule = "type='signal',sender='"+ name +"',path='" + path +"',interface='"+interface+"'";
529   dbus_bus_remove_match(bus->connection(),rule.text(),nullptr);
530   dbus_connection_remove_filter(bus->connection(),dbus_proxy_filter,this);
531 
532   /// remove any pending proxy replies;
533   for (FXint i=0;i<serial.no();i++) {
534     if (!serial.empty(i)) {
535       GMDBusProxyReply * reply = static_cast<GMDBusProxyReply*>(serial.data(i));
536       delete reply;
537       }
538     }
539   serial.clear();
540   }
541 
GMDBusProxy(GMDBus * c,const FXchar * n,const FXchar * p,const FXchar * i)542 GMDBusProxy::GMDBusProxy(GMDBus *c,const FXchar * n,const FXchar * p,const FXchar * i) : bus(c),name(n),path(p),interface(i),associated(true),target(nullptr) {
543   FXString rule = "type='signal',sender='"+ name +"',path='" + path +"',interface='"+interface+"'";
544   dbus_bus_add_match(bus->connection(),rule.text(),nullptr);
545   dbus_connection_add_filter(bus->connection(),dbus_proxy_filter,this,nullptr);
546   }
547 
548 
matchSerial(DBusMessage * msg)549 FXbool GMDBusProxy::matchSerial(DBusMessage * msg) {
550   void * ptr;
551   FXuint s=dbus_message_get_reply_serial(msg);
552   if (s && (ptr=serial.at((void*)(FXuval)s))!=nullptr) {
553     GMDBusProxyReply * reply = static_cast<GMDBusProxyReply*>(ptr);
554     if (reply->target) reply->target->handle(this,FXSEL(SEL_COMMAND,reply->message),msg);
555     serial.remove((void*)(FXuval)dbus_message_get_reply_serial(msg));
556     delete reply;
557     return true;
558     }
559   else {
560     return false;
561     }
562   }
563 
send(DBusMessage * msg,FXObject * obj,FXSelector m)564 void GMDBusProxy::send(DBusMessage*msg,FXObject * obj,FXSelector m) {
565   FXuint s;
566   dbus_connection_send(bus->connection(),msg,&s);
567   dbus_message_unref(msg);
568   serial.insert((void*)(FXuval)s,new GMDBusProxyReply(obj,m));
569   }
570 
571 
572 
method(const FXchar * methodcall)573 DBusMessage * GMDBusProxy::method(const FXchar * methodcall){
574   return dbus_message_new_method_call(name.text(),path.text(),interface.text(),methodcall);
575   }
576 
signal(const FXchar * sname)577 DBusMessage * GMDBusProxy::signal(const FXchar * sname){
578   return dbus_message_new_signal(path.text(),interface.text(),sname);
579   }
580 
581 
onCreate(FXObject *,FXSelector,void * ptr)582 long GMDBusProxy::onCreate(FXObject*,FXSelector,void*ptr) {
583   associated=true;
584   return target && target->tryHandle(this,FXSEL(SEL_DESTROY,message),ptr);
585   }
onDestroy(FXObject *,FXSelector,void * ptr)586 long GMDBusProxy::onDestroy(FXObject*,FXSelector,void*ptr) {
587   associated=false;
588   return target && target->tryHandle(this,FXSEL(SEL_DESTROY,message),ptr);
589   }
onReplaced(FXObject *,FXSelector,void * ptr)590 long GMDBusProxy::onReplaced(FXObject*,FXSelector,void*ptr) {
591   return target && target->tryHandle(this,FXSEL(SEL_REPLACED,message),ptr);
592   }
onSignal(FXObject *,FXSelector,void * ptr)593 long GMDBusProxy::onSignal(FXObject*,FXSelector,void*ptr) {
594   return target && target->tryHandle(this,FXSEL(SEL_SIGNAL,message),ptr);
595   }
onMethod(FXObject *,FXSelector,void * ptr)596 long GMDBusProxy::onMethod(FXObject*,FXSelector,void*ptr) {
597   return target && target->tryHandle(this,FXSEL(SEL_COMMAND,message),ptr);
598   }
599 
600 
601 
602 
603 
604 
605 
606 
607 
608 
609 
610 
611 
612 
613 
614 
615 
616 
617 
618 
619 
620 /*******************************************************************************************************/
621 /* HELPER API                                                                                 */
622 /*******************************************************************************************************/
623 
624 
gm_dbus_variant_append_basic(DBusMessageIter * iter,const FXchar * element_type_string,FXint element_type,const void * value)625 void gm_dbus_variant_append_basic(DBusMessageIter * iter,const FXchar * element_type_string,FXint element_type,const void * value) {
626   DBusMessageIter container;
627   dbus_message_iter_open_container(iter,DBUS_TYPE_VARIANT,element_type_string,&container);
628   dbus_message_iter_append_basic(&container,element_type,value);
629   dbus_message_iter_close_container(iter,&container);
630   }
631 
632 
gm_dbus_variant_append_string(DBusMessageIter * iter,const FXchar * value)633 void gm_dbus_variant_append_string(DBusMessageIter * iter,const FXchar * value) {
634   gm_dbus_variant_append_basic(iter,DBUS_TYPE_STRING_AS_STRING,DBUS_TYPE_STRING,&value);
635   }
636 
gm_dbus_variant_append_int32(DBusMessageIter * iter,const FXint value)637 void gm_dbus_variant_append_int32(DBusMessageIter * iter,const FXint value){
638   gm_dbus_variant_append_basic(iter,DBUS_TYPE_INT32_AS_STRING,DBUS_TYPE_INT32,&value);
639   }
640 
gm_dbus_variant_append_uint32(DBusMessageIter * iter,const FXuint value)641 void gm_dbus_variant_append_uint32(DBusMessageIter * iter,const FXuint value){
642   gm_dbus_variant_append_basic(iter,DBUS_TYPE_UINT32_AS_STRING,DBUS_TYPE_UINT32,&value);
643   }
644 
gm_dbus_variant_append_path(DBusMessageIter * iter,const FXchar * value)645 void gm_dbus_variant_append_path(DBusMessageIter * iter,const FXchar * value){
646   gm_dbus_variant_append_basic(iter,DBUS_TYPE_OBJECT_PATH_AS_STRING,DBUS_TYPE_OBJECT_PATH,&value);
647   }
648 
gm_dbus_variant_append_bool(DBusMessageIter * iter,const dbus_bool_t value)649 void gm_dbus_variant_append_bool(DBusMessageIter * iter,const dbus_bool_t value){
650   gm_dbus_variant_append_basic(iter,DBUS_TYPE_BOOLEAN_AS_STRING,DBUS_TYPE_BOOLEAN,&value);
651   }
652 
gm_dbus_variant_append_double(DBusMessageIter * iter,const FXdouble value)653 void gm_dbus_variant_append_double(DBusMessageIter * iter,const FXdouble value){
654   gm_dbus_variant_append_basic(iter,DBUS_TYPE_DOUBLE_AS_STRING,DBUS_TYPE_DOUBLE,&value);
655   }
656 
gm_dbus_variant_append_long(DBusMessageIter * iter,const FXlong value)657 void gm_dbus_variant_append_long(DBusMessageIter * iter,const FXlong value){
658   gm_dbus_variant_append_basic(iter,DBUS_TYPE_INT64_AS_STRING,DBUS_TYPE_INT64,&value);
659   }
660 
gm_dbus_variant_append_string_list(DBusMessageIter * iter,const FXchar * value[])661 void gm_dbus_variant_append_string_list(DBusMessageIter * iter,const FXchar * value[]){
662   DBusMessageIter container;
663   DBusMessageIter array;
664   dbus_message_iter_open_container(iter,DBUS_TYPE_VARIANT,DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,&container);
665   dbus_message_iter_open_container(&container,DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING,&array);
666   for (FXint n=0;value[n];n++) {
667     dbus_message_iter_append_basic(&array,DBUS_TYPE_STRING,&value[n]);
668     }
669   dbus_message_iter_close_container(&container,&array);
670   dbus_message_iter_close_container(iter,&container);
671   }
672 
gm_dbus_variant_append_string_list(DBusMessageIter * iter,const FXStringList & list)673 void gm_dbus_variant_append_string_list(DBusMessageIter * iter,const FXStringList & list){
674   DBusMessageIter container;
675   DBusMessageIter array;
676   dbus_message_iter_open_container(iter,DBUS_TYPE_VARIANT,DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,&container);
677   dbus_message_iter_open_container(&container,DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING,&array);
678   for (FXint n=0;n<list.no();n++) {
679     gm_dbus_append_string(&array,list[n]);
680     }
681   dbus_message_iter_close_container(&container,&array);
682   dbus_message_iter_close_container(iter,&container);
683   }
684 
gm_dbus_append_string(DBusMessageIter * iter,const FXString & value)685 void gm_dbus_append_string(DBusMessageIter *iter,const FXString & value){
686   const FXchar * v = value.text();
687   dbus_message_iter_append_basic(iter,DBUS_TYPE_STRING,&v);
688   }
689 
690 
gm_dbus_append_string_pair(DBusMessageIter * iter,const FXchar * key,const FXchar * value)691 void gm_dbus_append_string_pair(DBusMessageIter *iter,const FXchar * key,const FXchar * value){
692   dbus_message_iter_append_basic(iter,DBUS_TYPE_STRING,&key);
693   dbus_message_iter_append_basic(iter,DBUS_TYPE_STRING,&value);
694   }
695 
696 
gm_dbus_dict_append_int32(DBusMessageIter * iter,const FXchar * key,const FXint value)697 void gm_dbus_dict_append_int32(DBusMessageIter * iter,const FXchar * key,const FXint value){
698   DBusMessageIter container;
699   dbus_message_iter_open_container(iter,DBUS_TYPE_DICT_ENTRY,0,&container);
700   dbus_message_iter_append_basic(&container,DBUS_TYPE_STRING,&key);
701   gm_dbus_variant_append_int32(&container,value);
702   dbus_message_iter_close_container(iter,&container);
703   }
704 
gm_dbus_dict_append_uint32(DBusMessageIter * iter,const FXchar * key,const FXuint value)705 void gm_dbus_dict_append_uint32(DBusMessageIter * iter,const FXchar * key,const FXuint value){
706   DBusMessageIter container;
707   dbus_message_iter_open_container(iter,DBUS_TYPE_DICT_ENTRY,0,&container);
708   dbus_message_iter_append_basic(&container,DBUS_TYPE_STRING,&key);
709   gm_dbus_variant_append_uint32(&container,value);
710   dbus_message_iter_close_container(iter,&container);
711   }
712 
713 
gm_dbus_dict_append_string(DBusMessageIter * iter,const FXchar * key,const FXchar * value)714 void gm_dbus_dict_append_string(DBusMessageIter * iter,const FXchar * key,const FXchar * value){
715   DBusMessageIter container;
716   dbus_message_iter_open_container(iter,DBUS_TYPE_DICT_ENTRY,0,&container);
717   dbus_message_iter_append_basic(&container,DBUS_TYPE_STRING,&key);
718   gm_dbus_variant_append_string(&container,value);
719   dbus_message_iter_close_container(iter,&container);
720   }
721 
gm_dbus_dict_append_string(DBusMessageIter * iter,const FXchar * key,const FXString & value)722 void gm_dbus_dict_append_string(DBusMessageIter * iter,const FXchar * key,const FXString & value){
723   DBusMessageIter container;
724   dbus_message_iter_open_container(iter,DBUS_TYPE_DICT_ENTRY,0,&container);
725   dbus_message_iter_append_basic(&container,DBUS_TYPE_STRING,&key);
726   gm_dbus_variant_append_string(&container,value.text());
727   dbus_message_iter_close_container(iter,&container);
728   }
729 
gm_dbus_dict_append_path(DBusMessageIter * iter,const FXchar * key,const FXchar * value)730 void gm_dbus_dict_append_path(DBusMessageIter * iter,const FXchar * key,const FXchar * value){
731   DBusMessageIter container;
732   dbus_message_iter_open_container(iter,DBUS_TYPE_DICT_ENTRY,0,&container);
733   dbus_message_iter_append_basic(&container,DBUS_TYPE_STRING,&key);
734   gm_dbus_variant_append_path(&container,value);
735   dbus_message_iter_close_container(iter,&container);
736   }
737 
gm_dbus_dict_append_bool(DBusMessageIter * iter,const FXchar * key,const dbus_bool_t value)738 void gm_dbus_dict_append_bool(DBusMessageIter * iter,const FXchar * key,const dbus_bool_t value){
739   DBusMessageIter container;
740   dbus_message_iter_open_container(iter,DBUS_TYPE_DICT_ENTRY,0,&container);
741   dbus_message_iter_append_basic(&container,DBUS_TYPE_STRING,&key);
742   gm_dbus_variant_append_bool(&container,value);
743   dbus_message_iter_close_container(iter,&container);
744   }
745 
746 
gm_dbus_dict_append_double(DBusMessageIter * iter,const FXchar * key,const FXdouble & value)747 void gm_dbus_dict_append_double(DBusMessageIter * iter,const FXchar * key,const FXdouble & value){
748   DBusMessageIter container;
749   dbus_message_iter_open_container(iter,DBUS_TYPE_DICT_ENTRY,0,&container);
750   dbus_message_iter_append_basic(&container,DBUS_TYPE_STRING,&key);
751   gm_dbus_variant_append_double(&container,value);
752   dbus_message_iter_close_container(iter,&container);
753   }
754 
gm_dbus_dict_append_long(DBusMessageIter * iter,const FXchar * key,const FXlong & value)755 void gm_dbus_dict_append_long(DBusMessageIter * iter,const FXchar * key,const FXlong & value){
756   DBusMessageIter container;
757   dbus_message_iter_open_container(iter,DBUS_TYPE_DICT_ENTRY,0,&container);
758   dbus_message_iter_append_basic(&container,DBUS_TYPE_STRING,&key);
759   gm_dbus_variant_append_long(&container,value);
760   dbus_message_iter_close_container(iter,&container);
761   }
762 
763 
gm_dbus_dict_append_string_list(DBusMessageIter * iter,const FXchar * key,const FXchar * value[])764 void gm_dbus_dict_append_string_list(DBusMessageIter * iter,const FXchar * key,const FXchar * value[]){
765   DBusMessageIter container;
766   dbus_message_iter_open_container(iter,DBUS_TYPE_DICT_ENTRY,0,&container);
767   dbus_message_iter_append_basic(&container,DBUS_TYPE_STRING,&key);
768   gm_dbus_variant_append_string_list(&container,value);
769   dbus_message_iter_close_container(iter,&container);
770   }
771 
gm_dbus_dict_append_string_list(DBusMessageIter * iter,const FXchar * key,const FXStringList & value)772 void gm_dbus_dict_append_string_list(DBusMessageIter * iter,const FXchar * key,const FXStringList &value){
773   DBusMessageIter container;
774   dbus_message_iter_open_container(iter,DBUS_TYPE_DICT_ENTRY,0,&container);
775   dbus_message_iter_append_basic(&container,DBUS_TYPE_STRING,&key);
776   gm_dbus_variant_append_string_list(&container,value);
777   dbus_message_iter_close_container(iter,&container);
778   }
779 
780 
gm_dbus_property_string(DBusConnection * connection,DBusMessage * msg,const FXchar * data)781 DBusHandlerResult gm_dbus_property_string(DBusConnection * connection,DBusMessage * msg,const FXchar * data) {
782   FXuint serial;
783   DBusMessage * reply = dbus_message_new_method_return(msg);
784   if (reply) {
785     DBusMessageIter iter;
786     dbus_message_iter_init_append(reply,&iter);
787     gm_dbus_variant_append_string(&iter,data);
788     dbus_connection_send(connection,reply,&serial);
789     dbus_message_unref(reply);
790     }
791   return DBUS_HANDLER_RESULT_HANDLED;
792   }
793 
gm_dbus_property_string_list(DBusConnection * connection,DBusMessage * msg,const FXchar * data[])794 DBusHandlerResult gm_dbus_property_string_list(DBusConnection * connection,DBusMessage * msg,const FXchar * data[]) {
795   FXuint serial;
796   DBusMessage * reply = dbus_message_new_method_return(msg);
797   if (reply) {
798     DBusMessageIter iter;
799     dbus_message_iter_init_append(reply,&iter);
800     gm_dbus_variant_append_string_list(&iter,data);
801     dbus_connection_send(connection,reply,&serial);
802     dbus_message_unref(reply);
803     }
804   return DBUS_HANDLER_RESULT_HANDLED;
805   }
806 
807 
gm_dbus_property_bool(DBusConnection * connection,DBusMessage * msg,const dbus_bool_t data)808 DBusHandlerResult gm_dbus_property_bool(DBusConnection * connection,DBusMessage * msg,const dbus_bool_t data) {
809   FXuint serial;
810   DBusMessage * reply = dbus_message_new_method_return(msg);
811   if (reply) {
812     DBusMessageIter iter;
813     dbus_message_iter_init_append(reply,&iter);
814     gm_dbus_variant_append_bool(&iter,data);
815     dbus_connection_send(connection,reply,&serial);
816     dbus_message_unref(reply);
817     }
818   return DBUS_HANDLER_RESULT_HANDLED;
819   }
820 
gm_dbus_property_long(DBusConnection * connection,DBusMessage * msg,const FXlong data)821 DBusHandlerResult gm_dbus_property_long(DBusConnection * connection,DBusMessage * msg,const FXlong data) {
822   FXuint serial;
823   DBusMessage * reply = dbus_message_new_method_return(msg);
824   if (reply) {
825     DBusMessageIter iter;
826     dbus_message_iter_init_append(reply,&iter);
827     gm_dbus_variant_append_long(&iter,data);
828     dbus_connection_send(connection,reply,&serial);
829     dbus_message_unref(reply);
830     }
831   return DBUS_HANDLER_RESULT_HANDLED;
832   }
833 
834 
gm_dbus_property_double(DBusConnection * connection,DBusMessage * msg,const FXdouble data)835 DBusHandlerResult gm_dbus_property_double(DBusConnection * connection,DBusMessage * msg,const FXdouble data) {
836   FXuint serial;
837   DBusMessage * reply = dbus_message_new_method_return(msg);
838   if (reply) {
839     DBusMessageIter iter;
840     dbus_message_iter_init_append(reply,&iter);
841     gm_dbus_variant_append_double(&iter,data);
842     dbus_connection_send(connection,reply,&serial);
843     dbus_message_unref(reply);
844     }
845   return DBUS_HANDLER_RESULT_HANDLED;
846   }
847 
848 
849 
gm_dbus_reply_string(DBusConnection * connection,DBusMessage * msg,const FXchar * data)850 DBusHandlerResult gm_dbus_reply_string(DBusConnection * connection,DBusMessage * msg,const FXchar * data) {
851   FXuint serial;
852   DBusMessage * reply = dbus_message_new_method_return(msg);
853   if (reply) {
854     dbus_message_append_args(reply,DBUS_TYPE_STRING,&data,DBUS_TYPE_INVALID);
855     dbus_connection_send(connection,reply,&serial);
856     dbus_message_unref(reply);
857     }
858   return DBUS_HANDLER_RESULT_HANDLED;
859   }
860 
gm_dbus_reply_uint_string(DBusConnection * connection,DBusMessage * msg,const FXuint val,const FXchar * data)861 DBusHandlerResult gm_dbus_reply_uint_string(DBusConnection * connection,DBusMessage * msg,const FXuint val,const FXchar * data) {
862   FXuint serial;
863   DBusMessage * reply = dbus_message_new_method_return(msg);
864   if (reply) {
865     dbus_message_append_args(reply,DBUS_TYPE_UINT32,&val,DBUS_TYPE_STRING,&data,DBUS_TYPE_INVALID);
866     dbus_connection_send(connection,reply,&serial);
867     dbus_message_unref(reply);
868     }
869   return DBUS_HANDLER_RESULT_HANDLED;
870   }
871 
gm_dbus_reply_int(DBusConnection * connection,DBusMessage * msg,const FXint data)872 DBusHandlerResult gm_dbus_reply_int(DBusConnection * connection,DBusMessage * msg,const FXint data) {
873   FXuint serial;
874   DBusMessage * reply = dbus_message_new_method_return(msg);
875   if (reply) {
876     dbus_message_append_args(reply,DBUS_TYPE_INT32,&data,DBUS_TYPE_INVALID);
877     dbus_connection_send(connection,reply,&serial);
878     dbus_message_unref(reply);
879     }
880   return DBUS_HANDLER_RESULT_HANDLED;
881   }
882 
gm_dbus_reply_double(DBusConnection * connection,DBusMessage * msg,const FXdouble data)883 DBusHandlerResult gm_dbus_reply_double(DBusConnection * connection,DBusMessage * msg,const FXdouble data) {
884   FXuint serial;
885   DBusMessage * reply = dbus_message_new_method_return(msg);
886   if (reply) {
887     dbus_message_append_args(reply,DBUS_TYPE_DOUBLE,&data,DBUS_TYPE_INVALID);
888     dbus_connection_send(connection,reply,&serial);
889     dbus_message_unref(reply);
890     }
891   return DBUS_HANDLER_RESULT_HANDLED;
892   }
893 
gm_dbus_reply_long(DBusConnection * connection,DBusMessage * msg,const FXlong data)894 DBusHandlerResult gm_dbus_reply_long(DBusConnection * connection,DBusMessage * msg,const FXlong data) {
895   FXuint serial;
896   DBusMessage * reply = dbus_message_new_method_return(msg);
897   if (reply) {
898     dbus_message_append_args(reply,DBUS_TYPE_INT64,&data,DBUS_TYPE_INVALID);
899     dbus_connection_send(connection,reply,&serial);
900     dbus_message_unref(reply);
901     }
902   return DBUS_HANDLER_RESULT_HANDLED;
903   }
904 
gm_dbus_reply_unsigned_int(DBusConnection * connection,DBusMessage * msg,const FXuint data)905 DBusHandlerResult gm_dbus_reply_unsigned_int(DBusConnection * connection,DBusMessage * msg,const FXuint data) {
906   FXuint serial;
907   DBusMessage * reply = dbus_message_new_method_return(msg);
908   if (reply) {
909     dbus_message_append_args(reply,DBUS_TYPE_UINT32,&data,DBUS_TYPE_INVALID);
910     dbus_connection_send(connection,reply,&serial);
911     dbus_message_unref(reply);
912     }
913   return DBUS_HANDLER_RESULT_HANDLED;
914   }
915 
gm_dbus_reply_bool(DBusConnection * connection,DBusMessage * msg,const dbus_bool_t data)916 DBusHandlerResult gm_dbus_reply_bool(DBusConnection * connection,DBusMessage * msg,const dbus_bool_t data) {
917   FXuint serial;
918   DBusMessage * reply = dbus_message_new_method_return(msg);
919   if (reply) {
920     dbus_message_append_args(reply,DBUS_TYPE_BOOLEAN,&data,DBUS_TYPE_INVALID);
921     dbus_connection_send(connection,reply,&serial);
922     dbus_message_unref(reply);
923     }
924   return DBUS_HANDLER_RESULT_HANDLED;
925   }
926 
gm_dbus_reply_string_list(DBusConnection * connection,DBusMessage * msg,const FXchar * data[])927 DBusHandlerResult gm_dbus_reply_string_list(DBusConnection * connection,DBusMessage * msg,const FXchar * data[]) {
928   FXuint serial;
929   DBusMessage * reply = dbus_message_new_method_return(msg);
930   if (reply) {
931     DBusMessageIter iter;
932     DBusMessageIter array;
933     dbus_message_iter_init_append(reply,&iter);
934     dbus_message_iter_open_container(&iter,DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING,&array);
935     for (FXint n=0;data[n];n++) {
936       dbus_message_iter_append_basic(&array,DBUS_TYPE_STRING,&data[n]);
937       }
938     dbus_message_iter_close_container(&iter,&array);
939     dbus_connection_send(connection,reply,&serial);
940     dbus_message_unref(reply);
941     }
942   return DBUS_HANDLER_RESULT_HANDLED;
943   }
944 
945 
946 
947 
gm_dbus_reply_if_needed(DBusConnection * connection,DBusMessage * msg)948 DBusHandlerResult gm_dbus_reply_if_needed(DBusConnection * connection,DBusMessage * msg) {
949   if (!dbus_message_get_no_reply(msg)) {
950     FXuint serial;
951     DBusMessage * reply = dbus_message_new_method_return(msg);
952     if (reply) {
953       dbus_connection_send(connection,reply,&serial);
954       dbus_message_unref(reply);
955       }
956     }
957   return DBUS_HANDLER_RESULT_HANDLED;
958   }
959 
gm_dbus_match_signal(DBusConnection * connection,const FXchar * path,const FXchar * interface,const FXchar * member)960 void gm_dbus_match_signal(DBusConnection*connection,const FXchar * path,const FXchar * interface,const FXchar * member){
961   FXString rule = FXString::value("type='signal',path='%s',interface='%s',member='%s'",path,interface,member);
962   dbus_bus_add_match(connection,rule.text(),nullptr);
963   }
964