示例#1
0
 def set_op(self, device: Device, message: str) -> None:
     ManagerDeviceMenu.__ops__[device.get_object_path()] = message
     for inst in ManagerDeviceMenu.__instances__:
         logging.info(f"op: regenerating instance {inst}")
         if inst.SelectedDevice == self.SelectedDevice and not (
                 inst.is_popup and not inst.props.visible):
             inst.generate()
示例#2
0
    def disconnect_service(self,
                           device: Device,
                           uuid: str = GENERIC_CONNECT,
                           port: int = 0) -> None:
        def ok(_obj: AppletService, _result: None, _user_date: None) -> None:
            logging.info("disconnect success")
            self.generate()

        def err(_obj: Optional[AppletService], result: GLib.Error,
                _user_date: None) -> None:
            logging.warning(f"disconnect failed {result}")
            msg, tb = e_(result.message)
            MessageArea.show_message(_("Disconnection Failed: ") + msg, tb)
            self.generate()

        if self._appl is None:
            err(None, GLib.Error('Applet DBus Service not available'), None)
            return

        self._appl.DisconnectService('(osd)',
                                     device.get_object_path(),
                                     uuid,
                                     port,
                                     result_handler=ok,
                                     error_handler=err,
                                     timeout=GLib.MAXINT)
示例#3
0
    def generic_connect(self, _item: Optional[Gtk.MenuItem], device: Device,
                        connect: bool) -> None:
        def fail(_obj: AppletService, result: GLib.Error,
                 _user_data: None) -> None:
            logging.info(f"fail: {result}")
            prog.message(_("Failed"))
            self.unset_op(device)
            self._handle_error_message(result.message)

        def success(_obj: AppletService, _result: None,
                    _user_data: None) -> None:
            logging.info("success")
            prog.message(_("Success!"))
            MessageArea.close()
            self.unset_op(device)

        assert self._appl

        if connect:
            self.set_op(self.SelectedDevice, _("Connecting…"))
            self._appl.ConnectService("(os)",
                                      device.get_object_path(),
                                      '00000000-0000-0000-0000-000000000000',
                                      result_handler=success,
                                      error_handler=fail,
                                      timeout=GLib.MAXINT)
        else:
            self.set_op(self.SelectedDevice, _("Disconnecting…"))
            self._appl.DisconnectService(
                "(osd)",
                device.get_object_path(),
                '00000000-0000-0000-0000-000000000000',
                0,
                result_handler=success,
                error_handler=fail,
                timeout=GLib.MAXINT)

        prog = ManagerProgressbar(self.Blueman)

        def abort() -> None:
            assert self._appl is not None  # https://github.com/python/mypy/issues/2608
            self._appl.DisconnectService(
                "(osd)", device.get_object_path(),
                '00000000-0000-0000-0000-000000000000', 0)

        prog.connect("cancelled", lambda x: abort())
        prog.start()
    def device_remove_event(self, device: Device) -> None:
        tree_iter = self.find_device(device)

        row_fader = self.get(tree_iter, "row_fader")["row_fader"]
        super().device_remove_event(device)
        self._faderhandlers.update({
            device.get_object_path(): row_fader.connect("animation-finished", self.__on_fader_finished, device)
        })

        row_fader.thaw()
        self.emit("device-selected", None, None)
        row_fader.animate(start=row_fader.get_state(), end=0.0, duration=400)
示例#5
0
    def generic_connect(self, _item: Gtk.MenuItem, device: Device,
                        connect: bool) -> None:
        def fail(_obj: AppletService, result: GLib.Error,
                 _user_data: None) -> None:
            logging.info(f"fail: {result}")
            prog.message(_("Failed"))
            self.unset_op(device)
            msg, tb = e_(result.message)
            MessageArea.show_message(_("Connection Failed: ") + msg)

        def success(_obj: AppletService, _result: None,
                    _user_data: None) -> None:
            logging.info("success")
            prog.message(_("Success!"))
            MessageArea.close()
            self.unset_op(device)

        assert self._appl

        if connect:
            self.set_op(self.SelectedDevice, _("Connecting…"))
            self._appl.ConnectService("(os)",
                                      device.get_object_path(),
                                      '00000000-0000-0000-0000-000000000000',
                                      result_handler=success,
                                      error_handler=fail,
                                      timeout=GLib.MAXINT)
        else:
            self.set_op(self.SelectedDevice, _("Disconnecting…"))
            self._appl.DisconnectService(
                "(osd)",
                device.get_object_path(),
                '00000000-0000-0000-0000-000000000000',
                0,
                result_handler=success,
                error_handler=fail,
                timeout=GLib.MAXINT)

        prog = ManagerProgressbar(self.Blueman, False)
        prog.start()
