1#!/usr/local/bin/python3.8 2 3from gi.repository import GLib, Gio 4import sys 5import signal 6 7from xml.etree import ElementTree 8 9signal.signal(signal.SIGINT, signal.SIG_DFL) 10 11class MethodArg: 12 def __init__(self, method, arg_index, arg_type): 13 self.method = method 14 self.arg_index = arg_index 15 self.arg_type = arg_type 16 17class CinnamonDBusCommand: 18 def __init__(self, mainloop): 19 self.mainloop = mainloop 20 21 try: 22 self.cinnamon_proxy = Gio.DBusProxy.new_for_bus_sync(Gio.BusType.SESSION, 23 Gio.DBusProxyFlags.NONE, 24 None, 25 "org.Cinnamon", 26 "/org/Cinnamon", 27 "org.Cinnamon", 28 None) 29 except GLib.Error: 30 self.cinnamon_proxy = None 31 print("Cannot acquire org.Cinnamon proxy") 32 33 introspection_info = Gio.DBusConnection.call_sync(Gio.bus_get_sync(Gio.BusType.SESSION), 34 "org.Cinnamon", 35 "/org/Cinnamon", 36 "org.freedesktop.DBus.Introspectable", 37 "Introspect", 38 None, 39 GLib.VariantType(type_string="(s)"), 40 0, 41 -1, 42 None) 43 44 unpacked = introspection_info.unpack()[0] 45 self.tree = ElementTree.fromstring(unpacked) 46 47 self.arg_list = [] 48 list_methods = False 49 50 if len(sys.argv) < 2: 51 list_methods = True 52 print("\nProvide a method name and any parameters. Available commands are:\n") 53 54 for interface in self.tree: 55 if interface.attrib["name"] == "org.Cinnamon": 56 for entry in interface: 57 if entry.tag != "method": 58 continue 59 arg_str = "" 60 61 i = 0 62 63 for arg in entry: 64 if arg.attrib["direction"] != "in": 65 continue 66 67 if list_methods: 68 arg_str += "--- %s ('%s') " % (arg.attrib["name"], arg.attrib["type"]) 69 70 self.arg_list.append(MethodArg(entry.attrib["name"], i, arg.attrib["type"])) 71 i += 1 72 73 if list_methods: 74 print("%s %s" % (entry.attrib["name"], arg_str)) 75 76 if list_methods: 77 print("\nNote: boolean arguments should be specified as 0 (false) and 1 (true)") 78 print("\nAn example is: cinnamon-dbus-command GetMonitorWorkRect 0\n") 79 exit(1) 80 81 self.parse_command(sys.argv[1:]) 82 83 def method_call_finished_callback(self, proxy, result, data=None): 84 try: 85 variant = proxy.call_finish(result) 86 print("Returned: %s" % str(variant.unpack())) 87 except GLib.Error as e: 88 print("An error occurred attempting to run the command: %s" % e.message) 89 90 self.mainloop.quit() 91 92 def parse_command(self, args): 93 method_name = args[0] 94 95 parameters = self.build_variant(method_name, args[1:]) 96 97 try: 98 self.cinnamon_proxy.call(method_name, 99 parameters, 100 0, 101 -1, 102 None, 103 self.method_call_finished_callback, 104 None) 105 except TypeError as e: 106 print("Could not send command over the bus: %s" % str(e)) 107 exit(1) 108 109 def build_variant(self, method_name, in_args): 110 i = 0 111 112 variant_string = "(" 113 114 while i < len(in_args): 115 arg = in_args[i] 116 117 arg_info = self.lookup_arg(method_name, i) 118 119 if arg_info: 120 variant_string += arg_info.arg_type 121 else: 122 print("The parameter '%s' seems invalid for method '%s'" % (arg, method_name)) 123 exit(1) 124 125 i += 1 126 127 variant_string += ")" 128 129 parsed_args = [] 130 for arg_as_str in in_args: 131 try: 132 parsed_args.append(eval(arg_as_str)) 133 except: 134 parsed_args.append(arg_as_str) 135 136 print("Parsed: %s(format_string='%s', args=%s)\n" % (method_name, variant_string, parsed_args)) 137 138 try: 139 variant = GLib.Variant(variant_string, tuple(parsed_args)) 140 except TypeError as e: 141 print("Could not construct argument variant for method: %s" % str(e)) 142 exit(1) 143 144 return variant 145 146 def lookup_arg(self, method_name, index): 147 for arg in self.arg_list: 148 if arg.method == method_name and arg.arg_index == index: 149 return arg 150 151 return None 152 153if __name__ == "__main__": 154 ml = GLib.MainLoop.new(None, True) 155 main = CinnamonDBusCommand(ml) 156 157 ml.run() 158