pythondbus

Trying to access Inkscape from d-bus fails (but works with Gio)


I am trying to use dbus to drive Inkscape from scripts

This code - which I got from here - works ok:


#  Start after inkscape is running.
print ("DBus test")

import gi

gi.require_version("Gio", "2.0")
from gi.repository import Gio, GLib

try:
   bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)

except BaseException:
   print("No DBus bus")
   exit()

print ("Got DBus bus")

proxy = Gio.DBusProxy.new_sync(bus, Gio.DBusProxyFlags.NONE, None,
                              'org.freedesktop.DBus',
                              '/org/freedesktop/DBus',
                              'org.freedesktop.DBus', None)

names_list = proxy.call_sync('ListNames', None, Gio.DBusCallFlags.NO_AUTO_START, 500, None)

# names_list is a GVariant, must unpack

names = names_list.unpack()[0]

# Look for Inkscape; names is a tuple.

for name in names:
   if ('org.inkscape.Inkscape' in name):
       print ("Found: " + name)
       break

print ("Name: " + name)

appGroupName = "/org/inkscape/Inkscape"
winGroupName = appGroupName + "/window/1"
docGroupName = appGroupName + "/document/1"

applicationGroup = Gio.DBusActionGroup.get( bus, name, appGroupName)
windowGroup = Gio.DBusActionGroup.get(bus, name, winGroupName)
documentGroup = Gio.DBusActionGroup.get(bus, name, docGroupName)

# Activate actions. Draw a few objects first.

applicationGroup.activate_action('select-all', GLib.Variant.new_string('all'))
applicationGroup.activate_action('object-rotate-90-cw', None)

windowGroup.activate_action('tool-switch', GLib.Variant.new_string('Arc'))
windowGroup.activate_action('canvas-zoom-page', None)

When I try to translate it to use dbuslike this:

#!/usr/bin/env python

# Start after Inkscape is running.

import dbus
from xml.etree import ElementTree as ET

print("DBus test")

try:
    # Connect to the session bus
    bus = dbus.SessionBus()
except dbus.exceptions.DBusException as e:
    print(f"No DBus bus: {e}")
    exit()

print("Got DBus bus")

# Get the list of names on the bus
proxy = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
interface = dbus.Interface(proxy, 'org.freedesktop.DBus')
names = interface.ListNames()

# Look for Inkscape
name = None
for n in names:
    if 'org.inkscape.Inkscape' in n:
        name = n
        print(f"Found: {name}")
        break

if not name:
    print("Inkscape not found")
    exit()

print(f"Name: {name}")

appGroupName = "/org/inkscape/Inkscape"
winGroupName = appGroupName + "/window/1"
docGroupName = appGroupName + "/document/1"

def activate_action(group, action, parameter=None):
    try:
        group.Activate(action, parameter, dbus_interface='org.gtk.Actions')
        print(f"Activated action: {action} with parameter: {parameter}")
    except dbus.exceptions.DBusException as e:
        print(f"Failed to activate action {action}: {e}")

applicationGroup = bus.get_object(name, appGroupName)
windowGroup = bus.get_object(name, winGroupName)
documentGroup = bus.get_object(name, docGroupName)

# Activate actions. Draw a few objects first.
activate_action(applicationGroup, 'select-all', 'all')
activate_action(applicationGroup, 'object-rotate-90-cw')

it fails with this message:

ERROR:dbus.connection:Unable to set arguments ('select-all', 'all') according to signature 'sava{sv}': <class 'TypeError'>: More items found in D-Bus signature than in Python arguments
Traceback (most recent call last):
  File "/home/simone/inkscape_experiments/dbus_05.py", line 54, in <module>
    activate_action(applicationGroup, 'select-all', 'all')
  File "/home/simone/inkscape_experiments/dbus_05.py", line 44, in activate_action
    group.Activate(action, parameter, dbus_interface='org.gtk.Actions')
  File "/usr/lib/python3/dist-packages/dbus/proxies.py", line 72, in __call__
    return self._proxy_method(*args, **keywords)
  File "/usr/lib/python3/dist-packages/dbus/proxies.py", line 141, in __call__
    return self._connection.call_blocking(self._named_service,
  File "/usr/lib/python3/dist-packages/dbus/connection.py", line 643, in call_blocking
    message.append(signature=signature, *args)
TypeError: More items found in D-Bus signature than in Python arguments

What's the issue here? is there a way to inspect d-bus signatures and use that to call things correctly?


Solution

  • Error shows signature 'sava{sv}'.

    I found

    And all of this may suggest that 'sava{sv}' means 's,av,a{sv}' and it may need:
    String, Array of Variants (list), Array of Strings and Variants (dict)

    group.Activate(String, [Variant, ...], {String:Variant, ...})
    

    So I tested

    group.Activate('select-all', ['all'], {}, dbus_interface='org.gtk.Actions')
    group.Activate('object-rotate-90-cw', [], {}, dbus_interface='org.gtk.Actions')
    

    And it works for me.


    Finally I created function with *args and **kwargs

    def activate_action(group, action, *args, **kwargs):  # with * and **
        try:
            # without * and ** to keep it as list and dict
            group.Activate(action, args, kwargs, dbus_interface='org.gtk.Actions')
            print(f"Activated action: {action} with parameters: args:{args} kwargs:{kwargs}")
        except dbus.exceptions.DBusException as e:
            print(f"Failed to activate action {action}: {e}")
    
    
    activate_action(applicationGroup, 'select-all', 'all')
    activate_action(applicationGroup, 'object-rotate-90-cw')