Mercurial > emacs
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 |