Inkscape.org
Creating New Extensions More DBUS from within an extension
  1. #1
    gropiuswasright gropiuswasright @gropiuswasright
    *

    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()

     

  2. #2
    inklinea inklinea @inklinea⛰️

    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.

  3. #3
    gropiuswasright gropiuswasright @gropiuswasright
    *

    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?

Inkscape Inkscape.org Inkscape Forum Creating New Extensions More DBUS from within an extension