示例#6
0
    def find_device(self, device: Device) -> Optional[Gtk.TreeIter]:
        object_path = device.get_object_path()
        try:
            row = self.path_to_row[object_path]
            if row.valid():
                path = row.get_path()
                tree_iter = self.liststore.get_iter(path)
                return tree_iter
            else:
                del self.path_to_row[object_path]
                return None

        except KeyError:
            return None
示例#7
0
    def add_device(self, device: Device) -> None:
        # device belongs to another adapter
        if not self.Adapter or not device[
                'Adapter'] == self.Adapter.get_object_path():
            return

        logging.info("adding new device")
        tree_iter = self.liststore.append()

        self.set(tree_iter, device=device)
        self.row_setup_event(tree_iter, device)

        object_path = device.get_object_path()
        timestamp = datetime.strftime(datetime.now(), '%Y%m%d%H%M%S%f')
        self.set(tree_iter, dbus_path=object_path, timestamp=float(timestamp))
示例#8
0
    def bind_to_menuitem(self, item: Gtk.CheckMenuItem, device: Device, uuid: str) -> None:
        data = device.get_object_path(), uuid

        def switch(active: bool) -> None:
            services = set(self["services"])
            if active:
                self["services"] = set(services).union({data})
            else:
                self["services"] = set(self["services"]).difference({data})

        def on_change(config: AutoConnectConfig, key: str) -> None:
            if key == "services":
                item.props.active = data in set(config[key])

        item.props.active = data in set(self["services"])
        item.connect("toggled", lambda i: switch(i.props.active))
        self.connect("changed", on_change)
示例#9
0
    def _update_power_levels(self, tree_iter: Gtk.TreeIter, device: Device, cinfo: conn_info) -> None:
        row = self.get(tree_iter, "cell_fader", "battery", "rssi", "lq", "tpl")

        bars = {}

        if device["ServicesResolved"] and any(ServiceUUID(uuid).short_uuid == BATTERY_SERVICE_SVCLASS_ID
                                              for uuid in device["UUIDs"]):
            bars["battery"] = Battery(obj_path=device.get_object_path())["Percentage"]

        # cinfo init may fail for bluetooth devices version 4 and up
        # FIXME Workaround is horrible and we should show something better
        if cinfo.failed:
            if not bars:
                bars = {"rssi": 100.0, "tpl": 100.0, "lq": 100.0}
        else:
            try:
                bars["rssi"] = max(50 + float(cinfo.get_rssi()) / 127 * 50, 10)
            except ConnInfoReadError:
                bars["rssi"] = 50
            try:
                bars["lq"] = max(50 + float(cinfo.get_lq()) / 127 * 50, 10)
            except ConnInfoReadError:
                bars["lq"] = 50
            try:
                bars["tpl"] = max(float(cinfo.get_tpl()) / 255 * 100, 10)
            except ConnInfoReadError:
                bars["tpl"] = 0

        if row["battery"] == row["rssi"] == row["tpl"] == row["lq"] == 0:
            self._prepare_fader(row["cell_fader"]).animate(start=0.0, end=1.0, duration=400)

        w = 14 * self.get_scale_factor()
        h = 48 * self.get_scale_factor()

        for (name, perc) in bars.items():
            if round(row[name], -1) != round(perc, -1):
                icon_name = f"blueman-{name}-{int(round(perc, -1))}.png"
                icon = GdkPixbuf.Pixbuf.new_from_file_at_scale(os.path.join(PIXMAP_PATH, icon_name), w, h, True)
                self.set(tree_iter, **{name: perc, f"{name}_pb": icon})
示例#10
0
 def __on_fader_finished(self, fader: TreeRowFade, device: Device) -> None:
     fader.disconnect(self._faderhandlers.pop(device.get_object_path()))
     fader.freeze()
示例#11
0
class Device(GObject.GObject):
    __gsignals__ = {
        'invalidated': (GObject.SignalFlags.NO_HOOKS, None, ()),
        'property-changed': (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_PYOBJECT, GObject.TYPE_PYOBJECT,)),
    }

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

    @property
    def Services(self):
        if len(self.__services) == 0:
            self.init_services()

        return self.__services

    def __del__(self):
        dprint("deleting device", self.get_object_path())
        self.Destroy()

    def get_object_path(self):
        if not self.Fake:
            return self._obj_path

    def on_device_removed(self, path):
        if path == self._obj_path:
            self.emit("invalidated")
            self.Destroy()

    def init_services(self):
        dprint("Loading services")

        if not self.Fake:
            services = self.Device.list_services()
            self.__services = {}
            for service in services:
                name = service.get_interface_name().split(".")
                if name[0] == 'org' and name[1] == 'bluez':
                    name = name[2].lower()
                    if name.endswith('1'):
                        name = name[:-1]
                    self.__services[name] = service

    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
        if key == "UUIDs":
            self.init_services()

    def Destroy(self):
        dprint("invalidating device", self.get_object_path())
        self.Valid = False
        #self.Device = None
        self.Signals.DisconnectAll()

    #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
