=head1 NAME AnyEvent::DBus - adapt Net::DBus to AnyEvent =head1 SYNOPSIS use AnyEvent::DBus; # now use the Net::DBus API, preferably the non-blocking variants: use Net::DBus::Annotation qw(:call); $bus->get_object (...) ->Method (dbus_call_async, $arg1, ...) ->set_notify (sub { my @data = $_[0]->get_result ... }); $bus->get_connection->send (...); =head1 DESCRIPTION This module is an L user, you need to make sure that you use and run a supported event loop. Loading this module will install the necessary magic to seamlessly integrate L into L. It does this by quite brutally hacking L so that all dbus connections created after loading this module will automatically be managed by this module. Note that a) a lot inside Net::DBus is still blocking b) if you call a method that blocks, you again block your process (basically anything but calls to the Net::DBus::Binding::Connection objects block, but see Net::DBus::Annoation, specifically dbus_call_async) c) the underlying libdbus is often blocking itself, even with infinite timeouts and d) this module only implements the minimum API required to make Net::DBus work - Net::DBus unfortunately has no nice hooking API. However, unlike L, this module should be fully non-blocking as long as you only use non-blocking APIs (Net::DBus::Reactor blocks on writes). It should also be faster, but Net::DBus is such a morass of unneeded method calls that speed won't matter much... =head2 EXAMPLE Here is a simple example. Both work with AnyEvent::DBus and do the same thing, but only the second is actually non-blocking. Example 1: list registered named, blocking version. use AnyEvent::DBus; my $conn = Net::DBus->find; my $bus = $conn->get_bus_object; for my $name (@{ $bus->ListNames }) { print " $name\n"; } Example 1: list registered named, somewhat non-blocking version. use AnyEvent; use AnyEvent::DBus; use Net::DBus::Annotation qw(:call); my $conn = Net::DBus->find; # always blocks :/ my $bus = $conn->get_bus_object; my $quit = AE::cv; # the trick here is to prepend dbus_call_async to any method # arguments and then to call the set_notify method on the # returned Net::DBus::AsyncReply object $bus->ListNames (dbus_call_async)->set_notify (sub { for my $name (@{ $_[0]->get_result }) { print " $name\n"; } $quit->send; }); $quit->recv; =cut package AnyEvent::DBus; use common::sense; use AnyEvent (); use Net::DBus (); use Net::DBus::Binding::Watch (); our $VERSION = '0.31'; # yup, Net::DBus checks by using exists on %INC... $INC{'Net/DBus/Reactor.pm'} = undef; # claim we are the main reactor mainloop *Net::DBus::Reactor::main = sub { __PACKAGE__ }; our $I = 0; our %O; # watchers and timers, unfortunately, dbus only supports attaching integers... sub watch_off { delete $O{$_[1]->get_data}; } sub io_toggle { my ($con, $w) = @_; my $id = $w->get_data; my $f = $w->get_flags; my $fd = $w->get_fileno; my $on = $w->is_enabled; $f & Net::DBus::Binding::Watch::READABLE () and $O{$id}[0] = $on && AE::io $fd, 0, sub { $w->handle (Net::DBus::Binding::Watch::READABLE ()); $con->dispatch; }; $f & Net::DBus::Binding::Watch::WRITABLE () and $O{$id}[1] = $on && AE::io $fd, 1, sub { $w->handle (Net::DBus::Binding::Watch::WRITABLE ()); $con->dispatch; }; } sub io_on { my ($con, $w) = @_; my $id = ++$I; $w->set_data ($id); &io_toggle; } sub timeout_toggle { my ($con, $w) = @_; my $id = $w->get_data; my $i = $w->get_interval * 0.001; $O{$id} = $w->is_enabled && AE::timer $i, $i, sub { $w->handle; $con->dispatch; }; } sub timeout_on { my ($con, $w) = @_; my $id = ++$I; $w->set_data ($id); &timeout_toggle; } sub manage { my (undef, $con) = @_; $con->set_watch_callbacks (\&io_on, \&watch_off, \&io_toggle); # if $con->can ("set_watch_callbacks"); $con->set_timeout_callbacks (\&timeout_on, \&watch_off, \&timeout_toggle); # if $con->can ("set_timeout_callbacks"); $con->dispatch; # for good measure } =head1 SEE ALSO L, L. =head1 AUTHOR Marc Lehmann http://home.schmorp.de/ =cut 1