def CreateDevice(self, adapter_path, address, pair, time, _ok, err): def ok(device): _ok(device) self.RefreshServices(device, (lambda *args: None), (lambda *args: None)) if self.Applet.Manager: adapter = Adapter(adapter_path) if pair: agent_path = "/org/blueman/agent/temp/" + address.replace( ":", "") agent = TempAgent(self.Applet.Plugins.StatusIcon, agent_path, time) adapter.GetInterface().CreatePairedDevice(address, agent_path, "DisplayYesNo", error_handler=err, reply_handler=ok, timeout=120) else: adapter.GetInterface().CreateDevice(address, error_handler=err, reply_handler=ok, timeout=120) else: err()
def __init__(self, instance): GObject.GObject.__init__(self) self.Properties = {} self.Temp = False if hasattr(instance, "format") and hasattr(instance, "upper"): self.Device = BluezDevice(instance) else: self.Device = instance #set fallback icon, fixes lp:#327718 self.Device.Icon = "blueman" self.Device.Class = "unknown" self.Valid = True dprint("caching initial properties") self.Properties = self.Device.get_properties() w = weakref.ref(self) self._obj_path = self.Device.get_object_path() self.Device.connect_signal('property-changed', lambda _device, key, value: w() and w().property_changed(key, value)) self._any_adapter = Adapter() self._any_adapter.connect_signal('device-removed', lambda _adapter, path: w() and w().on_device_removed(path))
def on_adapter_added(self, _manager, adapter_path): adapter = Adapter(obj_path=adapter_path) menu = self.item_adapter.get_submenu() object_path = adapter.get_object_path() item = Gtk.RadioMenuItem.new_with_label(self._adapters_group, adapter.get_name()) item.show() self._adapters_group = item.get_group() self._itemhandler = item.connect("activate", self.on_adapter_selected, object_path) self._adapterhandler = adapter.connect_signal( "property-changed", self.on_adapter_property_changed) menu.insert(item, self._insert_adapter_item_pos) self._insert_adapter_item_pos += 1 self.adapter_items[object_path] = (item, adapter) if adapter_path == self.blueman.List.Adapter.get_object_path(): item.props.active = True if len(self.adapter_items) > 0: self.item_adapter.props.sensitive = True
def CancelDeviceCreation(self, adapter_path, address, ok, err): # BlueZ 4 only! if self.Applet.Manager: adapter = Adapter(adapter_path) adapter.get_interface().CancelDeviceCreation(address, error_handler=err, reply_handler=ok) else: err()
def list_adapters(self): if self.__class__.get_interface_version()[0] < 5: adapters = self.get_interface().ListAdapters() return [Adapter(adapter) for adapter in adapters] else: objects = self.get_interface().GetManagedObjects() adapters = [] for path, interfaces in objects.items(): if 'org.bluez.Adapter1' in interfaces: adapters.append(path) return [Adapter(adapter) for adapter in adapters]
def list_adapters(self): objects = self._call('GetManagedObjects') adapters = [] for path, interfaces in objects.items(): if 'org.bluez.Adapter1' in interfaces: adapters.append(path) return [Adapter(adapter) for adapter in adapters]
def connect(self, reply_handler=None, error_handler=None): channel = get_rfcomm_channel(self.short_uuid, self.device['Address']) if channel == 0: error = RFCOMMError("Failed to get rfcomm channel") if error_handler: error_handler(error) return True else: raise error try: port_id = create_rfcomm_device( Adapter(self.device["Adapter"])['Address'], self.device["Address"], channel) filename = '/dev/rfcomm%d' % port_id logging.info('Starting rfcomm watcher as root') Mechanism().open_rfcomm('(d)', port_id) mon = Gio.File.new_for_path(filename).monitor_file( Gio.FileMonitorFlags.NONE) self.file_changed_handler = mon.connect('changed', self.on_file_changed, port_id) self.try_replace_root_watcher(mon, filename, port_id) if reply_handler: reply_handler(filename) except RFCOMMError as e: if error_handler: error_handler(e) else: raise e return True
def on_adapter_added(self, _manager, adapter_path): hci_dev = os.path.basename(adapter_path) if hci_dev not in self._adapters: self._adapters[hci_dev] = Adapter(obj_path=adapter_path) self._adapters[hci_dev].connect_signal("property-changed", self.on_property_changed) self.add_to_notebook(self._adapters[hci_dev])
def notify(self, object_path, uuid): device = Device(object_path) logging.info("%s %s" % (device, uuid)) item = {} try: adapter = Adapter(device['Adapter']) except: logging.warning("adapter not found") return item["adapter"] = adapter["Address"] item["address"] = device['Address'] item["alias"] = device['Alias'] item["icon"] = device['Icon'] item["name"] = ServiceUUID(uuid).name item["uuid"] = uuid item["time"] = time.time() item["device"] = object_path item["mitem"] = None #menu item object for i in self.items: if i["adapter"] == item["adapter"] and \ i["address"] == item["address"] and \ i["uuid"] == item["uuid"]: i["time"] = item["time"] i["device"] = item["device"] self.initialize() return self.items.append(item) self.initialize() self.store_state()
def connect( self, reply_handler: Optional[Callable[[int], None]] = None, error_handler: Optional[Callable[[RFCOMMError], None]] = None ) -> bool: # We expect this service to have a reserved UUID uuid = self.short_uuid assert uuid channel = get_rfcomm_channel(uuid, self.device['Address']) if channel is None or channel == 0: error = RFCOMMError("Failed to get rfcomm channel") if error_handler: error_handler(error) return True else: raise error try: port_id = create_rfcomm_device(Adapter(obj_path=self.device["Adapter"])['Address'], self.device["Address"], channel) filename = '/dev/rfcomm%d' % port_id logging.info('Starting rfcomm watcher as root') Mechanism().OpenRFCOMM('(d)', port_id) mon = Gio.File.new_for_path(filename).monitor_file(Gio.FileMonitorFlags.NONE) self._handlerids[port_id] = mon.connect('changed', self.on_file_changed, port_id) self.try_replace_root_watcher(mon, filename, port_id) if reply_handler: reply_handler(port_id) except RFCOMMError as e: if error_handler: error_handler(e) else: raise e return True
def get_adapters(self): paths = [] for obj_proxy in self._object_manager.get_objects(): proxy = obj_proxy.get_interface('org.bluez.Adapter1') if proxy: paths.append(proxy.get_object_path()) return [Adapter(path) for path in paths]
def on_adapter_added(self, path): a = Adapter(path) def on_activated(): self.Adapters[str(path)] = str(a["Address"]) self.initialize() wait_for_adapter(a, on_activated)
def on_adapter_added(self, path): a = Adapter(path) def on_activated(): props = a.get_properties() self.Adapters[str(path)] = str(props["Address"]) self.initialize() wait_for_adapter(a, on_activated)
def notify(self, device, service_interface, conn_args): dprint(device, service_interface, conn_args) item = {} object_path = device.get_object_path() try: adapter = Adapter(device.Adapter) except: dprint("adapter not found") return props = adapter.get_properties() item["adapter"] = props["Address"] item["address"] = device.Address item["alias"] = device.Alias item["icon"] = device.Icon item["service"] = service_interface item["conn_args"] = conn_args item["time"] = time.time() item["device"] = device #device object item["mitem"] = None #menu item object for i in RecentConns.items: if i["adapter"] == item["adapter"] and \ i["address"] == item["address"] and \ i["service"] == item["service"] and \ i["conn_args"] == item["conn_args"]: i["time"] = item["time"] if i["gsignal"]: i["device"].disconnect(i["gsignal"]) i["device"] = item["device"] i["gsignal"] = item["device"].connect("invalidated", self.on_device_removed, i) self.initialize() return item["gsignal"] = item["device"].connect("invalidated", self.on_device_removed, item) RecentConns.items.append(item) self.initialize() self.store_state()
def get_adapters(self) -> List[Adapter]: paths = [] for obj_proxy in self._object_manager.get_objects(): proxy = obj_proxy.get_interface('org.bluez.Adapter1') if proxy: assert isinstance(proxy, Gio.DBusProxy) paths.append(proxy.get_object_path()) return [Adapter(obj_path=path) for path in paths]
def add_to_notebook(self, adapter: Adapter) -> None: hci_dev = os.path.basename(adapter.get_object_path()) hci_dev_num = int(hci_dev[3:]) if hci_dev not in self.tabs: self.tabs[hci_dev] = self.build_adapter_tab(adapter) else: if self.tabs[hci_dev]['visible']: return # might need to update settings at this point ui = self.tabs[hci_dev] ui['visible'] = True name = adapter.get_name() if name == '': name = _('Adapter') + ' %d' % (hci_dev_num + 1) label = Gtk.Label(label=name) ui['label'] = label label.set_max_width_chars(20) label.props.hexpand = True label.set_ellipsize(Pango.EllipsizeMode.END) self.notebook.insert_page(ui['grid'], label, hci_dev_num)
def CreateDevice(self, adapter_path, address, pair, time, _ok, err): # BlueZ 4 only! def ok(device): path = device.get_object_path() _ok(path) self.RefreshServices(path, (lambda *args: None), (lambda *args: None)) if self.Applet.Manager: adapter = Adapter(adapter_path) if pair: agent_path = "/org/blueman/agent/temp/" + address.replace( ":", "") agent = TempAgent(self.Applet.Plugins.StatusIcon, agent_path, time) adapter.create_paired_device(address, agent_path, "DisplayYesNo", error_handler=err, reply_handler=ok, timeout=120) else: adapter.create_device(address, error_handler=err, reply_handler=ok, timeout=120) else: err()
def notify(self, service): device = service.device dprint(device, service, service.uuid) item = {} try: adapter = Adapter(device['Adapter']) except: dprint("adapter not found") return props = adapter.get_properties() item["adapter"] = props["Address"] item["address"] = device['Address'] item["alias"] = device['Alias'] try: item["icon"] = device['Icon'] except KeyError: item["icon"] = 'blueman' item["name"] = service.name item["uuid"] = service.uuid item["time"] = time.time() item["device"] = device.get_object_path() item["mitem"] = None #menu item object for i in RecentConns.items: if i["adapter"] == item["adapter"] and \ i["address"] == item["address"] and \ i["uuid"] == item["uuid"]: i["time"] = item["time"] i["device"] = item["device"] self.initialize() return RecentConns.items.append(item) self.initialize() self.store_state()
def CreateDevice(self, adapter_path, address, pair, time, _ok, err): # BlueZ 4 only! def ok(device): path = device.get_object_path() _ok(path) self.RefreshServices(path, (lambda *args: None), (lambda *args: None)) if self.Applet.Manager: adapter = Adapter(adapter_path) if pair: agent_path = "/org/blueman/agent/temp/" + address.replace(":", "") agent = TempAgent(self.Applet.Plugins.StatusIcon, agent_path, time) adapter.create_paired_device( address, agent_path, "DisplayYesNo", error_handler=err, reply_handler=ok, timeout=120 ) else: adapter.create_device(address, error_handler=err, reply_handler=ok, timeout=120) else: err()
def connect(self, reply_handler=None, error_handler=None): props = self.device.get_properties() try: # TODO: Channel? port_id = create_rfcomm_device(Adapter(props['Adapter']).get_properties()['Address'], props['Address'], 1) Mechanism().open_rfcomm(port_id) if reply_handler: reply_handler('/dev/rfcomm%d' % port_id) except Exception as e: if error_handler: error_handler(e) else: raise e return True
def connect(self, reply_handler=None, error_handler=None): try: # TODO: Channel? port_id = create_rfcomm_device( Adapter(self.device["Adapter"])['Address'], self.device["Address"], 1) Mechanism().open_rfcomm(str('(d)'), port_id) if reply_handler: reply_handler('/dev/rfcomm%d' % port_id) except Exception as e: if error_handler: error_handler(e) else: raise e return True
def __init__(self, instance): GObject.GObject.__init__(self) self.Properties = {} self.Fake = True self.Temp = False if isinstance(instance, str) or isinstance(instance, unicode): self.Device = BluezDevice(instance) else: self.Device = instance #set fallback icon, fixes lp:#327718 self.Device.Icon = "blueman" self.Device.Class = "unknown" self.__services = {} self.Valid = True self.Signals = SignalTracker() dprint("caching initial properties") self.Properties = self.Device.get_properties() if not "Fake" in self.Properties: self.Fake = False w = weakref.ref(self) if not self.Fake: self._obj_path = self.Device.get_object_path() self.Signals.Handle( "bluez", self.Device, lambda key, value: w() and w().property_changed(key, value), "PropertyChanged") object_path = self.Device.get_object_path() adapter = Adapter( object_path.replace("/" + os.path.basename(object_path), "")) self.Signals.Handle( "bluez", adapter, lambda path: w() and w().on_device_removed(path), "DeviceRemoved")
def connect(self, reply_handler=None, error_handler=None): props = self.device.get_properties() short_uuid = uuid128_to_uuid16(self.uuid) channel = get_rfcomm_channel(short_uuid, props['Address']) if channel == 0: error = RFCOMMError("Failed to get rfcomm channel") if error_handler: error_handler(error) return True else: raise error try: port_id = create_rfcomm_device(Adapter(props['Adapter']).get_properties()['Address'], props['Address'], channel) Mechanism().open_rfcomm(port_id) if reply_handler: reply_handler('/dev/rfcomm%d' % port_id) except RFCOMMError as e: if error_handler: error_handler(e) else: raise e return True
def __init__(self, device, adapter_path, files): super(Sender, self).__init__(title=_("Bluetooth File Transfer")) self.set_name("BluemanSendTo") self.set_position(Gtk.WindowPosition.CENTER) self.set_type_hint(Gdk.WindowTypeHint.DIALOG) self.props.border_width = 5 self.props.icon_name = "blueman" self.props.width_request = 400 self.b_cancel = self.add_button("_Stop", Gtk.ResponseType.CLOSE) self.b_cancel.props.receives_default = True self.b_cancel.props.use_underline = True self.b_cancel.connect("clicked", self.on_cancel) self.Builder = Gtk.Builder() self.Builder.set_translation_domain("blueman") bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/send-dialog.ui") grid = self.Builder.get_object("sendto") content_area = self.get_content_area() content_area.add(grid) self.l_dest = self.Builder.get_object("l_dest") self.l_file = self.Builder.get_object("l_file") self.pb = self.Builder.get_object("pb") self.pb.props.text = _("Connecting") self.device = device self.adapter = Adapter(adapter_path) self.files = files self.object_push = None self.transfer = None self.total_bytes = 0 self.total_transferred = 0 self._last_bytes = 0 self._last_update = 0 self.error_dialog = None self.cancelling = False #bytes transferred on a current transfer self.transferred = 0 self.speed = SpeedCalc(6) for i in range(len(self.files) - 1, -1, -1): f = self.files[i] match = re.match("file://(.*)", f) if match: f = self.files[i] = urllib.parse.unquote(match.groups(1)[0]) if os.path.exists(f) and not os.path.isdir(f): f = os.path.abspath(f) self.total_bytes += os.path.getsize(f) else: self.files.remove(f) self.num_files = len(self.files) try: self.client = obex.Client() except obex.ObexdNotFoundError: d = ErrorDialog(_("obexd not available"), _("obexd is probably not installed")) d.run() d.destroy() exit(1) if self.num_files == 0: exit(1) self.l_file.props.label = os.path.basename(self.files[-1]) self.client.connect('session-created', self.on_session_created) self.client.connect('session-failed', self.on_session_failed) self.client.connect('session-removed', self.on_session_removed) logging.info("Sending to %s" % device['Address']) self.l_dest.props.label = device['Alias'] # Stop discovery if discovering and let adapter settle for a second if self.adapter["Discovering"]: self.adapter.stop_discovery() time.sleep(1) self.create_session() self.show()
class Device(GObject.GObject): __gsignals__ = { str('invalidated'): (GObject.SignalFlags.NO_HOOKS, None, ()), str('property-changed'): (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_PYOBJECT, GObject.TYPE_PYOBJECT,)), } def __init__(self, instance): GObject.GObject.__init__(self) self.Properties = {} self.Temp = False if hasattr(instance, "format") and hasattr(instance, "upper"): self.Device = BluezDevice(instance) else: self.Device = instance #set fallback icon, fixes lp:#327718 self.Device.Icon = "blueman" self.Device.Class = "unknown" self.Valid = True dprint("caching initial properties") self.Properties = self.Device.get_properties() w = weakref.ref(self) self._obj_path = self.Device.get_object_path() self.Device.connect_signal('property-changed', lambda _device, key, value: w() and w().property_changed(key, value)) self._any_adapter = Adapter() self._any_adapter.connect_signal('device-removed', lambda _adapter, path: w() and w().on_device_removed(path)) def get_service(self, uuid): for name, cls in inspect.getmembers(blueman.services, inspect.isclass): if uuid128_to_uuid16(uuid) == cls.__svclass_id__: return cls(self, uuid) def get_services(self): services = (self.get_service(uuid) for uuid in self.UUIDs) return [service for service in services if service] def __del__(self): dprint("deleting device", self.get_object_path()) self.Destroy() def get_object_path(self): return self._obj_path def on_device_removed(self, path): if path == self._obj_path: self.emit("invalidated") self.Destroy() def Copy(self): if not self.Valid: raise Exception("Attempted to copy an invalidated device") return Device(self.Device) def property_changed(self, key, value): self.emit("property-changed", key, value) self.Properties[key] = value def Destroy(self): dprint("invalidating device", self.get_object_path()) self.Valid = False #self.Device = None #def __del__(self): # dprint("DEBUG: deleting Device instance") def get_properties(self): #print "Properties requested" if not self.Valid: raise Exception("Attempted to get properties for an invalidated device") return self.Properties def __getattr__(self, name): if name in self.__dict__["Properties"]: if not self.Valid: #traceback.print_stack() dprint("Warning: Attempted to get %s property for an invalidated device" % name) return self.__dict__["Properties"][name] else: return getattr(self.Device, name) def __setattr__(self, key, value): if not key in self.__dict__ and "Properties" in self.__dict__ and key in self.__dict__["Properties"]: if not self.Valid: raise Exception("Attempted to set properties for an invalidated device") dprint("Setting property", key, value) self.__dict__["Device"].set(key, value) else: self.__dict__[key] = value
def __init__(self, device, adapter_path, files): super().__init__( title=_("Bluetooth File Transfer"), name="BluemanSendTo", icon_name="blueman", border_width=5, default_width=400, window_position=Gtk.WindowPosition.CENTER, type_hint=Gdk.WindowTypeHint.DIALOG ) self.b_cancel = self.add_button("_Stop", Gtk.ResponseType.CLOSE) self.b_cancel.props.receives_default = True self.b_cancel.props.use_underline = True self.b_cancel.connect("clicked", self.on_cancel) self.Builder = Gtk.Builder(translation_domain="blueman") bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/send-dialog.ui") grid = self.Builder.get_object("sendto") content_area = self.get_content_area() content_area.add(grid) self.l_dest = self.Builder.get_object("l_dest") self.l_file = self.Builder.get_object("l_file") self.pb = self.Builder.get_object("pb") self.pb.props.text = _("Connecting") self.device = device self.adapter = Adapter(adapter_path) self.files = [] self.num_files = 0 self.object_push = None self.transfer = None self.total_bytes = 0 self.total_transferred = 0 self._last_bytes = 0 self._last_update = 0 self.error_dialog = None self.cancelling = False # bytes transferred on a current transfer self.transferred = 0 self.speed = SpeedCalc(6) for file_name in files: parsed_file = Gio.File.parse_name(file_name) if not parsed_file.query_exists(): logging.info("Skipping non existing file %s" % parsed_file.get_path()) continue file_info = parsed_file.query_info("standard::*", Gio.FileQueryInfoFlags.NONE) if file_info.get_file_type() == Gio.FileType.DIRECTORY: logging.info("Skipping directory %s" % parsed_file.get_path()) continue self.files.append(parsed_file) self.num_files += 1 self.total_bytes += file_info.get_size() if len(self.files) == 0: exit(1) try: self.client = obex.Client() except GLib.Error as e: if 'StartServiceByName' in e.message: logging.debug(e.message) d = ErrorDialog(_("obexd not available"), _("Failed to autostart obex service. Make sure the obex " "daemon is running"), parent=self.get_toplevel()) d.run() d.destroy() exit(1) else: # Fail on anything else raise self.l_file.props.label = self.files[-1].get_basename() self.client.connect('session-created', self.on_session_created) self.client.connect('session-failed', self.on_session_failed) self.client.connect('session-removed', self.on_session_removed) logging.info("Sending to %s" % device['Address']) self.l_dest.props.label = device['Alias'] # Stop discovery if discovering and let adapter settle for a second if self.adapter["Discovering"]: self.adapter.stop_discovery() time.sleep(1) self.create_session() self.show()
def on_adapter_added(self, path: str) -> None: adapter = Adapter(obj_path=path) adapter.set("Powered", self.adapter_state)
def __init__(self, device, adapter_path, files): super(Sender, self).__init__(title=_("Bluetooth File Transfer")) self.set_name("BluemanSendTo") self.set_position(Gtk.WindowPosition.CENTER) self.set_type_hint(Gdk.WindowTypeHint.DIALOG) self.props.border_width = 5 self.props.icon_name = "blueman" self.props.width_request = 400 self.b_cancel = self.add_button("_Stop", Gtk.ResponseType.CLOSE) self.b_cancel.props.receives_default = True self.b_cancel.props.use_underline = True self.b_cancel.connect("clicked", self.on_cancel) self.Builder = Gtk.Builder() self.Builder.set_translation_domain("blueman") bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/send-dialog.ui") grid = self.Builder.get_object("sendto") content_area = self.get_content_area() content_area.add(grid) self.l_dest = self.Builder.get_object("l_dest") self.l_file = self.Builder.get_object("l_file") self.pb = self.Builder.get_object("pb") self.pb.props.text = _("Connecting") self.device = device self.adapter = Adapter(adapter_path) self.files = files self.object_push = None self.transfer = None self.total_bytes = 0 self.total_transferred = 0 self._last_bytes = 0 self._last_update = 0 self.error_dialog = None self.cancelling = False # bytes transferred on a current transfer self.transferred = 0 self.speed = SpeedCalc(6) for i in range(len(self.files) - 1, -1, -1): f = self.files[i] match = re.match("file://(.*)", f) if match: f = self.files[i] = urllib.parse.unquote(match.groups(1)[0]) if os.path.exists(f) and not os.path.isdir(f): f = os.path.abspath(f) self.total_bytes += os.path.getsize(f) else: self.files.remove(f) self.num_files = len(self.files) try: self.client = obex.Client() except GLib.Error as e: if 'StartServiceByName' in e.message: logging.debug(e.message) d = ErrorDialog( _("obexd not available"), _("Failed to autostart obex service. Make sure the obex " "daemon is running")) d.run() d.destroy() exit(1) else: # Fail on anything else raise if self.num_files == 0: exit(1) self.l_file.props.label = os.path.basename(self.files[-1]) self.client.connect('session-created', self.on_session_created) self.client.connect('session-failed', self.on_session_failed) self.client.connect('session-removed', self.on_session_removed) logging.info("Sending to %s" % device['Address']) self.l_dest.props.label = device['Alias'] # Stop discovery if discovering and let adapter settle for a second if self.adapter["Discovering"]: self.adapter.stop_discovery() time.sleep(1) self.create_session() self.show()
class Sender(Gtk.Dialog): __gsignals__ = { 'result': (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_BOOLEAN,)), } def __init__(self, device, adapter_path, files): super(Sender, self).__init__(title=_("Bluetooth File Transfer")) self.set_name("BluemanSendTo") self.set_position(Gtk.WindowPosition.CENTER) self.set_type_hint(Gdk.WindowTypeHint.DIALOG) self.props.border_width = 5 self.props.icon_name = "blueman" self.props.width_request = 400 self.b_cancel = self.add_button("_Stop", Gtk.ResponseType.CLOSE) self.b_cancel.props.receives_default = True self.b_cancel.props.use_underline = True self.b_cancel.connect("clicked", self.on_cancel) self.Builder = Gtk.Builder() self.Builder.set_translation_domain("blueman") bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/send-dialog.ui") grid = self.Builder.get_object("sendto") content_area = self.get_content_area() content_area.add(grid) self.l_dest = self.Builder.get_object("l_dest") self.l_file = self.Builder.get_object("l_file") self.pb = self.Builder.get_object("pb") self.pb.props.text = _("Connecting") self.device = device self.adapter = Adapter(adapter_path) self.files = files self.object_push = None self.transfer = None self.total_bytes = 0 self.total_transferred = 0 self._last_bytes = 0 self._last_update = 0 self.error_dialog = None self.cancelling = False #bytes transferred on a current transfer self.transferred = 0 self.speed = SpeedCalc(6) for i in range(len(self.files) - 1, -1, -1): f = self.files[i] match = re.match("file://(.*)", f) if match: f = self.files[i] = urllib.parse.unquote(match.groups(1)[0]) if os.path.exists(f) and not os.path.isdir(f): f = os.path.abspath(f) self.total_bytes += os.path.getsize(f) else: self.files.remove(f) self.num_files = len(self.files) try: self.client = obex.Client() except obex.ObexdNotFoundError: d = ErrorDialog(_("obexd not available"), _("obexd is probably not installed")) d.run() d.destroy() exit(1) if self.num_files == 0: exit(1) self.l_file.props.label = os.path.basename(self.files[-1]) self.client.connect('session-created', self.on_session_created) self.client.connect('session-failed', self.on_session_failed) self.client.connect('session-removed', self.on_session_removed) logging.info("Sending to %s" % device['Address']) self.l_dest.props.label = device['Alias'] # Stop discovery if discovering and let adapter settle for a second if self.adapter["Discovering"]: self.adapter.stop_discovery() time.sleep(1) self.create_session() self.show() def create_session(self): self.client.create_session(self.device['Address'], self.adapter["Address"]) def on_cancel(self, button): self.pb.props.text = _("Cancelling") if button: button.props.sensitive = False if self.object_push: self.client.remove_session(self.object_push.get_session_path()) else: self.emit("result", False) def on_transfer_started(self, _object_push, transfer_path, filename): if self.total_transferred == 0: self.pb.props.text = _("Sending File") + (" %(0)s/%(1)s (%(2).2f %(3)s/s) " + _("ETA:") + " %(4)s") % { "1": self.num_files, "0": (self.num_files - len(self.files) + 1), "2": 0.0, "3": "B/s", "4": "∞"} self.l_file.props.label = filename self._last_bytes = 0 self.transferred = 0 self.transfer = obex.Transfer(transfer_path) self.transfer.connect("error", self.on_transfer_error) self.transfer.connect("progress", self.on_transfer_progress) self.transfer.connect("completed", self.on_transfer_completed) def on_transfer_failed(self, _object_push, error): self.on_transfer_error(None, str(error)) def on_transfer_progress(self, _transfer, progress): self.transferred = progress if self._last_bytes == 0: self.total_transferred += progress else: self.total_transferred += (progress - self._last_bytes) self._last_bytes = progress tm = time.time() if tm - self._last_update > 0.5: spd = self.speed.calc(self.total_transferred) (size, units) = format_bytes(spd) try: x = ((self.total_bytes - self.total_transferred) / spd) + 1 if x > 60: x /= 60 eta = ngettext("%.0f Minute", "%.0f Minutes", round(x)) % x else: eta = ngettext("%.0f Second", "%.0f Seconds", round(x)) % x except ZeroDivisionError: eta = "∞" self.pb.props.text = _("Sending File") + (" %(0)s/%(1)s (%(2).2f %(3)s/s) " + _("ETA:") + " %(4)s") % { "1": self.num_files, "0": (self.num_files - len(self.files) + 1), "2": size, "3": units, "4": eta} self._last_update = tm self.pb.props.fraction = float(self.total_transferred) / self.total_bytes def on_transfer_completed(self, _transfer): del self.files[-1] self.transfer = None self.process_queue() def process_queue(self): if len(self.files) > 0: self.send_file(self.files[-1]) else: self.emit("result", True) def send_file(self, file_path): logging.info(file_path) if self.object_push: self.object_push.send_file(file_path) def on_transfer_error(self, _transfer, msg=""): if not self.error_dialog: self.speed.reset() d = ErrorDialog(msg, _("Error occurred while sending file %s") % os.path.basename(self.files[-1]), modal=True, icon_name="blueman", buttons=None) if len(self.files) > 1: d.add_button(_("Skip"), Gtk.ResponseType.NO) d.add_button(_("Retry"), Gtk.ResponseType.YES) d.add_button("_Cancel", Gtk.ResponseType.CANCEL) def on_response(dialog, resp): dialog.destroy() self.error_dialog = None if resp == "_Cancel": self.on_cancel(None) elif resp == Gtk.ResponseType.NO: self.total_bytes -= os.path.getsize(self.files[-1]) self.total_transferred -= self.transferred self.transferred = 0 del self.files[-1] if not self.object_push: self.create_session() self.process_queue() elif resp == Gtk.ResponseType.YES: self.total_transferred -= self.transferred self.transferred = 0 if not self.object_push: self.create_session() self.process_queue() else: self.on_cancel(None) d.connect("response", on_response) d.show() self.error_dialog = d def on_session_created(self, _client, session_path): self.object_push = ObjectPush(session_path) self.object_push.connect("transfer-started", self.on_transfer_started) self.object_push.connect("transfer-failed", self.on_transfer_failed) self.process_queue() def on_session_failed(self, _client, msg): d = ErrorDialog(_("Error occurred"), msg.reason.split(None, 1)[1], icon_name="blueman") d.run() d.destroy() exit(1) def on_session_removed(self, _client): self.emit("result", False)
class Sender(Gtk.Dialog): __gsignals__ = { 'result': (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_BOOLEAN,)), } def __init__(self, device, adapter_path, files): super().__init__( title=_("Bluetooth File Transfer"), name="BluemanSendTo", icon_name="blueman", border_width=5, default_width=400, window_position=Gtk.WindowPosition.CENTER, type_hint=Gdk.WindowTypeHint.DIALOG ) self.b_cancel = self.add_button("_Stop", Gtk.ResponseType.CLOSE) self.b_cancel.props.receives_default = True self.b_cancel.props.use_underline = True self.b_cancel.connect("clicked", self.on_cancel) self.Builder = Gtk.Builder(translation_domain="blueman") bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/send-dialog.ui") grid = self.Builder.get_object("sendto") content_area = self.get_content_area() content_area.add(grid) self.l_dest = self.Builder.get_object("l_dest") self.l_file = self.Builder.get_object("l_file") self.pb = self.Builder.get_object("pb") self.pb.props.text = _("Connecting") self.device = device self.adapter = Adapter(adapter_path) self.files = [] self.num_files = 0 self.object_push = None self.transfer = None self.total_bytes = 0 self.total_transferred = 0 self._last_bytes = 0 self._last_update = 0 self.error_dialog = None self.cancelling = False # bytes transferred on a current transfer self.transferred = 0 self.speed = SpeedCalc(6) for file_name in files: parsed_file = Gio.File.parse_name(file_name) if not parsed_file.query_exists(): logging.info("Skipping non existing file %s" % parsed_file.get_path()) continue file_info = parsed_file.query_info("standard::*", Gio.FileQueryInfoFlags.NONE) if file_info.get_file_type() == Gio.FileType.DIRECTORY: logging.info("Skipping directory %s" % parsed_file.get_path()) continue self.files.append(parsed_file) self.num_files += 1 self.total_bytes += file_info.get_size() if len(self.files) == 0: exit(1) try: self.client = obex.Client() except GLib.Error as e: if 'StartServiceByName' in e.message: logging.debug(e.message) d = ErrorDialog(_("obexd not available"), _("Failed to autostart obex service. Make sure the obex " "daemon is running"), parent=self.get_toplevel()) d.run() d.destroy() exit(1) else: # Fail on anything else raise self.l_file.props.label = self.files[-1].get_basename() self.client.connect('session-created', self.on_session_created) self.client.connect('session-failed', self.on_session_failed) self.client.connect('session-removed', self.on_session_removed) logging.info("Sending to %s" % device['Address']) self.l_dest.props.label = device['Alias'] # Stop discovery if discovering and let adapter settle for a second if self.adapter["Discovering"]: self.adapter.stop_discovery() time.sleep(1) self.create_session() self.show() def create_session(self): self.client.create_session(self.device['Address'], self.adapter["Address"]) def on_cancel(self, button): self.pb.props.text = _("Cancelling") if button: button.props.sensitive = False if self.object_push: self.client.remove_session(self.object_push.get_session_path()) else: self.emit("result", False) def on_transfer_started(self, _object_push, transfer_path, filename): if self.total_transferred == 0: self.pb.props.text = _("Sending File") + (" %(0)s/%(1)s (%(2).2f %(3)s/s) " + _("ETA:") + " %(4)s") % { "1": self.num_files, "0": (self.num_files - len(self.files) + 1), "2": 0.0, "3": "B/s", "4": "∞"} self.l_file.props.label = filename self._last_bytes = 0 self.transferred = 0 self.transfer = obex.Transfer(transfer_path) self.transfer.connect("error", self.on_transfer_error) self.transfer.connect("progress", self.on_transfer_progress) self.transfer.connect("completed", self.on_transfer_completed) def on_transfer_failed(self, _object_push, error): self.on_transfer_error(None, str(error)) def on_transfer_progress(self, _transfer, progress): self.transferred = progress if self._last_bytes == 0: self.total_transferred += progress else: self.total_transferred += (progress - self._last_bytes) self._last_bytes = progress tm = time.time() if tm - self._last_update > 0.5: spd = self.speed.calc(self.total_transferred) (size, units) = format_bytes(spd) try: x = ((self.total_bytes - self.total_transferred) / spd) + 1 if x > 60: x /= 60 eta = ngettext("%.0f Minute", "%.0f Minutes", round(x)) % x else: eta = ngettext("%.0f Second", "%.0f Seconds", round(x)) % x except ZeroDivisionError: eta = "∞" self.pb.props.text = _("Sending File") + (" %(0)s/%(1)s (%(2).2f %(3)s/s) " + _("ETA:") + " %(4)s") % { "1": self.num_files, "0": (self.num_files - len(self.files) + 1), "2": size, "3": units, "4": eta} self._last_update = tm self.pb.props.fraction = float(self.total_transferred) / self.total_bytes def on_transfer_completed(self, _transfer): del self.files[-1] self.transfer = None self.process_queue() def process_queue(self): if len(self.files) > 0: self.send_file(self.files[-1].get_path()) else: self.emit("result", True) def send_file(self, file_path): logging.info(file_path) if self.object_push: self.object_push.send_file(file_path) def on_transfer_error(self, _transfer, msg=""): if not self.error_dialog: self.speed.reset() d = ErrorDialog(msg, _("Error occurred while sending file %s") % os.path.basename(self.files[-1]), modal=True, icon_name="blueman", parent=self.get_toplevel()) if len(self.files) > 1: d.add_button(_("Skip"), Gtk.ResponseType.NO) d.add_button(_("Retry"), Gtk.ResponseType.YES) d.add_button("_Cancel", Gtk.ResponseType.CANCEL) def on_response(dialog, resp): dialog.destroy() self.error_dialog = None if resp == "_Cancel": self.on_cancel(None) elif resp == Gtk.ResponseType.NO: self.total_bytes -= os.path.getsize(self.files[-1]) self.total_transferred -= self.transferred self.transferred = 0 del self.files[-1] if not self.object_push: self.create_session() self.process_queue() elif resp == Gtk.ResponseType.YES: self.total_transferred -= self.transferred self.transferred = 0 if not self.object_push: self.create_session() self.process_queue() else: self.on_cancel(None) d.connect("response", on_response) d.show() self.error_dialog = d def on_session_created(self, _client, session_path): self.object_push = ObjectPush(session_path) self.object_push.connect("transfer-started", self.on_transfer_started) self.object_push.connect("transfer-failed", self.on_transfer_failed) self.process_queue() def on_session_failed(self, _client, msg): d = ErrorDialog(_("Error occurred"), msg.reason.split(None, 1)[1], icon_name="blueman", parent=self.get_toplevel()) d.run() d.destroy() exit(1) def on_session_removed(self, _client): self.emit("result", False)
def __init__(self, device, adapter_path, files): super().__init__( title=_("Bluetooth File Transfer"), name="BluemanSendTo", icon_name="blueman", border_width=5, default_width=400, window_position=Gtk.WindowPosition.CENTER, type_hint=Gdk.WindowTypeHint.DIALOG ) self.b_cancel = self.add_button("_Stop", Gtk.ResponseType.CLOSE) self.b_cancel.props.receives_default = True self.b_cancel.props.use_underline = True self.b_cancel.connect("clicked", self.on_cancel) self.Builder = Gtk.Builder(translation_domain="blueman") bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/send-dialog.ui") grid = self.Builder.get_object("sendto") content_area = self.get_content_area() content_area.add(grid) self.l_dest = self.Builder.get_object("l_dest") self.l_file = self.Builder.get_object("l_file") self.pb = self.Builder.get_object("pb") self.pb.props.text = _("Connecting") self.device = device self.adapter = Adapter(adapter_path) self.manager = Manager() self.files: List[Gio.File] = [] self.num_files = 0 self.object_push = None self.transfer = None self.total_bytes = 0 self.total_transferred = 0 self._last_bytes = 0 self._last_update = 0.0 self.error_dialog = None self.cancelling = False # bytes transferred on a current transfer self.transferred = 0 self.speed = SpeedCalc(6) for file_name in files: parsed_file = Gio.File.parse_name(file_name) if not parsed_file.query_exists(): logging.info("Skipping non existing file %s" % parsed_file.get_path()) continue file_info = parsed_file.query_info("standard::*", Gio.FileQueryInfoFlags.NONE) if file_info.get_file_type() == Gio.FileType.DIRECTORY: logging.info("Skipping directory %s" % parsed_file.get_path()) continue self.files.append(parsed_file) self.num_files += 1 self.total_bytes += file_info.get_size() if len(self.files) == 0: self.emit("result", False) try: self.client = Client() self.manager.connect_signal('session-added', self.on_session_added) self.manager.connect_signal('session-removed', self.on_session_removed) except GLib.Error as e: if 'StartServiceByName' in e.message: logging.debug(e.message) d = ErrorDialog(_("obexd not available"), _("Failed to autostart obex service. Make sure the obex " "daemon is running"), parent=self.get_toplevel()) d.run() d.destroy() self.emit("result", False) else: # Fail on anything else raise self.l_file.props.label = self.files[-1].get_basename() self.client.connect('session-failed', self.on_session_failed) logging.info("Sending to %s" % device['Address']) self.l_dest.props.label = device['Alias'] # Stop discovery if discovering and let adapter settle for a second if self.adapter["Discovering"]: self.adapter.stop_discovery() time.sleep(1) self.create_session() self.show()
class Sender(Gtk.Dialog): __gsignals__: GSignals = { 'result': (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_BOOLEAN,)), } def __init__(self, device, adapter_path, files): super().__init__( title=_("Bluetooth File Transfer"), name="BluemanSendTo", icon_name="blueman", border_width=5, default_width=400, window_position=Gtk.WindowPosition.CENTER, type_hint=Gdk.WindowTypeHint.DIALOG ) self.b_cancel = self.add_button("_Stop", Gtk.ResponseType.CLOSE) self.b_cancel.props.receives_default = True self.b_cancel.props.use_underline = True self.b_cancel.connect("clicked", self.on_cancel) self.Builder = Gtk.Builder(translation_domain="blueman") bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/send-dialog.ui") grid = self.Builder.get_object("sendto") content_area = self.get_content_area() content_area.add(grid) self.l_dest = self.Builder.get_object("l_dest") self.l_file = self.Builder.get_object("l_file") self.pb = self.Builder.get_object("pb") self.pb.props.text = _("Connecting") self.device = device self.adapter = Adapter(adapter_path) self.manager = Manager() self.files: List[Gio.File] = [] self.num_files = 0 self.object_push = None self.transfer = None self.total_bytes = 0 self.total_transferred = 0 self._last_bytes = 0 self._last_update = 0.0 self.error_dialog = None self.cancelling = False # bytes transferred on a current transfer self.transferred = 0 self.speed = SpeedCalc(6) for file_name in files: parsed_file = Gio.File.parse_name(file_name) if not parsed_file.query_exists(): logging.info("Skipping non existing file %s" % parsed_file.get_path()) continue file_info = parsed_file.query_info("standard::*", Gio.FileQueryInfoFlags.NONE) if file_info.get_file_type() == Gio.FileType.DIRECTORY: logging.info("Skipping directory %s" % parsed_file.get_path()) continue self.files.append(parsed_file) self.num_files += 1 self.total_bytes += file_info.get_size() if len(self.files) == 0: self.emit("result", False) try: self.client = Client() self.manager.connect_signal('session-added', self.on_session_added) self.manager.connect_signal('session-removed', self.on_session_removed) except GLib.Error as e: if 'StartServiceByName' in e.message: logging.debug(e.message) d = ErrorDialog(_("obexd not available"), _("Failed to autostart obex service. Make sure the obex " "daemon is running"), parent=self.get_toplevel()) d.run() d.destroy() self.emit("result", False) else: # Fail on anything else raise self.l_file.props.label = self.files[-1].get_basename() self.client.connect('session-failed', self.on_session_failed) logging.info("Sending to %s" % device['Address']) self.l_dest.props.label = device['Alias'] # Stop discovery if discovering and let adapter settle for a second if self.adapter["Discovering"]: self.adapter.stop_discovery() time.sleep(1) self.create_session() self.show() def create_session(self): self.client.create_session(self.device['Address'], self.adapter["Address"]) def on_cancel(self, button): self.pb.props.text = _("Cancelling") if button: button.props.sensitive = False if self.object_push: self.client.remove_session(self.object_push.get_session_path()) self.emit("result", False) def on_transfer_started(self, _object_push, transfer_path, filename): if self.total_transferred == 0: self.pb.props.text = _("Sending File") + (" %(0)s/%(1)s (%(2).2f %(3)s/s) " + _("ETA:") + " %(4)s") % { "1": self.num_files, "0": (self.num_files - len(self.files) + 1), "2": 0.0, "3": "B/s", "4": "∞"} self.l_file.props.label = filename self._last_bytes = 0 self.transferred = 0 self.transfer = Transfer(transfer_path) self.transfer.connect("error", self.on_transfer_error) self.transfer.connect("progress", self.on_transfer_progress) self.transfer.connect("completed", self.on_transfer_completed) def on_transfer_failed(self, _object_push, error): self.on_transfer_error(None, str(error)) def on_transfer_progress(self, _transfer, progress): self.transferred = progress if self._last_bytes == 0: self.total_transferred += progress else: self.total_transferred += (progress - self._last_bytes) self._last_bytes = progress tm = time.time() if tm - self._last_update > 0.5: spd = self.speed.calc(self.total_transferred) (size, units) = format_bytes(spd) try: x = ((self.total_bytes - self.total_transferred) / spd) + 1 if x > 60: x /= 60 eta = ngettext("%.0f Minute", "%.0f Minutes", round(x)) % x else: eta = ngettext("%.0f Second", "%.0f Seconds", round(x)) % x except ZeroDivisionError: eta = "∞" self.pb.props.text = _("Sending File") + (" %(0)s/%(1)s (%(2).2f %(3)s/s) " + _("ETA:") + " %(4)s") % { "1": self.num_files, "0": (self.num_files - len(self.files) + 1), "2": size, "3": units, "4": eta} self._last_update = tm self.pb.props.fraction = float(self.total_transferred) / self.total_bytes def on_transfer_completed(self, _transfer): del self.files[-1] self.transfer = None self.process_queue() def process_queue(self): if len(self.files) > 0: self.send_file(self.files[-1].get_path()) else: self.emit("result", True) def send_file(self, file_path): logging.info(file_path) if self.object_push: self.object_push.send_file(file_path) def on_transfer_error(self, _transfer, msg=""): if not self.error_dialog: self.speed.reset() d = ErrorDialog(msg, _("Error occurred while sending file %s") % self.files[-1].get_basename(), modal=True, icon_name="blueman", parent=self.get_toplevel(), buttons=[]) if len(self.files) > 1: d.add_button(_("Skip"), Gtk.ResponseType.NO) d.add_button(_("Retry"), Gtk.ResponseType.YES) d.add_button("_Cancel", Gtk.ResponseType.CANCEL) if self.object_push: self.client.remove_session(self.object_push.get_object_path()) def on_response(dialog, resp): dialog.destroy() self.error_dialog = None if resp == Gtk.ResponseType.CANCEL: self.on_cancel(None) elif resp == Gtk.ResponseType.NO: finfo = self.files[-1].query_info('standard::*', Gio.FileQueryInfoFlags.NONE) self.total_bytes -= finfo.get_size() self.total_transferred -= self.transferred self.transferred = 0 del self.files[-1] if not self.object_push: self.create_session() self.process_queue() elif resp == Gtk.ResponseType.YES: self.total_transferred -= self.transferred self.transferred = 0 if not self.object_push: self.create_session() self.process_queue() else: self.on_cancel(None) d.connect("response", on_response) d.show() self.error_dialog = d def on_session_added(self, _manager, session_path): self.object_push = ObjectPush(session_path) self.object_push.connect("transfer-started", self.on_transfer_started) self.object_push.connect("transfer-failed", self.on_transfer_failed) self.process_queue() def on_session_removed(self, _manager, session_path): logging.debug('Session removed: %s' % session_path) if self.object_push: self.object_push.disconnect_by_func(self.on_transfer_started) self.object_push.disconnect_by_func(self.on_transfer_failed) self.object_push = None def on_session_failed(self, _client, msg): d = ErrorDialog(_("Error occurred"), msg.reason.split(None, 1)[1], icon_name="blueman", parent=self.get_toplevel()) d.run() d.destroy() self.emit("result", False)
def remove_from_notebook(self, adapter: Adapter) -> None: hci_dev = os.path.basename(adapter.get_object_path()) hci_dev_num = int(hci_dev[3:]) self.tabs[hci_dev]['visible'] = False self.notebook.remove_page(hci_dev_num)
def on_adapter_added(self, path): adapter = Adapter(path) adapter.set("Powered", self.adapter_state)
def build_adapter_tab(self, adapter: Adapter) -> "Tab": def on_hidden_toggle(radio: Gtk.RadioButton) -> None: if not radio.props.active: return adapter['DiscoverableTimeout'] = 0 adapter['Discoverable'] = False hscale.set_sensitive(False) def on_always_toggle(radio: Gtk.RadioButton) -> None: if not radio.props.active: return adapter['DiscoverableTimeout'] = 0 adapter['Discoverable'] = True hscale.set_sensitive(False) def on_temporary_toggle(radio: Gtk.RadioButton) -> None: if not radio.props.active: return adapter['Discoverable'] = True hscale.set_sensitive(True) hscale.set_value(3) def on_scale_format_value(_scale: Gtk.Scale, value: float) -> str: if value == 0: if adapter['Discoverable']: return _("Always") else: return _("Hidden") else: return gettext.ngettext("%(minutes)d Minute", "%(minutes)d Minutes", int(value)) % { "minutes": value } def on_scale_value_changed(scale: Gtk.Scale) -> None: val = scale.get_value() logging.info(f"value: {val}") if val == 0 and adapter['Discoverable']: always_radio.props.active = True timeout = int(val * 60) adapter['DiscoverableTimeout'] = timeout def on_name_changed(entry: Gtk.Entry) -> None: adapter['Alias'] = entry.get_text() builder = Builder("adapters-tab.ui") hscale = builder.get_widget("hscale", Gtk.Scale) hscale.connect("format-value", on_scale_format_value) hscale.connect("value-changed", on_scale_value_changed) hscale.set_range(0, 30) hscale.set_increments(1, 1) hidden_radio = builder.get_widget("hidden", Gtk.RadioButton) always_radio = builder.get_widget("always", Gtk.RadioButton) temporary_radio = builder.get_widget("temporary", Gtk.RadioButton) if adapter['Discoverable'] and adapter['DiscoverableTimeout'] > 0: temporary_radio.set_active(True) hscale.set_value(adapter['DiscoverableTimeout']) hscale.set_sensitive(True) elif adapter['Discoverable'] and adapter['DiscoverableTimeout'] == 0: always_radio.set_active(True) else: hidden_radio.set_active(True) name_entry = builder.get_widget("name_entry", Gtk.Entry) name_entry.set_text(adapter.get_name()) hidden_radio.connect("toggled", on_hidden_toggle) always_radio.connect("toggled", on_always_toggle) temporary_radio.connect("toggled", on_temporary_toggle) name_entry.connect("changed", on_name_changed) return { "grid": builder.get_widget("grid", Gtk.Grid), "hidden_radio": hidden_radio, "always_radio": always_radio, "temparary_radio": temporary_radio, "visible": False, "label": Gtk.Label() }