#!/usr/bin/python
# demo D-Bus server using GDBus
# (C) 2010 Martin Pitt <martin@piware.de>

# manual tests (when greatly increasing the last g_timeout_add):
# gdbus introspect -e -d de.piware.Demo -o / -x
# gdbus call -e -d de.piware.Demo -o / -m de.piware.Demo.Hello.hello Martin
# gdbus call -e -d de.piware.Demo -o / -m org.freedesktop.DBus.Properties.GetAll de.piware.Demo.Hello

from gi.repository import GObject
from gi.repository import Gio
from gi.repository import GLib
import subprocess

introspection_xml = '''
<node>
  <interface name='de.piware.Demo.Hello'>
    <method name='hello'>
      <arg type='s' name='greeting' direction='in'/>
      <arg type='s' name='response' direction='out'/>
    </method>
    <property type='i' name='number' access='readwrite'/>"
  </interface>
</node>'''

prop_number = 42

def method_call(conn, sender, object_path, iface_name, method_name, parameters,
        invocation, user_data):
    print 'method call: %s %s.%s(%s)' % (object_path, iface_name, method_name, str(parameters))

    name = parameters.unpack()[0]
    if name == 'error':
        invocation.return_error_literal(Gio.dbus_error_quark(), 
                Gio.DBusError.IO_ERROR,
                'Raising an error as requested')
    else:
        invocation.return_value(GLib.Variant('(s)', ('Good day %s' % name,)))

def get_property(conn, sender, object_path, iface_name, prop_name, error, user_data):
    print 'get_property: %s %s %s' % (object_path, iface_name, prop_name)
    print 'user data:', user_data
    return GLib.Variant('(i)', (prop_number,))

def set_property(conn, sender, object_path, iface_name, prop_name, value, error, user_data):
    print 'set_property: %s %s %s = %s' % (object_path, iface_name, prop_name, str(value))
    print 'user data:', user_data
    global prop_number
    prop_number = value.unpack()
    return True

def bus_acquired(conn, name):
    print 'bus_acquired:', conn, name

    vtable = Gio.DBusInterfaceVTable.new()
    vtable.set_method_call(method_call)
    vtable.set_get_property(get_property)
    vtable.set_set_property(set_property)

    node_info = Gio.DBusNodeInfo.new_for_xml(introspection_xml)

    s = GLib.String()
    node_info.generate_xml(4, s)
    print '--- XML: ---\n%s\n-------' % s.str
    s.free(True)

    iface_info = node_info.lookup_interface('de.piware.Demo.Hello')

    global reg_id
    global acquired_conn

    acquired_conn = conn
    reg_id = conn.register_object('/', iface_info, vtable, None,
            (lambda *args: None), # workaround for gbo#655051
            )
    print 'registered object id', reg_id

def name_acquired(conn, name):
    print 'name_acquired:', conn, name

def name_lost(conn, name):
    print 'name_lost:', conn, name

def send_request(arg):
    print '\n----- sending request hello("%s") -------' % arg
    subprocess.Popen(['gdbus', 'call', '-e', '-d', 'de.piware.Demo', '-o', '/',
        '-m', 'de.piware.Demo.Hello.hello', arg])
    return False

def send_property_get():
    print '\n----- sending property get -------'
    subprocess.Popen(['gdbus', 'call', '-e', '-d', 'de.piware.Demo', '-o', '/',
        '-m', 'org.freedesktop.DBus.Properties.Get', 'de.piware.Demo.Hello', 'number'])
    return False

def send_property_set():
    print '\n----- sending property set -------'
    subprocess.Popen(['dbus-send', '--print-reply', '--dest=de.piware.Demo',
            '/', 'org.freedesktop.DBus.Properties.Set',
            'string:de.piware.Demo.Hello', 'string:number',
            'variant:int32:99'])
    return False

#
# main
#

bus_id = Gio.bus_own_name(Gio.BusType.SESSION, 'de.piware.Demo',
        Gio.BusNameOwnerFlags.NONE, bus_acquired, name_acquired, name_lost)
print 'bus_own_name done:', bus_id

# now send some requests to check the result
ml = GObject.MainLoop()
GObject.timeout_add(2000, send_request, 'Martin')
GObject.timeout_add(3000, send_request, 'error')
GObject.timeout_add(4000, send_property_get)
GObject.timeout_add(5000, send_property_set)
GObject.timeout_add(6000, send_property_get)
GObject.timeout_add(7000, ml.quit)
ml.run()

print 'unregistering object...'
acquired_conn.unregister_object(reg_id)
GObject.timeout_add(1000, ml.quit)
ml.run()

print 'unowning bus name...'
Gio.bus_unown_name(bus_id)
GObject.timeout_add(1000, ml.quit)
ml.run()
