M src/DBus.jl => src/DBus.jl +161 -10
@@ 4,25 4,28 @@ export connect, request_name!
using Dbus_jll
-include("api.jl")
+include("types.jl")
+include("error.jl")
+include("connection.jl")
+include("bus.jl")
+include("message.jl")
+include("pending-call.jl")
const ERROR = Ref{DBusError}()
struct DBusException
title::String
- name::Cstring
- msg::Cstring
+ name::String
+ msg::String
end
function Base.show(io::IO, ex::DBusException)
- name = Base.unsafe_string(ex.name)
- msg = Base.unsafe_string(ex.msg)
- print(io, ex.title, " (", name, "): ", msg)
+ print(io, ex.title, " (", ex.name, "): ", ex.msg)
end
function check(title, error=ERROR)
if dbus_error_is_set(error)
- name = error[].name
- msg = error[].message
+ name = Base.unsafe_string(error[].name)
+ msg = Base.unsafe_string(error[].message)
dbus_error_free(error)
throw(DBusException(title, name, msg))
end
@@ 42,12 45,160 @@ end
function request_name!(conn, name; err=ERROR, strict=false)
ret = dbus_bus_request_name(conn, name, DBUS_NAME_FLAG_REPLACE_EXISTING,
err)
- check("Name Request")
+ check("bus_name_request")
if strict && (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ||
ret != DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER)
error("request_name! failed: $ret")
end
- ret
+ return ret
+end
+function release_name!(conn, name; err=ERROR, strict=false)
+ ret = dbus_bus_release_name(conn, name, err)
+ check("bus_name_release")
+ if strict && ret != DBUS_RELEASE_NAME_REPLY_RELEASED
+ error("release_name! failed: $ret")
+ end
+ return ret
+end
+function name_has_owner(conn, name; err=ERROR)
+ ret = dbus_bus_name_has_owner(conn, name, err)
+ check("bus_name_has_owner")
+ return ret
+end
+function start_service!(conn, name; err=ERROR)
+ reply = Ref{DBusStartServiceByNameReplyFlag}()
+ ret = dbus_bus_start_service_by_name(conn, name, 0, reply, err)
+ check("dbus_bus_start_service_by_name")
+ return (;success=ret, reply=reply[])
+end
+
+dbus_type(x) = error("Invalid DBus type: $x")
+const TYPE_MAP = [
+ Array => DBUS_TYPE_ARRAY,
+ Bool => DBUS_TYPE_BOOLEAN,
+ Union{Int8,UInt8} => DBUS_TYPE_BYTE,
+ Int16 => DBUS_TYPE_INT16,
+ UInt16 => DBUS_TYPE_UINT16,
+ Int32 => DBUS_TYPE_INT32,
+ UInt32 => DBUS_TYPE_UINT32,
+ Int64 => DBUS_TYPE_INT64,
+ UInt64 => DBUS_TYPE_UINT64,
+ Float64 => DBUS_TYPE_DOUBLE,
+ String => DBUS_TYPE_STRING,
+ Ref => DBUS_TYPE_VARIANT,
+]
+for (jltype, dbustype) in TYPE_MAP
+ @eval dbus_type(::Type{$jltype}) = $dbustype
+end
+function julia_type(x::Char)
+ for (jltype, dbustype) in TYPE_MAP
+ if dbustype == x
+ return jltype
+ end
+ end
+ error("Unknown Julia type for DBus type $x")
+end
+dbus_spec(::Type{Vector{T}}) where T = "a$(dbus_spec(T))"
+dbus_spec(::Type{Dict{K,V}}) where {K,V} = "{$(dbus_spec(K))$(dbus_spec(V))}"
+dbus_spec(::Type{T}) where T = string(dbus_type(T))
+dbus_spec(x) = dbus_spec(typeof(x))
+
+function message_write!(msg, args)
+ iter = Ref{DBusMessageIter}()
+ dbus_message_iter_init_append(msg, iter)
+ for arg in args
+ message_iter_write!(iter, arg)
+ end
+end
+function message_iter_write!(iter, arr::Vector{T}) where T
+ arr_iter = Ref{DBusMessageIter}()
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, dbus_spec(T), arr_iter)
+ for arg in arr
+ message_iter_write!(arr_iter, arg)
+ end
+ dbus_message_iter_close_container(iter, arr_iter)
+end
+function message_iter_write!(iter, arg::String)
+ GC.@preserve arg begin
+ arg_ptr = Ref{Cstring}(pointer(arg))
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, arg_ptr)
+ end
+end
+message_iter_write!(iter, arg::T) where {T<:Integer} =
+ dbus_message_iter_append_basic(iter, dbus_type(T), Ref(arg))
+
+function message_read(msg)
+ iter = Ref{DBusMessageIter}()
+ if dbus_message_iter_init(msg, iter)
+ return message_iter_read(iter)
+ end
+end
+message_iter_read(iter) =
+ message_iter_read(julia_type(dbus_message_iter_get_arg_type(iter)), iter)
+function message_iter_read(::Type{Vector{T}}, iter) where T
+ arr_iter = Ref{DBusMessageIter}()
+ dbus_message_iter_recurse(iter, arr_iter)
+ values = T[]
+ while dbus_message_iter_has_next(arr_iter)
+ S = dbus_message_iter_get_arg_type(arr_iter)
+ push!(values, message_iter_read(S, arr_iter))
+ dbus_message_iter_next(arr_iter)
+ end
+ dbus_message_iter_next(iter)
+ return values
+end
+message_iter_read(::Type{String}, iter) =
+ dbus_message_iter_get_basic(iter, String)
+message_iter_read(::Type{T}, iter) where {T<:Integer} =
+ dbus_message_iter_get_basic(iter, T)
+
+function send_recv!(conn, target, object, interface, method, args)
+ pending = Ref{Ptr{DBusPendingCall}}(Ptr{DBusPendingCall}(0))
+
+ # create a new method call and check for errors
+ msg = dbus_message_new_method_call(target, object, interface, method)
+ @assert msg != C_NULL "Failed to allocate new message"
+
+ # append args
+ message_write!(msg, args)
+
+ # send message and get a handle for a reply
+ if !dbus_connection_send_with_reply(conn, msg, pending, -1) # -1 is default timeout
+ error("Out of Memory")
+ end
+ if pending[] == C_NULL
+ error("Pending Call was NULL")
+ end
+ dbus_connection_flush(conn)
+
+ # free message
+ dbus_message_unref(msg)
+
+ # block until we recieve a reply
+ dbus_pending_call_block(pending[])
+
+ # get the reply message
+ msg = dbus_pending_call_steal_reply(pending[])
+ if msg == C_NULL
+ error("Reply was NULL")
+ end
+ # free the pending message handle
+ dbus_pending_call_unref(pending[])
+
+ # read the parameters
+ ret = message_read(msg)
+ err = dbus_message_get_error_name(msg)
+ if err != C_NULL
+ err = Base.unsafe_string(err)
+ end
+
+ # free reply and close connection
+ dbus_message_unref(msg)
+
+ if err isa String
+ error(err * ": " * ret)
+ end
+ return ret
end
function __init__()
D src/api.jl => src/api.jl +0 -53
@@ 1,53 0,0 @@
-struct DBusError
- name::Cstring
- message::Cstring
-
- dummy1::Cuint
- dummy2::Cuint
- dummy3::Cuint
- dummy4::Cuint
- dummy5::Cuint
-
- padding::Ptr{Cvoid}
-end
-
-function dbus_error_init(error)
- ccall((:dbus_error_init, libdbus), Cvoid, (Ptr{DBusError},), error)
-end
-function dbus_error_free(error)
- ccall((:dbus_error_free, libdbus), Cvoid, (Ptr{DBusError},), error)
-end
-function dbus_error_is_set(error)
- ccall((:dbus_error_is_set, libdbus), Cint, (Ptr{DBusError},), error) != 0
-end
-
-const DBusConnection = Cvoid
-@enum DBusBusType begin
- DBUS_BUS_SESSION = Cint(0)
- DBUS_BUS_SYSTEM = Cint(1)
- DBUS_BUS_STARTER = Cint(2)
-end
-@enum DBusNameFlag begin
- DBUS_NAME_FLAG_ALLOW_REPLACEMENT = Cuint(1)
- DBUS_NAME_FLAG_REPLACE_EXISTING = Cuint(2)
- DBUS_NAME_FLAG_DO_NOT_QUEUE = Cuint(4)
-end
-@enum DBusRequestNameReplyFlag begin
- DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = Cuint(1)
- DBUS_REQUEST_NAME_REPLY_IN_QUEUE = Cuint(2)
- DBUS_REQUEST_NAME_REPLY_EXISTS = Cuint(3)
- DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER = Cuint(4)
-end
-
-function dbus_bus_get(bus_type::DBusBusType, error)
- ccall((:dbus_bus_get, libdbus), Ptr{DBusConnection}, (DBusBusType, Ptr{DBusError},), bus_type, error)
-end
-function dbus_connection_close(conn)
- ccall((:dbus_connection_close, libdbus), Cvoid, (Ptr{DBusConnection},), conn)
-end
-function dbus_bus_request_name(conn, name, flag, error)
- ccall((:dbus_bus_request_name, libdbus),
- DBusRequestNameReplyFlag,
- (Ptr{DBusConnection}, Cstring, DBusNameFlag, Ptr{DBusError}),
- conn, name, flag, error)
-end
A src/bus.jl => src/bus.jl +28 -0
@@ 0,0 1,28 @@
+function dbus_bus_get(bus_type::DBusBusType, error)
+ ccall((:dbus_bus_get, libdbus), Ptr{DBusConnection}, (DBusBusType, Ptr{DBusError},), bus_type, error)
+end
+function dbus_bus_request_name(conn, name, flag, error)
+ ccall((:dbus_bus_request_name, libdbus),
+ DBusRequestNameReplyFlag,
+ (Ptr{DBusConnection}, Cstring, DBusNameFlag, Ptr{DBusError}),
+ conn, name, flag, error)
+end
+function dbus_bus_release_name(conn, name, error)
+ ccall((:dbus_bus_release_name, libdbus),
+ DBusReleaseNameReplyFlag,
+ (Ptr{DBusConnection}, Cstring, Ptr{DBusError}),
+ conn, name, error)
+end
+function dbus_bus_name_has_owner(conn, name, error)
+ ccall((:dbus_bus_name_has_owner, libdbus),
+ Bool,
+ (Ptr{DBusConnection}, Cstring, Ptr{DBusError}),
+ conn, name, error)
+end
+function dbus_bus_start_service_by_name(conn, name, flags, reply, error)
+ ccall((:dbus_bus_start_service_by_name, libdbus),
+ Bool,
+ (Ptr{DBusConnection}, Cstring, UInt32,
+ Ptr{DBusStartServiceByNameReplyFlag}, Ptr{DBusError}),
+ conn, name, flags, reply, error)
+end
A src/connection.jl => src/connection.jl +12 -0
@@ 0,0 1,12 @@
+function dbus_connection_close(conn)
+ ccall((:dbus_connection_close, libdbus), Cvoid, (Ptr{DBusConnection},), conn)
+end
+function dbus_connection_flush(conn)
+ ccall((:dbus_connection_flush, libdbus), Cvoid, (Ptr{DBusConnection},), conn)
+end
+function dbus_connection_send_with_reply(conn, msg, pending, timeout)
+ ccall((:dbus_connection_send_with_reply, libdbus),
+ Bool,
+ (Ptr{DBusConnection}, Ptr{DBusMessage}, Ptr{Ptr{DBusPendingCall}}, Cint),
+ conn, msg, pending, timeout)
+end
A src/error.jl => src/error.jl +9 -0
@@ 0,0 1,9 @@
+function dbus_error_init(error)
+ ccall((:dbus_error_init, libdbus), Cvoid, (Ptr{DBusError},), error)
+end
+function dbus_error_free(error)
+ ccall((:dbus_error_free, libdbus), Cvoid, (Ptr{DBusError},), error)
+end
+function dbus_error_is_set(error)
+ ccall((:dbus_error_is_set, libdbus), Cint, (Ptr{DBusError},), error) != 0
+end
A src/message.jl => src/message.jl +55 -0
@@ 0,0 1,55 @@
+function dbus_message_iter_init(msg, iter)
+ ccall((:dbus_message_iter_init, libdbus),
+ Bool, (Ptr{DBusMessage}, Ptr{DBusMessageIter},), msg, iter)
+end
+function dbus_message_iter_init_append(msg, iter)
+ ccall((:dbus_message_iter_init_append, libdbus),
+ Bool,
+ (Ptr{DBusMessage}, Ptr{DBusMessageIter}),
+ msg, iter)
+end
+function dbus_message_iter_get_arg_type(iter)
+ Char(ccall((:dbus_message_iter_get_arg_type, libdbus),
+ UInt8, (Ptr{DBusMessageIter},), iter))
+end
+function dbus_message_iter_get_basic(iter, T)
+ ref = Ref{UInt64}()
+ ccall((:dbus_message_iter_get_basic, libdbus),
+ Cvoid, (Ptr{DBusMessageIter}, Ptr{UInt64}), iter, ref)
+ if T === String
+ return unsafe_string(Ptr{Cchar}(ref[]))
+ else
+ return unsafe_trunc(T, ref[])
+ end
+end
+function dbus_message_iter_append_basic(iter, type, arg)
+ ccall((:dbus_message_iter_append_basic, libdbus),
+ UInt64, (Ptr{DBusMessageIter}, UInt8, Ptr{Cvoid}),
+ iter, UInt8(type), arg)
+end
+function dbus_message_iter_open_container(iter, type, spec, inner_iter)
+ ccall((:dbus_message_iter_open_container, libdbus),
+ Cvoid,
+ (Ptr{DBusMessageIter}, UInt8, Cstring, Ptr{DBusMessageIter}),
+ iter, UInt8(type), spec, inner_iter)
+end
+function dbus_message_iter_close_container(iter, inner_iter)
+ ccall((:dbus_message_iter_close_container, libdbus),
+ Cvoid,
+ (Ptr{DBusMessageIter}, Ptr{DBusMessageIter}),
+ iter, inner_iter)
+end
+
+function dbus_message_new_method_call(target, object, interface, method)
+ ccall((:dbus_message_new_method_call, libdbus),
+ Ptr{DBusMessage},
+ (Cstring, Cstring, Cstring, Cstring),
+ target, object, interface, method)
+end
+function dbus_message_unref(msg)
+ ccall((:dbus_message_unref, libdbus), Bool, (Ptr{DBusMessage},), msg)
+end
+function dbus_message_get_error_name(msg)
+ ccall((:dbus_message_get_error_name, libdbus),
+ Cstring, (Ptr{DBusMessage},), msg)
+end
A src/pending-call.jl => src/pending-call.jl +12 -0
@@ 0,0 1,12 @@
+function dbus_pending_call_block(pending)
+ ccall((:dbus_pending_call_block, libdbus),
+ Cvoid, (Ptr{DBusPendingCall},), pending)
+end
+function dbus_pending_call_unref(pending)
+ ccall((:dbus_pending_call_unref, libdbus),
+ Cvoid, (Ptr{DBusPendingCall},), pending)
+end
+function dbus_pending_call_steal_reply(pending)
+ ccall((:dbus_pending_call_steal_reply, libdbus),
+ Ptr{DBusMessage}, (Ptr{DBusPendingCall},), pending)
+end
A src/types.jl => src/types.jl +85 -0
@@ 0,0 1,85 @@
+struct DBusError
+ name::Cstring
+ message::Cstring
+
+ dummy1::Cuint
+ dummy2::Cuint
+ dummy3::Cuint
+ dummy4::Cuint
+ dummy5::Cuint
+
+ padding::Ptr{Cvoid}
+end
+
+const DBusConnection = Cvoid
+
+@enum DBusBusType begin
+ DBUS_BUS_SESSION = Cint(0)
+ DBUS_BUS_SYSTEM = Cint(1)
+ DBUS_BUS_STARTER = Cint(2)
+end
+@enum DBusNameFlag begin
+ DBUS_NAME_FLAG_ALLOW_REPLACEMENT = Cuint(1)
+ DBUS_NAME_FLAG_REPLACE_EXISTING = Cuint(2)
+ DBUS_NAME_FLAG_DO_NOT_QUEUE = Cuint(4)
+end
+@enum DBusRequestNameReplyFlag begin
+ DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = Cuint(1)
+ DBUS_REQUEST_NAME_REPLY_IN_QUEUE = Cuint(2)
+ DBUS_REQUEST_NAME_REPLY_EXISTS = Cuint(3)
+ DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER = Cuint(4)
+end
+@enum DBusReleaseNameReplyFlag begin
+ DBUS_RELEASE_NAME_REPLY_RELEASED = Cuint(1)
+ DBUS_RELEASE_NAME_REPLY_NON_EXISTENT = Cuint(2)
+ DBUS_RELEASE_NAME_REPLY_NOT_OWNER = Cuint(3)
+end
+@enum DBusStartServiceByNameReplyFlag begin
+ DBUS_START_REPLY_SUCCESS = Cuint(1)
+ DBUS_START_REPLY_ALREADY_RUNNING = Cuint(2)
+end
+
+const DBusMessage = Cvoid
+struct DBusMessageIter
+ dummy1::Ptr{Cvoid}
+ dummy2::Ptr{Cvoid}
+ dummy3::UInt32
+ dummy4::Cint
+ dummy5::Cint
+ dummy6::Cint
+ dummy7::Cint
+ dummy8::Cint
+ dummy9::Cint
+ dummy10::Cint
+ dummy11::Cint
+ pad1::Cint
+ pad2::Ptr{Cvoid}
+ pad3::Ptr{Cvoid}
+end
+
+const DBusPendingCall = Cvoid
+
+const DBUS_NUMBER_OF_TYPES = 16
+
+const DBUS_TYPE_INVALID = Char(0)
+const DBUS_TYPE_BYTE = 'y'
+const DBUS_TYPE_BOOLEAN = 'b'
+const DBUS_TYPE_INT16 = 'n'
+const DBUS_TYPE_UINT16 = 'q'
+const DBUS_TYPE_INT32 = 'i'
+const DBUS_TYPE_UINT32 = 'u'
+const DBUS_TYPE_INT64 = 'x'
+const DBUS_TYPE_UINT64 = 't'
+const DBUS_TYPE_DOUBLE = 'd'
+const DBUS_TYPE_STRING = 's'
+const DBUS_TYPE_OBJECT_PATH = 'o'
+const DBUS_TYPE_SIGNATURE = 'g'
+const DBUS_TYPE_UNIX_FD = 'h'
+const DBUS_TYPE_ARRAY = 'a'
+const DBUS_TYPE_VARIANT = 'v'
+const DBUS_TYPE_STRUCT = 'r'
+const DBUS_TYPE_DICT_ENTRY = 'e'
+const DBUS_STRUCT_BEGIN_CHAR = '('
+const DBUS_STRUCT_END_CHAR = ')'
+const DBUS_DICT_ENTRY_BEGIN_CHAR = '{'
+const DBUS_DICT_ENTRY_END_CHAR = '}'