comparison src/dbusbind.c @ 87051:1da959e791de

* dbusbind.c (QCdbus_system_bus, QCdbus_session_bus): Renamed from Qdbus_system_bus and Qdbus_session_bus, respectively. (Vdbus_intern_symbols): Removed. (Vdbus_registered_functions_table): New hash table. (XD_SYMBOL_INTERN_SYMBOL): Removed. (xd_read_message, Fdbus_register_signal, Fdbus_unregister_signal): Rewritten in order to manage registered functions by hash table Vdbus_registered_functions_table.
author Michael Albinus <michael.albinus@gmx.de>
date Tue, 04 Dec 2007 21:29:40 +0000
parents 2dd672d9fe75
children f767f1ba8301
comparison
equal deleted inserted replaced
87050:7d80e0f3d8f8 87051:1da959e791de
38 38
39 /* D-Bus error symbol. */ 39 /* D-Bus error symbol. */
40 Lisp_Object Qdbus_error; 40 Lisp_Object Qdbus_error;
41 41
42 /* Lisp symbols of the system and session buses. */ 42 /* Lisp symbols of the system and session buses. */
43 Lisp_Object Qdbus_system_bus, Qdbus_session_bus; 43 Lisp_Object QCdbus_system_bus, QCdbus_session_bus;
44 44
45 /* Obarray which keeps interned symbols. */ 45 /* Hash table which keeps function definitions. */
46 Lisp_Object Vdbus_intern_symbols; 46 Lisp_Object Vdbus_registered_functions_table;
47 47
48 /* Whether to debug D-Bus. */ 48 /* Whether to debug D-Bus. */
49 Lisp_Object Vdbus_debug; 49 Lisp_Object Vdbus_debug;
50 50
51 51
52 /* We use "xd_" and "XD_" as prefix for all internal symbols, because 52 /* We use "xd_" and "XD_" as prefix for all internal symbols, because
53 we don't want to poison other namespaces with "dbus_". */ 53 we don't want to poison other namespaces with "dbus_". */
54
55 /* Create a new interned symbol which represents a function handler.
56 bus is a Lisp symbol, either :system or :session. interface and
57 member are both Lisp strings.
58
59 D-Bus sends messages, which are captured by Emacs in the main loop,
60 converted into an event then. Emacs must identify a message from
61 D-Bus, in order to call the right Lisp function when the event is
62 handled in the event handler function of dbus.el.
63
64 A D-Bus message is determined at least by the D-Bus bus it is
65 raised from (system bus or session bus), the interface and the
66 method the message belongs to. There could be even more properties
67 for determination, but that isn't implemented yet.
68
69 The approach is to create a new interned Lisp symbol once there is
70 a registration request for a given signal, which is a special D-Bus
71 message. The symbol's name is a concatenation of the bus name,
72 interface name and method name of the signal; the function cell is
73 the Lisp function to be called when such a signal arrives. Since
74 this code runs in the main loop, receiving input, it must be
75 performant. */
76 #define XD_SYMBOL_INTERN_SYMBOL(symbol, bus, interface, member) \
77 { \
78 XD_DEBUG_VALID_LISP_OBJECT_P (bus); \
79 XD_DEBUG_VALID_LISP_OBJECT_P (interface); \
80 XD_DEBUG_VALID_LISP_OBJECT_P (member); \
81 char s[1024]; \
82 strcpy (s, SDATA (SYMBOL_NAME (bus))); \
83 strcat (s, "."); \
84 strcat (s, SDATA (interface)); \
85 strcat (s, "."); \
86 strcat (s, SDATA (member)); \
87 symbol = Fintern (build_string (s), Vdbus_intern_symbols); \
88 }
89 54
90 /* Raise a Lisp error from a D-Bus error. */ 55 /* Raise a Lisp error from a D-Bus error. */
91 #define XD_ERROR(error) \ 56 #define XD_ERROR(error) \
92 { \ 57 { \
93 char s[1024]; \ 58 char s[1024]; \
246 DBusConnection *connection; 211 DBusConnection *connection;
247 DBusError derror; 212 DBusError derror;
248 213
249 /* Parameter check. */ 214 /* Parameter check. */
250 CHECK_SYMBOL (bus); 215 CHECK_SYMBOL (bus);
251 if (!((EQ (bus, Qdbus_system_bus)) || (EQ (bus, Qdbus_session_bus)))) 216 if (!((EQ (bus, QCdbus_system_bus)) || (EQ (bus, QCdbus_session_bus))))
252 xsignal2 (Qdbus_error, build_string ("Wrong bus name"), bus); 217 xsignal2 (Qdbus_error, build_string ("Wrong bus name"), bus);
253 218
254 /* Open a connection to the bus. */ 219 /* Open a connection to the bus. */
255 dbus_error_init (&derror); 220 dbus_error_init (&derror);
256 221
257 if (EQ (bus, Qdbus_system_bus)) 222 if (EQ (bus, QCdbus_system_bus))
258 connection = dbus_bus_get (DBUS_BUS_SYSTEM, &derror); 223 connection = dbus_bus_get (DBUS_BUS_SYSTEM, &derror);
259 else 224 else
260 connection = dbus_bus_get (DBUS_BUS_SESSION, &derror); 225 connection = dbus_bus_get (DBUS_BUS_SESSION, &derror);
261 226
262 if (dbus_error_is_set (&derror)) 227 if (dbus_error_is_set (&derror))
575 symbol, either :system or :session. */ 540 symbol, either :system or :session. */
576 void 541 void
577 xd_read_message (bus) 542 xd_read_message (bus)
578 Lisp_Object bus; 543 Lisp_Object bus;
579 { 544 {
580 Lisp_Object symbol; 545 Lisp_Object key;
581 struct gcpro gcpro1; 546 struct gcpro gcpro1;
582 static struct input_event event; 547 static struct input_event event;
583 DBusConnection *connection; 548 DBusConnection *connection;
584 DBusMessage *dmessage; 549 DBusMessage *dmessage;
585 DBusMessageIter iter; 550 DBusMessageIter iter;
586 uint dtype; 551 uint dtype;
587 char s1[1024], s2[1024]; 552 char service[1024], path[1024], interface[1024], member[1024];
553
554 /* Vdbus_registered_functions_table will be made as hash table in
555 dbus.el. When it isn't loaded yet, it doesn't make sense to
556 handle D-Bus messages. */
557 if (!HASH_TABLE_P (Vdbus_registered_functions_table))
558 return;
588 559
589 /* Open a connection to the bus. */ 560 /* Open a connection to the bus. */
590 connection = xd_initialize (bus); 561 connection = xd_initialize (bus);
591 562
592 /* Non blocking read of the next available message. */ 563 /* Non blocking read of the next available message. */
623 } 594 }
624 595
625 /* The arguments are stored in reverse order. Reorder them. */ 596 /* The arguments are stored in reverse order. Reorder them. */
626 event.arg = Fnreverse (event.arg); 597 event.arg = Fnreverse (event.arg);
627 598
628 /* Add the object path of the sender of the message. */ 599 /* Read service, object path interface and member from the
629 strcpy (s1, dbus_message_get_path (dmessage)); 600 message. */
630 event.arg = Fcons ((s1 == NULL ? Qnil : build_string (s1)), event.arg); 601 strcpy (service, dbus_message_get_sender (dmessage));
631 602 strcpy (path, dbus_message_get_path (dmessage));
632 /* Add the unique name of the sender of the message. */ 603 strcpy (interface, dbus_message_get_interface (dmessage));
633 strcpy (s2, dbus_message_get_sender (dmessage)); 604 strcpy (member, dbus_message_get_member (dmessage));
634 event.arg = Fcons ((s2 == NULL ? Qnil : build_string (s2)), event.arg); 605
635 606 /* Add them to the event. */
636 /* Add the interned symbol the message is raised from (signal) or 607 event.arg = Fcons ((member == NULL ? Qnil : build_string (member)),
637 for (method). */ 608 event.arg);
638 strcpy (s1, dbus_message_get_interface (dmessage)); 609 event.arg = Fcons ((interface == NULL ? Qnil : build_string (interface)),
639 strcpy (s2, dbus_message_get_member (dmessage)); 610 event.arg);
640 XD_SYMBOL_INTERN_SYMBOL 611 event.arg = Fcons ((path == NULL ? Qnil : build_string (path)),
641 (symbol, bus, 612 event.arg);
642 (s1 == NULL ? Qnil : build_string (s1)), 613 event.arg = Fcons ((service == NULL ? Qnil : build_string (service)),
643 (s2 == NULL ? Qnil : build_string (s2))); 614 event.arg);
644 event.arg = Fcons (symbol, event.arg); 615
616 /* Add the bus symbol to the event. */
617 event.arg = Fcons (bus, event.arg);
618
619 /* Add the registered function of the message. */
620 key = list3 (bus,
621 (interface == NULL ? Qnil : build_string (interface)),
622 (member == NULL ? Qnil : build_string (member)));
623 event.arg = Fcons (Fgethash (key, Vdbus_registered_functions_table, Qnil),
624 event.arg);
645 625
646 /* Store it into the input event queue. */ 626 /* Store it into the input event queue. */
647 kbd_buffer_store_event (&event); 627 kbd_buffer_store_event (&event);
648 628
649 /* Cleanup. */ 629 /* Cleanup. */
653 633
654 /* Read queued incoming messages from the system and session buses. */ 634 /* Read queued incoming messages from the system and session buses. */
655 void 635 void
656 xd_read_queued_messages () 636 xd_read_queued_messages ()
657 { 637 {
658 xd_read_message (Qdbus_system_bus); 638 xd_read_message (QCdbus_system_bus);
659 xd_read_message (Qdbus_session_bus); 639 xd_read_message (QCdbus_session_bus);
660 } 640 }
661 641
662 DEFUN ("dbus-register-signal", Fdbus_register_signal, Sdbus_register_signal, 642 DEFUN ("dbus-register-signal", Fdbus_register_signal, Sdbus_register_signal,
663 6, 6, 0, 643 6, 6, 0,
664 doc: /* Register for signal SIGNAL on the D-Bus BUS. 644 doc: /* Register for signal SIGNAL on the D-Bus BUS.
665 645
666 BUS is either the symbol `:system' or the symbol `:session'. 646 BUS is either the symbol `:system' or the symbol `:session'.
667 647
668 SERVICE is the D-Bus service name to be used. PATH is the D-Bus 648 SERVICE is the D-Bus service name used by the sending D-Bus object.
669 object path SERVICE is registered. INTERFACE is an interface offered 649 It can be either a known name or the unique name of the D-Bus object
670 by SERVICE. It must provide SIGNAL. 650 sending the signal. When SERVICE is nil, related signals from all
671 651 D-Bus objects shall be accepted.
652
653 PATH is the D-Bus object path SERVICE is registered. It can also be
654 nil if the path name of incoming signals shall not be checked.
655
656 INTERFACE is an interface offered by SERVICE. It must provide SIGNAL.
672 HANDLER is a Lisp function to be called when the signal is received. 657 HANDLER is a Lisp function to be called when the signal is received.
673 It must accept as arguments the values SIGNAL is sending. 658 It must accept as arguments the values SIGNAL is sending. INTERFACE,
674 659 SIGNAL and HANDLER must not be nil. Example:
675 Example:
676 660
677 \(defun my-signal-handler (device) 661 \(defun my-signal-handler (device)
678 (message "Device %s added" device)) 662 (message "Device %s added" device))
679 663
680 \(dbus-register-signal 664 \(dbus-register-signal
681 :system "DeviceAdded" "org.freedesktop.Hal" 665 :system "DeviceAdded"
666 (dbus-get-name-owner :system "org.freedesktop.Hal")
682 "/org/freedesktop/Hal/Manager" "org.freedesktop.Hal.Manager" 667 "/org/freedesktop/Hal/Manager" "org.freedesktop.Hal.Manager"
683 'my-signal-handler) 668 'my-signal-handler)
684 669
685 => org.freedesktop.Hal.Manager.DeviceAdded 670 => (:system "org.freedesktop.Hal.Manager" "DeviceAdded")
686 671
687 `dbus-register-signal' returns an object, which can be used in 672 `dbus-register-signal' returns an object, which can be used in
688 `dbus-unregister-signal' for removing the registration. */) 673 `dbus-unregister-signal' for removing the registration. */)
689 (bus, signal, service, path, interface, handler) 674 (bus, signal, service, path, interface, handler)
690 Lisp_Object bus, signal, service, path, interface, handler; 675 Lisp_Object bus, signal, service, path, interface, handler;
691 { 676 {
692 Lisp_Object name_owner, result; 677 Lisp_Object key;
693 DBusConnection *connection; 678 DBusConnection *connection;
679 char rule[1024];
694 DBusError derror; 680 DBusError derror;
695 char rule[1024];
696 681
697 /* Check parameters. */ 682 /* Check parameters. */
698 CHECK_SYMBOL (bus); 683 CHECK_SYMBOL (bus);
699 CHECK_STRING (signal); 684 CHECK_STRING (signal);
700 CHECK_STRING (service); 685 if (!NILP (service)) CHECK_STRING (service);
701 CHECK_STRING (path); 686 if (!NILP (path)) CHECK_STRING (path);
702 CHECK_STRING (interface); 687 CHECK_STRING (interface);
703 CHECK_SYMBOL (handler); 688 CHECK_SYMBOL (handler);
704 689
705 /* Open a connection to the bus. */ 690 /* Open a connection to the bus. */
706 connection = xd_initialize (bus); 691 connection = xd_initialize (bus);
707 692
708 #if 0 693 /* Create a rule to receive related signals. */
709 /* TODO: Get name owner. This is the sending service name. */
710 name_owner = call2 (intern ("dbus-get-name-owner"), bus, service);
711 #endif
712
713 /* Add a rule to the bus in order to receive related signals. */
714 dbus_error_init (&derror);
715 sprintf (rule, 694 sprintf (rule,
716 "type='signal',interface='%s',member=%s%", 695 "type='signal',interface='%s',member=%s%",
717 SDATA (interface), 696 SDATA (interface),
718 SDATA (signal)); 697 SDATA (signal));
719 #if 0 698
720 /* TODO: We need better checks when we want use sender and path. */ 699 /* Add service and path to the rule if they are non-nil. */
721 sprintf (rule, 700 if (!NILP (service))
722 "type='signal',sender='%s',path='%s',interface='%s',member=%s%", 701 sprintf (rule, "%s,sender='%s'%", rule, SDATA (service));
723 SDATA (name_owner), 702
724 SDATA (path), 703 if (!NILP (path))
725 SDATA (interface), 704 sprintf (rule, "%s,path='%s'", rule, SDATA (path));
726 SDATA (signal)); 705
727 #endif 706 /* Add the rule to the bus. */
707 dbus_error_init (&derror);
728 dbus_bus_add_match (connection, rule, &derror); 708 dbus_bus_add_match (connection, rule, &derror);
729
730 if (dbus_error_is_set (&derror)) 709 if (dbus_error_is_set (&derror))
731 XD_ERROR (derror); 710 XD_ERROR (derror);
732 711
733 XD_DEBUG_MESSAGE ("Matching rule \"%s\" created", rule); 712 XD_DEBUG_MESSAGE ("Matching rule \"%s\" created", rule);
734 713
735 /* Create a new protected symbol, which has the complete name of the 714 /* Create a hash table entry. */
736 signal. The function cell is taken from the handler. */ 715 key = list3 (bus, interface, signal);
737 result = Qnil; 716 Fputhash (key, handler, Vdbus_registered_functions_table);
738
739 XD_SYMBOL_INTERN_SYMBOL (result, bus, interface, signal);
740 Ffset (result, Fsymbol_function (handler));
741 XD_DEBUG_MESSAGE ("\"%s\" registered with handler \"%s\"", 717 XD_DEBUG_MESSAGE ("\"%s\" registered with handler \"%s\"",
742 SDATA (format2 ("%s", result, Qnil)), 718 SDATA (format2 ("%s", key, Qnil)),
743 SDATA (format2 ("%s", Fsymbol_function (result), Qnil))); 719 SDATA (format2 ("%s", handler, Qnil)));
744 720
745 /* Return. */ 721 /* Return key. */
746 return result; 722 return key;
747 } 723 }
748 724
749 DEFUN ("dbus-unregister-signal", Fdbus_unregister_signal, Sdbus_unregister_signal, 725 DEFUN ("dbus-unregister-signal", Fdbus_unregister_signal, Sdbus_unregister_signal,
750 1, 1, 0, 726 1, 1, 0,
751 doc: /* Unregister OBJECT from the D-Bus. 727 doc: /* Unregister OBJECT from the D-Bus.
760 XD_DEBUG_MESSAGE ("\"%s\" unregistered with handler \"%s\"", 736 XD_DEBUG_MESSAGE ("\"%s\" unregistered with handler \"%s\"",
761 SDATA (format2 ("%s", object, Qnil)), 737 SDATA (format2 ("%s", object, Qnil)),
762 SDATA (format2 ("%s", Fsymbol_function (object), Qnil))); 738 SDATA (format2 ("%s", Fsymbol_function (object), Qnil)));
763 739
764 /* Unintern the signal symbol. */ 740 /* Unintern the signal symbol. */
765 Funintern (object, Vdbus_intern_symbols); 741 Fremhash (object, Vdbus_registered_functions_table);
766 742
767 /* Return. */ 743 /* Return. */
768 return Qnil; 744 return Qnil;
769 } 745 }
770 746
798 Fput (Qdbus_error, Qerror_conditions, 774 Fput (Qdbus_error, Qerror_conditions,
799 list2 (Qdbus_error, Qerror)); 775 list2 (Qdbus_error, Qerror));
800 Fput (Qdbus_error, Qerror_message, 776 Fput (Qdbus_error, Qerror_message,
801 build_string ("D-Bus error")); 777 build_string ("D-Bus error"));
802 778
803 Qdbus_system_bus = intern (":system"); 779 QCdbus_system_bus = intern (":system");
804 staticpro (&Qdbus_system_bus); 780 staticpro (&QCdbus_system_bus);
805 781
806 Qdbus_session_bus = intern (":session"); 782 QCdbus_session_bus = intern (":session");
807 staticpro (&Qdbus_session_bus); 783 staticpro (&QCdbus_session_bus);
808 784
809 Vdbus_intern_symbols = Fmake_vector (make_number (64), 0); 785 DEFVAR_LISP ("dbus-registered-functions-table", &Vdbus_registered_functions_table,
810 staticpro (&Vdbus_intern_symbols); 786 doc: /* Hash table of registered functions for D-Bus.
787 The key in the hash table is the list (BUS INTERFACE MEMBER). BUS is
788 either the symbol `:system' or the symbol `:session'. INTERFACE is a
789 string which denotes a D-Bus interface, and MEMBER, also a string, is
790 either a method or a signal INTERFACE is offering.
791
792 The value in the hash table a the function to be called when a D-Bus
793 message, which matches the key criteria, arrives. */);
794 /* We initialize Vdbus_registered_functions_table in dbus.el,
795 because we need to define a hash table function first. */
796 Vdbus_registered_functions_table = Qnil;
811 797
812 DEFVAR_LISP ("dbus-debug", &Vdbus_debug, 798 DEFVAR_LISP ("dbus-debug", &Vdbus_debug,
813 doc: /* If non-nil, debug messages of D-Bus bindings are raised. */); 799 doc: /* If non-nil, debug messages of D-Bus bindings are raised. */);
814 #ifdef DBUS_DEBUG 800 #ifdef DBUS_DEBUG
815 Vdbus_debug = Qt; 801 Vdbus_debug = Qt;
816 #else 802 #else
817 Vdbus_debug = Qnil; 803 Vdbus_debug = Qnil;
818 #endif 804 #endif