示例#12
0
    def on_request_menu_items(self, manager_menu: ManagerDeviceMenu,
                              device: Device) -> List[DeviceMenuItem]:
        items: List[DeviceMenuItem] = []
        appl = AppletService()

        services = get_services(device)

        connectable_services = [
            service for service in services if service.connectable
        ]
        for service in connectable_services:
            item: Gtk.MenuItem = create_menuitem(service.name, service.icon)
            if service.description:
                item.props.tooltip_text = service.description
            item.connect(
                "activate", lambda _item: manager_menu.connect_service(
                    service.device, service.uuid))
            items.append(
                DeviceMenuItem(item, DeviceMenuItem.Group.CONNECT,
                               service.priority))
            item.props.sensitive = service.available
            item.show()

        connected_services = [
            service for service in services if service.connected_instances
        ]
        for service in connected_services:
            for instance in service.connected_instances:
                surface = self._make_x_icon(service.icon, 16)
                item = create_menuitem(instance.name, surface=surface)
                item.connect(
                    "activate", lambda _item: manager_menu.disconnect_service(
                        service.device, service.uuid, instance.port))
                items.append(
                    DeviceMenuItem(item, DeviceMenuItem.Group.DISCONNECT,
                                   service.priority + 100))
                item.show()

        if services:
            config = AutoConnectConfig()
            autoconnect_services = set(config["services"])
            for service in services:
                if service.connected_instances or (
                        device.get_object_path(),
                        service.uuid) in autoconnect_services:
                    item = Gtk.CheckMenuItem(label=service.name)
                    config.bind_to_menuitem(item, device, service.uuid)
                    item.show()
                    items.append(
                        DeviceMenuItem(item, DeviceMenuItem.Group.AUTOCONNECT,
                                       service.priority))

        for action, priority in set((action, service.priority)
                                    for service in services
                                    for action in service.common_actions
                                    if any(plugin in appl.QueryPlugins()
                                           for plugin in action.plugins)):
            item = create_menuitem(action.title, action.icon)
            items.append(
                DeviceMenuItem(item, DeviceMenuItem.Group.ACTIONS,
                               priority + 200))
            item.show()
            item.connect("activate",
                         self._get_activation_handler(action.callback))

        return items
示例#13
0
 def get_op(self, device: Device) -> Optional[str]:
     try:
         return ManagerDeviceMenu.__ops__[device.get_object_path()]
     except KeyError:
         return None
示例#14
0
 def __init__(self, device: Device, uuid: str):
     super().__init__(device, uuid)
     self._service = Network(obj_path=device.get_object_path())
示例#15
0
 def remove_device(self, device: Device) -> None:
     param = GLib.Variant('(o)', (device.get_object_path(), ))
     self._call('RemoveDevice', param)
示例#16
0
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
示例#17
0
文件: Device.py 项目: posophe/blueman
class Device(GObject.GObject):
    __gsignals__ = {
        'invalidated': (GObject.SignalFlags.NO_HOOKS, None, ()),
        'property-changed': (GObject.SignalFlags.NO_HOOKS, None, (
            GObject.TYPE_PYOBJECT,
            GObject.TYPE_PYOBJECT,
        )),
    }

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

    @property
    def Services(self):
        if len(self.__services) == 0:
            self.init_services()

        return self.__services

    def __del__(self):
        dprint("deleting device", self.get_object_path())
        self.Destroy()

    def get_object_path(self):
        if not self.Fake:
            return self._obj_path

    def on_device_removed(self, path):
        if path == self._obj_path:
            self.emit("invalidated")
            self.Destroy()

    def init_services(self):
        dprint("Loading services")

        if not self.Fake:
            services = self.Device.list_services()
            self.__services = {}
            for service in services:
                name = service.get_interface_name().split(".")
                if name[0] == 'org' and name[1] == 'bluez':
                    name = name[2].lower()
                    if name.endswith('1'):
                        name = name[:-1]
                    self.__services[name] = service

    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
        if key == "UUIDs":
            self.init_services()

    def Destroy(self):
        dprint("invalidating device", self.get_object_path())
        self.Valid = False
        #self.Device = None
        self.Signals.DisconnectAll()

    #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