I'm trying to see if it's possible to use DBus from within an extension and how.
I'm making progress with some things, but I am blocked with others.
in the code below, I manage to execute some commands both at the application and at the window level, but cannot manage to get inkscape to save the current document somewhere. This would be useful for other type of things, such as daemonizing this process and have it happen every x seconds without blocking (more about this at some point).
Is there a way to use Inkscape to transparently save a document? and how do I pass arguments to dbus functions that seem to want more complex things?
import inkex import dbus import sys import os import warnings import time import builtins
import gi import json gi.require_version("Gio", "2.0") gi.require_version("GLib", "2.0") from gi.repository import Gio, GLib
from inkex import etree
class Logger(): def el_to_str(self, element): """Convert an Inkex BaseElement or etree element to a string.""" if isinstance(element, etree._Element): return etree.tostring(element, pretty_print=True).decode() return str(element) def log(self, *args, **kwargs): try: with open('/dev/tty', 'w') as tty: # Convert BaseElement or etree._Element instances to XML strings converted_args = [ self.el_to_str(arg) if isinstance(arg, inkex.elements._base.BaseElement) else arg for arg in args ] print(*converted_args, file=tty, **kwargs) except Exception as e: print(e, file=sys.stderr)
class DBUSTestExtension(inkex.EffectExtension, Logger): def __init__(self): super().__init__() self.log("{} running in {}".format(self.__class__.__name__, __file__ )) with warnings.catch_warnings(): warnings.simplefilter('ignore', category=ImportWarning) _oldprint = builtins.print builtins.print = lambda *args, **kwargsx: None # def print(s): pass
import gi gi.require_version("Gio", "2.0") from gi.repository import Gio, GLib
globals()['GLib'] = GLib
try: bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) except BaseException: exit()
def effect(self): self.log("{} running in {}".format(self.__class__.__name__, __file__ )) # self.log(self.application_group)
self.log("-" * 96) # -------------------------------------------------------------- # these all work # -------------------------------------------------------------- self.application_group.activate_action('select-all', GLib.Variant.new_string("all")) self.application_group.activate_action('copy') self.application_group.activate_action('object-rotate-90-cw') self.window_group.activate_action('paste') # this works
# -------------------------------------------------------------- # none of these work: they do nothing and generate an error # (org.inkscape.Inkscape:60441): GLib-GIO-CRITICAL **: 10:20:28.339: g_simple_action_activate: assertion 'simple->parameter_type == NULL ? parameter == NULL : (parameter != NULL && g_variant_is_of_type (parameter, simple->parameter_type))' failed
I'm trying to see if it's possible to use DBus from within an extension and how.
I'm making progress with some things, but I am blocked with others.
in the code below, I manage to execute some commands both at the application and at the window level, but cannot manage to get inkscape to save the current document somewhere. This would be useful for other type of things, such as daemonizing this process and have it happen every x seconds without blocking (more about this at some point).
Is there a way to use Inkscape to transparently save a document? and how do I pass arguments to dbus functions that seem to want more complex things?
import inkex
import dbus
import sys
import os
import warnings
import time
import builtins
import gi
import json
gi.require_version("Gio", "2.0")
gi.require_version("GLib", "2.0")
from gi.repository import Gio, GLib
from inkex import etree
class Logger():
def el_to_str(self, element):
"""Convert an Inkex BaseElement or etree element to a string."""
if isinstance(element, etree._Element):
return etree.tostring(element, pretty_print=True).decode()
return str(element)
def log(self, *args, **kwargs):
try:
with open('/dev/tty', 'w') as tty:
# Convert BaseElement or etree._Element instances to XML strings
converted_args = [
self.el_to_str(arg) if isinstance(arg, inkex.elements._base.BaseElement) else arg
for arg in args
]
print(*converted_args, file=tty, **kwargs)
except Exception as e:
print(e, file=sys.stderr)
class DBUSTestExtension(inkex.EffectExtension, Logger):
def __init__(self):
super().__init__()
self.log("{} running in {}".format(self.__class__.__name__, __file__ ))
with warnings.catch_warnings():
warnings.simplefilter('ignore', category=ImportWarning)
_oldprint = builtins.print
builtins.print = lambda *args, **kwargsx: None
# def print(s): pass
import gi
gi.require_version("Gio", "2.0")
from gi.repository import Gio, GLib
globals()['GLib'] = GLib
try:
bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
except BaseException:
exit()
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 = names_list.unpack()[0]
for name in names:
if ('org.inkscape.Inkscape' in name): break
app_group_name = "/org/inkscape/Inkscape"
win_group_name = app_group_name + "/window/1"
doc_group_name = app_group_name + "/document/1"
self.log(win_group_name)
self.log(doc_group_name)
application_group = Gio.DBusActionGroup.get( bus, name, app_group_name)
window_group = Gio.DBusActionGroup.get(bus, name, win_group_name)
document_group = Gio.DBusActionGroup.get(bus, name, doc_group_name)
self.bus = bus
self.application_group = application_group
self.window_group = window_group
self.document_group = document_group
builtins.print = _oldprint
def effect(self):
self.log("{} running in {}".format(self.__class__.__name__, __file__ ))
# self.log(self.application_group)
self.log("-" * 96)
# --------------------------------------------------------------
# these all work
# --------------------------------------------------------------
self.application_group.activate_action('select-all', GLib.Variant.new_string("all"))
self.application_group.activate_action('copy')
self.application_group.activate_action('object-rotate-90-cw')
self.window_group.activate_action('paste') # this works
# --------------------------------------------------------------
# none of these work: they do nothing and generate an error
# (org.inkscape.Inkscape:60441): GLib-GIO-CRITICAL **: 10:20:28.339: g_simple_action_activate: assertion 'simple->parameter_type == NULL ? parameter == NULL : (parameter != NULL && g_variant_is_of_type (parameter, simple->parameter_type))' failed
# --------------------------------------------------------------
self.window_group.activate_action('document-save-as', GLib.Variant.new_string("/home/simone/dbus_foobar.svg"))
self.window_group.activate_action('document-save-as', GLib.Variant('a{sv}', {'filename': GLib.Variant('s', "/home/simone/output.svg")}))
self.log(self.window_group)
self.log("-" * 96)
if __name__ == '__main__':
DBUSTestExtension().run()
It follows the same pattern as on the command line.
export-filename
export-do
It's that simple.
However, it's import to understand that this is the current state of the gui document.
If you are combining dbus commands with standard extension code, until the extension returns the svg back to the gui, export cannot 'see' it.
Thanks @inklinea for your answer!
I did get it to work like this:
self.application_group.activate_action('export-filename', GLib.Variant.new_string("/home/gropius/dbus_foobar.svg"))
self.application_group.activate_action('export-do')
however - for the sake of knowledge - do you know why this:
self.window_group.activate_action('document-save-as', GLib.Variant.new_string("/home/simone/dbus_foobar.svg"))
does not work?
It's not the window group when this:
self.window_group.activate_action('paste')
works - so what is it?