def __init__(self, bd_address: str) -> None: super().__init__() self.set_name("GsmSettings") self.device = bd_address builder = Builder("gsm-settings.ui") gsm_grid = builder.get_widget("gsm_grid", Gtk.Grid) self.config = Config("org.blueman.gsmsetting", f"/org/blueman/gsmsettings/{bd_address}/") self.props.icon_name = "network-wireless" self.props.title = _("GSM Settings") self.props.resizable = False a = self.get_content_area() a.pack_start(gsm_grid, True, True, 0) gsm_grid.show() self.e_apn = builder.get_widget("e_apn", Gtk.Entry) self.e_number = builder.get_widget("e_number", Gtk.Entry) self.config.bind_to_widget("apn", self.e_apn, "text") self.config.bind_to_widget("number", self.e_number, "text") self.add_button("_Close", Gtk.ResponseType.CLOSE)
def send_note(device: Device, parent: Gtk.Window) -> None: builder = Builder("note.ui") dialog = builder.get_widget("dialog", Gtk.Dialog) dialog.set_transient_for(parent) dialog.props.icon_name = 'blueman' note = builder.get_widget("note", Gtk.Entry) dialog.connect('response', send_note_cb, device['Address'], note) dialog.present()
def on_load(self, container: Gtk.Box) -> None: self._builder = Builder("services-transfer.ui") self.widget = self._builder.get_widget("transfer", Gtk.Widget) container.pack_start(self.widget, True, True, 0) a = AppletService() if "TransferService" in a.QueryPlugins(): self._setup_transfer() else: self.widget.props.sensitive = False self.widget.props.tooltip_text = _( "Applet's transfer service plugin is disabled")
def build_passkey_dialog(self, device_alias: str, dialog_msg: str, is_numeric: bool) -> Tuple[Gtk.Dialog, Gtk.Entry]: def on_insert_text(editable: Gtk.Entry, new_text: str, _new_text_length: int, _position: int) -> None: if not new_text.isdigit(): editable.stop_emission("insert-text") builder = Builder("applet-passkey.ui") dialog = builder.get_widget("dialog", Gtk.Dialog) dialog.props.icon_name = "blueman" dev_name = builder.get_widget("device_name", Gtk.Label) dev_name.set_markup(device_alias) msg = builder.get_widget("message", Gtk.Label) msg.set_text(dialog_msg) pin_entry = builder.get_widget("pin_entry", Gtk.Entry) show_input = builder.get_widget("show_input_check", Gtk.CheckButton) if is_numeric: pin_entry.set_max_length(6) pin_entry.set_width_chars(6) pin_entry.connect("insert-text", on_insert_text) show_input.hide() else: pin_entry.set_max_length(16) pin_entry.set_width_chars(16) pin_entry.set_visibility(False) show_input.connect("toggled", lambda x: pin_entry.set_visibility(x.props.active)) accept_button = builder.get_widget("accept", Gtk.Button) pin_entry.connect( "changed", lambda x: accept_button.set_sensitive(x.get_text() != '')) return dialog, pin_entry
def on_rename(_item: Gtk.MenuItem, device: Device) -> None: def on_response(dialog: Gtk.Dialog, response_id: int) -> None: if response_id == Gtk.ResponseType.ACCEPT: assert isinstance(alias_entry, Gtk.Entry) # https://github.com/python/mypy/issues/2608 device.set('Alias', alias_entry.get_text()) elif response_id == 1: device.set('Alias', '') dialog.destroy() builder = Builder("rename-device.ui") dialog = builder.get_widget("dialog", Gtk.Dialog) dialog.set_transient_for(self.Blueman.window) dialog.props.icon_name = "blueman" alias_entry = builder.get_widget("alias_entry", Gtk.Entry) alias_entry.set_text(device['Alias']) dialog.connect("response", on_response) dialog.present()
def on_load(self, container: Gtk.Box) -> None: self._builder = Builder("services-network.ui") self.widget = self._builder.get_widget("network_frame", Gtk.Widget) container.pack_start(self.widget, True, True, 0) self.interfaces: List[Tuple[str, ipaddress.IPv4Interface]] = [] netifs = get_local_interfaces() for iface in netifs: if iface != "lo" and iface != "pan1": logging.info(iface) ipiface = ipaddress.ip_interface('/'.join( cast(Tuple[str, str], netifs[iface]))) self.interfaces.append((iface, ipiface)) self.setup_network() try: self.ip_check() except (ValueError, ipaddress.AddressValueError) as e: logging.exception(e)
def do_activate(self) -> None: if not self.window: self.window = Gtk.ApplicationWindow(application=self, name="BluemanManager", icon_name="blueman", title=_("Bluetooth Devices")) w, h, x, y = self.Config["window-properties"] if w and h: self.window.resize(w, h) if x and y: self.window.move(x, y) # Connect to configure event to store new window position and size self.window.connect("configure-event", self._on_configure) self.builder = Builder("manager-main.ui") box = self.builder.get_widget("box", Gtk.Box) self.window.add(box) grid = self.builder.get_widget("grid", Gtk.Grid) toolbar = self.builder.get_widget("toolbar", Gtk.Toolbar) statusbar = self.builder.get_widget("statusbar", Gtk.Box) self.Plugins = PluginManager(ManagerPlugin, blueman.plugins.manager, self) self.Plugins.load_plugin() area = MessageArea() grid.attach(area, 0, 1, 1, 1) self._applethandlerid: Optional[int] = None # Add margin for resize grip or it will overlap if self.window.get_has_resize_grip(): margin_right = statusbar.get_margin_right() statusbar.set_margin_right(margin_right + 10) def bt_status_changed(status: bool) -> None: assert self.window is not None if not status: self.window.hide() check_bluetooth_status( _("Bluetooth needs to be turned on for the device manager to function" ), self.quit) else: self.window.show() def on_applet_signal(_proxy: AppletService, _sender: str, signal_name: str, params: GLib.Variant) -> None: if signal_name == 'BluetoothStatusChanged': status = params.unpack() bt_status_changed(status) def on_dbus_name_vanished(_connection: Gio.DBusConnection, name: str) -> None: logging.info(name) if self._applethandlerid: self.Applet.disconnect(self._applethandlerid) self._applethandlerid = None if self.window is not None: self.window.hide() d = ErrorDialog( _("Connection to BlueZ failed"), _("Bluez daemon is not running, blueman-manager cannot continue.\n" "This probably means that there were no Bluetooth adapters detected " "or Bluetooth daemon was not started."), icon_name="blueman") d.run() d.destroy() # FIXME ui can handle BlueZ start/stop but we should inform user self.quit() def on_dbus_name_appeared(_connection: Gio.DBusConnection, name: str, owner: str) -> None: logging.info(f"{name} {owner}") setup_icon_path() try: self.Applet = AppletService() except DBusProxyFailed: print("Blueman applet needs to be running") bmexit() check_bluetooth_status( _("Bluetooth needs to be turned on for the device manager to function" ), lambda: self.quit()) manager = Manager() try: manager.get_adapter(self.Config['last-adapter']) except DBusNoSuchAdapterError: logging.error( 'Default adapter not found, trying first available.') try: manager.get_adapter(None) except DBusNoSuchAdapterError: logging.error('No adapter(s) found, exiting') bmexit() self._applethandlerid = self.Applet.connect( 'g-signal', on_applet_signal) sw = self.builder.get_widget("scrollview", Gtk.ScrolledWindow) # Disable overlay scrolling if Gtk.get_minor_version() >= 16: sw.props.overlay_scrolling = False self.List = ManagerDeviceList( adapter=self.Config["last-adapter"], inst=self) self.List.show() sw.add(self.List) self.Toolbar = ManagerToolbar(self) self.Menu = ManagerMenu(self) self.Stats = ManagerStats(self) if self.List.is_valid_adapter(): self.List.populate_devices() self.List.connect("adapter-changed", self.on_adapter_changed) self.Config.bind_to_widget("show-toolbar", toolbar, "visible") self.Config.bind_to_widget("show-statusbar", statusbar, "visible") Manager.watch_name_owner(on_dbus_name_appeared, on_dbus_name_vanished) self.window.present_with_time(Gtk.get_current_event_time())
class Blueman(Gtk.Application): def __init__(self) -> None: super().__init__(application_id="org.blueman.Manager") def do_quit(_: object) -> bool: self.quit() return False s = GLib.unix_signal_source_new(signal.SIGINT) s.set_callback(do_quit) s.attach() window: Optional[Gtk.ApplicationWindow] def do_startup(self) -> None: def doquit(_a: Gio.SimpleAction, _param: None) -> None: self.quit() Gtk.Application.do_startup(self) self.window = None self.Config = Config("org.blueman.general") quit_action = Gio.SimpleAction.new("Quit", None) quit_action.connect("activate", doquit) self.set_accels_for_action("app.Quit", ["<Ctrl>q", "<Ctrl>w"]) self.add_action(quit_action) def do_activate(self) -> None: if not self.window: self.window = Gtk.ApplicationWindow(application=self, name="BluemanManager", icon_name="blueman", title=_("Bluetooth Devices")) w, h, x, y = self.Config["window-properties"] if w and h: self.window.resize(w, h) if x and y: self.window.move(x, y) # Connect to configure event to store new window position and size self.window.connect("configure-event", self._on_configure) self.builder = Builder("manager-main.ui") box = self.builder.get_widget("box", Gtk.Box) self.window.add(box) grid = self.builder.get_widget("grid", Gtk.Grid) toolbar = self.builder.get_widget("toolbar", Gtk.Toolbar) statusbar = self.builder.get_widget("statusbar", Gtk.Box) self.Plugins = PluginManager(ManagerPlugin, blueman.plugins.manager, self) self.Plugins.load_plugin() area = MessageArea() grid.attach(area, 0, 1, 1, 1) self._applethandlerid: Optional[int] = None # Add margin for resize grip or it will overlap if self.window.get_has_resize_grip(): margin_right = statusbar.get_margin_right() statusbar.set_margin_right(margin_right + 10) def bt_status_changed(status: bool) -> None: assert self.window is not None if not status: self.window.hide() check_bluetooth_status( _("Bluetooth needs to be turned on for the device manager to function" ), self.quit) else: self.window.show() def on_applet_signal(_proxy: AppletService, _sender: str, signal_name: str, params: GLib.Variant) -> None: if signal_name == 'BluetoothStatusChanged': status = params.unpack() bt_status_changed(status) def on_dbus_name_vanished(_connection: Gio.DBusConnection, name: str) -> None: logging.info(name) if self._applethandlerid: self.Applet.disconnect(self._applethandlerid) self._applethandlerid = None if self.window is not None: self.window.hide() d = ErrorDialog( _("Connection to BlueZ failed"), _("Bluez daemon is not running, blueman-manager cannot continue.\n" "This probably means that there were no Bluetooth adapters detected " "or Bluetooth daemon was not started."), icon_name="blueman") d.run() d.destroy() # FIXME ui can handle BlueZ start/stop but we should inform user self.quit() def on_dbus_name_appeared(_connection: Gio.DBusConnection, name: str, owner: str) -> None: logging.info(f"{name} {owner}") setup_icon_path() try: self.Applet = AppletService() except DBusProxyFailed: print("Blueman applet needs to be running") bmexit() check_bluetooth_status( _("Bluetooth needs to be turned on for the device manager to function" ), lambda: self.quit()) manager = Manager() try: manager.get_adapter(self.Config['last-adapter']) except DBusNoSuchAdapterError: logging.error( 'Default adapter not found, trying first available.') try: manager.get_adapter(None) except DBusNoSuchAdapterError: logging.error('No adapter(s) found, exiting') bmexit() self._applethandlerid = self.Applet.connect( 'g-signal', on_applet_signal) sw = self.builder.get_widget("scrollview", Gtk.ScrolledWindow) # Disable overlay scrolling if Gtk.get_minor_version() >= 16: sw.props.overlay_scrolling = False self.List = ManagerDeviceList( adapter=self.Config["last-adapter"], inst=self) self.List.show() sw.add(self.List) self.Toolbar = ManagerToolbar(self) self.Menu = ManagerMenu(self) self.Stats = ManagerStats(self) if self.List.is_valid_adapter(): self.List.populate_devices() self.List.connect("adapter-changed", self.on_adapter_changed) self.Config.bind_to_widget("show-toolbar", toolbar, "visible") self.Config.bind_to_widget("show-statusbar", statusbar, "visible") Manager.watch_name_owner(on_dbus_name_appeared, on_dbus_name_vanished) self.window.present_with_time(Gtk.get_current_event_time()) def _on_configure(self, _window: Gtk.ApplicationWindow, event: Gdk.EventConfigure) -> bool: width, height, x, y = self.Config["window-properties"] if event.x != x or event.y != y or event.width != width or event.height != height: self.Config["window-properties"] = [ event.width, event.height, event.x, event.y ] return False def on_adapter_changed(self, lst: ManagerDeviceList, adapter: str) -> None: if adapter is not None: self.List.populate_devices() def inquiry(self) -> None: def prop_changed(_lst: ManagerDeviceList, _adapter: Adapter, key_value: Tuple[str, Any]) -> None: key, value = key_value if key == "Discovering" and not value: prog.finalize() self.List.disconnect(s1) self.List.disconnect(s2) def on_progress(_lst: ManagerDeviceList, frac: float) -> None: if abs(1.0 - frac) <= 0.00001: if not prog.started(): prog.start() else: prog.fraction(frac) prog = ManagerProgressbar(self, text=_("Searching")) prog.connect("cancelled", lambda x: self.List.stop_discovery()) def on_error(e: Exception) -> None: prog.finalize() MessageArea.show_message(*e_(e)) self.List.discover_devices(error_handler=on_error) s1 = self.List.connect("discovery-progress", on_progress) s2 = self.List.connect("adapter-property-changed", prop_changed) @staticmethod def bond(device: Device) -> None: def error_handler(e: Exception) -> None: logging.exception(e) message = f"Pairing failed for:\n{device['Alias']} ({device['Address']})" Notification('Bluetooth', message, icon_name="blueman").show() device.pair(error_handler=error_handler) @staticmethod def adapter_properties() -> None: launch("blueman-adapters", name=_("Adapter Preferences")) @staticmethod def toggle_trust(device: Device) -> None: device['Trusted'] = not device['Trusted'] @staticmethod def toggle_blocked(device: Device) -> None: device['Blocked'] = not device['Blocked'] def send(self, device: Device) -> None: adapter = self.List.Adapter assert adapter command = f"blueman-sendto --source={adapter['Address']} --device={device['Address']}" launch(command, name=_("File Sender")) def remove(self, device: Device) -> None: assert self.List.Adapter self.List.Adapter.remove_device(device)
def __init__(self, applet: "BluemanApplet") -> None: super().__init__(title=_("Plugins"), icon_name="blueman", name="PluginDialog", border_width=6, default_width=490, default_height=380, resizable=False, visible=False) self.applet = applet builder = Builder("applet-plugins-widget.ui") self.description = builder.get_widget("description", Gtk.Label) self.icon = builder.get_widget("icon", Gtk.Image) self.author_txt = builder.get_widget("author_txt", Gtk.Label) self.depends_hdr = builder.get_widget("depends_hdr", Gtk.Widget) self.depends_txt = builder.get_widget("depends_txt", Gtk.Label) self.conflicts_hdr = builder.get_widget("conflicts_hdr", Gtk.Widget) self.conflicts_txt = builder.get_widget("conflicts_txt", Gtk.Label) self.plugin_name = builder.get_widget("name", Gtk.Label) self.main_container = builder.get_widget("main_container", Gtk.Bin) self.content_grid = builder.get_widget("content", Gtk.Widget) self.b_prefs = builder.get_widget("b_prefs", Gtk.ToggleButton) self.b_prefs.connect("toggled", self.on_prefs_toggled) self.add(builder.get_widget("all", Gtk.Container)) cr = Gtk.CellRendererToggle() cr.connect("toggled", self.on_toggled) data: List[ListDataDict] = [ { "id": "active", "type": bool, "renderer": cr, "render_attrs": { "active": 0, "activatable": 1, "visible": 1 } }, { "id": "activatable", "type": bool }, { "id": "icon", "type": str, "renderer": Gtk.CellRendererPixbuf(), "render_attrs": { "icon-name": 2 } }, # device caption { "id": "desc", "type": str, "renderer": Gtk.CellRendererText(), "render_attrs": { "markup": 3 }, "view_props": { "expand": True } }, { "id": "name", "type": str }, ] self.list = GenericList(data, headers_visible=False, visible=True) self.list.liststore.set_sort_column_id(3, Gtk.SortType.ASCENDING) self.list.liststore.set_sort_func(3, self.list_compare_func) self.list.selection.connect("changed", self.on_selection_changed) plugin_list = builder.get_widget("plugin_list", Gtk.ScrolledWindow) plugin_info = builder.get_widget("main_scrolled_window", Gtk.ScrolledWindow) plugin_list.add(self.list) # Disable overlay scrolling if Gtk.get_minor_version() >= 16: plugin_list.props.overlay_scrolling = False plugin_info.props.overlay_scrolling = False self.populate() self.sig_a: int = self.applet.Plugins.connect( "plugin-loaded", self.plugin_state_changed, True) self.sig_b: int = self.applet.Plugins.connect( "plugin-unloaded", self.plugin_state_changed, False) self.connect("delete-event", self._on_close) self.list.set_cursor(0)
class Transfer(ServicePlugin): __plugin_info__ = (_("Transfer"), "document-open") def on_load(self, container: Gtk.Box) -> None: self._builder = Builder("services-transfer.ui") self.widget = self._builder.get_widget("transfer", Gtk.Widget) container.pack_start(self.widget, True, True, 0) a = AppletService() if "TransferService" in a.QueryPlugins(): self._setup_transfer() else: self.widget.props.sensitive = False self.widget.props.tooltip_text = _( "Applet's transfer service plugin is disabled") def on_enter(self) -> None: self.widget.props.visible = True def on_leave(self) -> None: self.widget.props.visible = False def on_property_changed(self, config: Gio.Settings, key: str) -> None: value = config[key] if key == "shared-path": self._builder.get_widget( key, Gtk.FileChooserButton).set_current_folder(value) self.option_changed_notify(key, False) def on_apply(self) -> None: if self.on_query_apply_state(): for opt in self.get_options(): if opt == "shared-path": shared_path = self._builder.get_widget( "shared-path", Gtk.FileChooserButton) self._config["shared-path"] = shared_path.get_filename() elif opt == "opp-accept": opp_accept = self._builder.get_widget( "opp-accept", Gtk.CheckButton) self._config["opp-accept"] = opp_accept.get_active() else: raise NotImplementedError("Unknow option: %s" % opt) self.clear_options() logging.info("transfer apply") def on_query_apply_state(self) -> bool: opts = self.get_options() if not opts: return False else: return True def _setup_transfer(self) -> None: self._config = Config("org.blueman.transfer") self._config.connect("changed", self.on_property_changed) opp_accept = self._builder.get_widget("opp-accept", Gtk.CheckButton) shared_path = self._builder.get_widget("shared-path", Gtk.FileChooserButton) opp_accept.props.active = self._config["opp-accept"] if self._config["shared-path"]: shared_path.set_current_folder(self._config["shared-path"]) opp_accept.connect("toggled", lambda x: self.option_changed_notify("opp-accept")) shared_path.connect( "file-set", lambda x: self.option_changed_notify("shared-path"))
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() }
def __init__(self, device: Device, adapter_path: str, files: Iterable[str]) -> None: 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) builder = Builder("send-dialog.ui") grid = builder.get_widget("sendto", Gtk.Grid) content_area = self.get_content_area() content_area.add(grid) self.l_dest = builder.get_widget("l_dest", Gtk.Label) self.l_file = builder.get_widget("l_file", Gtk.Label) self.pb = builder.get_widget("pb", Gtk.ProgressBar) self.pb.props.text = _("Connecting") self.device = device self.adapter = Adapter(obj_path=adapter_path) self.manager = Manager() self.files: List[Gio.File] = [] self.num_files = 0 self.object_push: Optional[ObjectPush] = None self.object_push_handlers: List[int] = [] self.transfer: Optional[Transfer] = None self.total_bytes = 0 self.total_transferred = 0 self._last_bytes = 0 self._last_update = 0.0 self.error_dialog: Optional[ErrorDialog] = 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( f"Skipping non existing file {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(f"Skipping directory {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) parent = self.get_toplevel() assert isinstance(parent, Gtk.Container) d = ErrorDialog( _("obexd not available"), _("Failed to autostart obex service. Make sure the obex " "daemon is running"), parent=parent) d.run() d.destroy() self.emit("result", False) else: # Fail on anything else raise basename = self.files[-1].get_basename() assert basename is not None self.l_file.props.label = basename self.client.connect('session-failed', self.on_session_failed) logging.info(f"Sending to {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 Network(ServicePlugin): __plugin_info__ = (_("Network"), "network-workgroup") def on_load(self, container: Gtk.Box) -> None: self._builder = Builder("services-network.ui") self.widget = self._builder.get_widget("network_frame", Gtk.Widget) container.pack_start(self.widget, True, True, 0) self.interfaces: List[Tuple[str, Union[ipaddress.IPv4Interface, ipaddress.IPv6Interface]]] = [] netifs = get_local_interfaces() for iface in netifs: if iface != "lo" and iface != "pan1": logging.info(iface) ipiface = ipaddress.ip_interface('/'.join( cast(Tuple[str, str], netifs[iface]))) self.interfaces.append((iface, ipiface)) self.setup_network() try: self.ip_check() except (ValueError, ipaddress.AddressValueError) as e: logging.exception(e) def on_enter(self) -> None: self.widget.props.visible = True def on_leave(self) -> None: self.widget.props.visible = False def on_apply(self) -> None: if self.on_query_apply_state(): logging.info("network apply") m = Mechanism() nap_enable = self._builder.get_widget("nap-enable", Gtk.CheckButton) if nap_enable.props.active: if self._builder.get_widget("r_dhcpd", Gtk.RadioButton).props.active: stype = "DhcpdHandler" elif self._builder.get_widget("r_dnsmasq", Gtk.RadioButton).props.active: stype = "DnsMasqHandler" elif self._builder.get_widget("r_udhcpd", Gtk.RadioButton).props.active: stype = "UdhcpdHandler" net_ip = self._builder.get_widget("net_ip", Gtk.Entry) try: m.EnableNetwork('(sss)', net_ip.props.text, "255.255.255.0", stype) if not self.Config["nap-enable"]: self.Config["nap-enable"] = True except Exception as e: parent = self.widget.get_toplevel() assert isinstance(parent, Gtk.Container) d = ErrorDialog("<b>Failed to apply network settings</b>", excp=e, parent=parent) d.run() d.destroy() return else: self.Config["nap-enable"] = False m.DisableNetwork() self.clear_options() def ip_check(self) -> None: entry = self._builder.get_widget("net_ip", Gtk.Entry) try: nap_ipiface = ipaddress.ip_interface('/'.join( (entry.props.text, '255.255.255.0'))) except (ValueError, ipaddress.AddressValueError): entry.props.secondary_icon_name = "dialog-error" entry.props.secondary_icon_tooltip_text = _("Invalid IP address") raise for iface, ipiface in self.interfaces: if nap_ipiface.ip == ipiface.ip: error_message = _( "IP address conflicts with interface %s which has the same address" % iface) tooltip_text = error_message entry.props.secondary_icon_name = "dialog-error" entry.props.secondary_icon_tooltip_text = tooltip_text raise ValueError(error_message) elif nap_ipiface.network == ipiface.network: tooltip_text = _( "IP address overlaps with subnet of interface %s, which has the following configuration %s/%s\n" "This may cause incorrect network behavior" % (iface, ipiface.ip, ipiface.netmask)) entry.props.secondary_icon_name = "dialog-warning" entry.props.secondary_icon_tooltip_text = tooltip_text return entry.props.secondary_icon_name = None def on_query_apply_state(self) -> Union[bool, "Literal[-1]"]: opts = self.get_options() if not opts: return False if "ip" in opts: try: self.ip_check() except (ValueError, ipaddress.AddressValueError) as e: logging.exception(e) return -1 return True def setup_network(self) -> None: self.Config = Config("org.blueman.network") nap_enable = self._builder.get_widget("nap-enable", Gtk.CheckButton) r_dnsmasq = self._builder.get_widget("r_dnsmasq", Gtk.RadioButton) r_dhcpd = self._builder.get_widget("r_dhcpd", Gtk.RadioButton) r_udhcpd = self._builder.get_widget("r_udhcpd", Gtk.RadioButton) net_ip = self._builder.get_widget("net_ip", Gtk.Entry) rb_nm = self._builder.get_widget("rb_nm", Gtk.RadioButton) rb_blueman = self._builder.get_widget("rb_blueman", Gtk.RadioButton) rb_dun_nm = self._builder.get_widget("rb_dun_nm", Gtk.RadioButton) rb_dun_blueman = self._builder.get_widget("rb_dun_blueman", Gtk.RadioButton) nap_frame = self._builder.get_widget("nap_frame", Gtk.Frame) warning = self._builder.get_widget("warning", Gtk.Box) if not self.Config["nap-enable"]: nap_frame.props.sensitive = False nc = NetConf.get_default() if nc.ip4_address is not None: # previously we stored a bytearray, ipaddress module reads both net_ip.props.text = str(ipaddress.ip_address(nc.ip4_address)) nap_enable.props.active = True else: net_ip.props.text = "10.%d.%d.1" % (randint(0, 255), randint( 0, 255)) if nc.get_dhcp_handler() is None: nap_frame.props.sensitive = False nap_enable.props.active = False r_dnsmasq.props.active = True self.Config["nap-enable"] = False have_dhcpd = have("dhcpd3") or have("dhcpd") have_dnsmasq = have("dnsmasq") have_udhcpd = have("udhcpd") if nc.get_dhcp_handler() == DnsMasqHandler and have_dnsmasq: r_dnsmasq.props.active = True elif nc.get_dhcp_handler() == DhcpdHandler and have_dhcpd: r_dhcpd.props.active = True elif nc.get_dhcp_handler() == UdhcpdHandler and have_udhcpd: r_udhcpd.props.active = True else: r_dnsmasq.props.active = True if not have_dnsmasq and not have_dhcpd and not have_udhcpd: nap_frame.props.sensitive = False warning.props.visible = True warning.props.sensitive = True nap_enable.props.sensitive = False self.Config["nap-enable"] = False if not have_dnsmasq: r_dnsmasq.props.sensitive = False r_dnsmasq.props.active = False if not have_dhcpd: r_dhcpd.props.sensitive = False r_dhcpd.props.active = False if not have_udhcpd: r_udhcpd.props.sensitive = False r_udhcpd.props.active = False r_dnsmasq.connect("toggled", lambda x: self.option_changed_notify("dnsmasq")) r_dhcpd.connect("toggled", lambda x: self.option_changed_notify("dhcpd")) r_udhcpd.connect("toggled", lambda x: self.option_changed_notify("udhcpd")) net_ip.connect("changed", lambda x: self.option_changed_notify("ip", False)) nap_enable.connect("toggled", lambda x: self.option_changed_notify("nap_enable")) self.Config.bind_to_widget("nap-enable", nap_enable, "active", Gio.SettingsBindFlags.GET) nap_enable.bind_property("active", nap_frame, "sensitive", GObject.BindingFlags.DEFAULT) applet = AppletService() avail_plugins = applet.QueryAvailablePlugins() active_plugins = applet.QueryPlugins() def dun_support_toggled(rb: Gtk.RadioButton, x: str) -> None: if rb.props.active and x == "nm": applet.SetPluginConfig('(sb)', "PPPSupport", False) applet.SetPluginConfig('(sb)', "NMDUNSupport", True) elif rb.props.active and x == "blueman": applet.SetPluginConfig('(sb)', "NMDUNSupport", False) applet.SetPluginConfig('(sb)', "PPPSupport", True) def pan_support_toggled(rb: Gtk.RadioButton, x: str) -> None: if rb.props.active and x == "nm": applet.SetPluginConfig('(sb)', "DhcpClient", False) applet.SetPluginConfig('(sb)', "NMPANSupport", True) elif rb.props.active and x == "blueman": applet.SetPluginConfig('(sb)', "NMPANSupport", False) applet.SetPluginConfig('(sb)', "DhcpClient", True) if "PPPSupport" in active_plugins: rb_dun_blueman.props.active = True if "NMDUNSupport" in avail_plugins: rb_dun_nm.props.sensitive = True else: rb_dun_nm.props.sensitive = False rb_dun_nm.props.tooltip_text = _( "Not currently supported with this setup") if "DhcpClient" in active_plugins: rb_blueman.props.active = True if "NMPANSupport" in avail_plugins: rb_nm.props.sensitive = True else: rb_nm.props.sensitive = False rb_nm.props.tooltip_text = _( "Not currently supported with this setup") if "NMPANSupport" in active_plugins: rb_nm.props.active = True if "NMDUNSupport" in active_plugins: rb_dun_nm.props.active = True rb_nm.connect("toggled", pan_support_toggled, "nm") rb_blueman.connect("toggled", pan_support_toggled, "blueman") rb_dun_nm.connect("toggled", dun_support_toggled, "nm") rb_dun_blueman.connect("toggled", dun_support_toggled, "blueman")
def __init__(self, plugin: "NetUsage"): if not Dialog.running: Dialog.running = True else: return self.plugin = plugin builder = Builder("net-usage.ui") self.dialog = builder.get_widget("dialog", Gtk.Dialog) self.dialog.connect("response", self.on_response) cr1 = Gtk.CellRendererText() cr1.props.ellipsize = Pango.EllipsizeMode.END self._handlerids: List[int] = [] self._handlerids.append( plugin.connect("monitor-added", self.monitor_added)) self._handlerids.append( plugin.connect("monitor-removed", self.monitor_removed)) self._handlerids.append(plugin.connect("stats", self.on_stats)) cr2 = Gtk.CellRendererText() cr2.props.sensitive = False cr2.props.style = Pango.Style.ITALIC self.liststore = Gtk.ListStore(str, str, str, object) self.e_ul = builder.get_widget("e_ul", Gtk.Entry) self.e_dl = builder.get_widget("e_dl", Gtk.Entry) self.e_total = builder.get_widget("e_total", Gtk.Entry) self.l_started = builder.get_widget("l_started", Gtk.Label) self.l_duration = builder.get_widget("l_duration", Gtk.Label) self.b_reset = builder.get_widget("b_reset", Gtk.Button) self.b_reset.connect("clicked", self.on_reset) self.cb_device = builder.get_widget("cb_device", Gtk.ComboBox) self.cb_device.props.model = self.liststore self.cb_device.connect("changed", self.on_selection_changed) self.cb_device.pack_start(cr1, True) self.cb_device.add_attribute(cr1, 'markup', 1) self.cb_device.pack_start(cr2, False) self.cb_device.add_attribute(cr2, 'markup', 2) general_config = Config("org.blueman.general") added = False for d in general_config["netusage-dev-list"]: for m in plugin.monitors: if d == m.device["Address"]: titer = self.liststore.append([ d, self.get_caption(m.device["Alias"], m.device["Address"]), _("Connected:") + " " + m.interface, m ]) if self.cb_device.get_active() == -1: self.cb_device.set_active_iter(titer) added = True break if not added: name = d if self.plugin.parent.Manager: device = self.plugin.parent.Manager.find_device(d) if device is None: pass else: name = self.get_caption(device["Alias"], device["Address"]) self.liststore.append([d, name, _("Not Connected"), None]) added = False if len(self.liststore) > 0: if self.cb_device.get_active() == -1: self.cb_device.set_active(0) else: msg = _( "No usage statistics are available yet. Try establishing a connection first and " "then check this page.") d = Gtk.MessageDialog(parent=self.dialog, modal=True, type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.CLOSE, text=msg) d.props.icon_name = "blueman" d.run() d.destroy() self.on_response(None, None) return self.dialog.show()