def Handle(self, signame, handler): SignalTracker.Handle(self, "dbus", self.bus, handler, signame, self.dbus_interface, path=self.object_path)
class GameControllerWakelock(AppletPlugin): __description__ = _("Temporarily suspends the screensaver when a bluetooth game controller is connected.") __author__ = "bwRavencl" __icon__ = "input-gaming" def on_load(self, applet): self.wake_lock = 0 self.root_window_id = "0x%x" % Gdk.Screen.get_default().get_root_window().get_xid() self.signals = SignalTracker() self.signals.Handle("bluez", bluez.Device(), self.on_device_property_changed, "PropertyChanged", path_keyword="path") def on_unload(self): if self.wake_lock: self.wake_lock = 1 self.suspend_screensaver("resume") self.signals.DisconnectAll() def on_device_property_changed(self, key, value, path): if key == "Connected": klass = Device(path).get_properties()["Class"] & 0x1fff if klass == 0x504 or klass == 0x508: if value: self.xdg_screensaver("suspend") else: self.xdg_screensaver("resume") def xdg_screensaver(self, action): if action == "resume": if self.wake_lock == 0: pass elif self.wake_lock > 1: self.wake_lock -= 1 pass elif action == "suspend" and self.wake_lock >= 1: self.wake_lock += 1 pass command = ["xdg-screensaver", action, self.root_window_id] try: process = subprocess.Popen(command, stderr=subprocess.PIPE) _, stderr = process.communicate() if process.returncode != 0: dprint(" ".join(command) + " failed with: " + stderr) pass if action == "suspend": self.wake_lock += 1 elif action == "resume": self.wake_lock = 0 except: dprint(traceback.format_exc())
class NMMonitor(MonitorBase): def __init__(self, device, nm_dev_path): MonitorBase.__init__(self, device, "NM") dprint("created nm monitor for path", nm_dev_path) self.signals = SignalTracker() self.signals.Handle("dbus", dbus.SystemBus(), self.on_ppp_stats, "PppStats", "org.freedesktop.NetworkManager.Device.Serial", path=nm_dev_path) self.signals.Handle(device, "property-changed", self.on_device_property_changed) def on_ppp_stats(self, rx, tx): self.update_stats(tx, rx) def on_device_property_changed(self, device, key, value): if key == "Connected" and not value: self.signals.DisconnectAll() self.Disconnect()
class NewConnectionBuilder: DEVICE_STATE_DISCONNECTED = 30 DEVICE_STATE_ACTIVATED = 100 DEVICE_STATE_DEACTIVATING = 110 DEVICE_STATE_FAILED = 120 def __init__(self, parent, service, ok_cb, err_cb): self.parent = parent self.ok_cb = ok_cb self.err_cb = err_cb self.signals = SignalTracker() self.device = None self.connection = None self.signals.Handle("dbus", parent.bus, self.on_nm_device_added, "DeviceAdded", "org.freedesktop.NetworkManager") self.signals.Handle("dbus", parent.bus, self.on_nma_new_connection, "NewConnection", self.parent.settings_interface) self.device = self.parent.find_device(service.device.Address) self.connection = self.parent.find_connection(service.device.Address, "panu") if not self.connection: # This is for compatibility with network-manager < 0.9.8.6. Newer versions that support BlueZ 5 add a # default connection automatically addr_bytes = bytearray.fromhex( str.replace(str(service.device.Address), ':', ' ')) parent.nma.AddConnection({ 'connection': { 'id': '%s on %s' % (service.name, service.device.Alias), 'uuid': str(uuid1()), 'autoconnect': False, 'type': 'bluetooth' }, 'bluetooth': { 'bdaddr': dbus.ByteArray(addr_bytes), 'type': 'panu' }, 'ipv4': { 'method': 'auto' }, 'ipv6': { 'method': 'auto' } }) GObject.timeout_add(1000, self.signal_wait_timeout) else: self.init_connection() def cleanup(self): self.signals.DisconnectAll() def signal_wait_timeout(self): if not self.device or not self.connection: self.err_cb( dbus.DBusException( "Network Manager did not support the connection")) if self.connection: self.remove_connection() self.cleanup() def on_nm_device_added(self, path): dprint(path) self.device = path if self.device and self.connection: self.init_connection() def on_nma_new_connection(self, path): dprint(path) self.connection = path if self.device and self.connection: self.init_connection() def init_connection(self): self.cleanup() dprint("activating", self.connection, self.device) if not self.device or not self.connection: self.err_cb( dbus.DBusException( "Network Manager did not support the connection")) if self.connection: self.remove_connection() self.cleanup() else: self.signals.Handle("dbus", self.parent.bus, self.on_device_state, "StateChanged", "org.freedesktop.NetworkManager.Device", path=self.device) args = [self.connection, self.device, self.connection] if self.parent.legacy: args.insert(0, self.parent.settings_bus) self.parent.nm.ActivateConnection(*args) def remove_connection(self): self.parent.remove_connection(self.connection) def on_device_state(self, state, oldstate, reason): dprint("state=", state, "oldstate=", oldstate, "reason=", reason) if (state <= self.DEVICE_STATE_DISCONNECTED or state == self.DEVICE_STATE_DEACTIVATING) and \ self.DEVICE_STATE_DISCONNECTED < oldstate <= self.DEVICE_STATE_ACTIVATED: if self.err_cb: self.err_cb(dbus.DBusException("Connection was interrupted")) self.remove_connection() self.cleanup() elif state == self.DEVICE_STATE_FAILED: self.err_cb( dbus.DBusException( "Network Manager Failed to activate the connection")) self.remove_connection() self.cleanup() elif state == self.DEVICE_STATE_ACTIVATED: self.ok_cb() self.err_cb = None self.ok_cb = None
class SerialManager(AppletPlugin): __icon__ = "blueman-serial" __author__ = "Walmis" __description__ = _( "Standard SPP profile connection handler, allows executing custom actions" ) __author__ = "walmis" __options__ = { "script": { "type": str, "default": "", "name": _("Script to execute on connection"), "desc": _("<span size=\"small\">The following arguments will be passed:\n" "Address, Name, service name, uuid16s, rfcomm node\n" "For example:\n" "AA:BB:CC:DD:EE:FF, Phone, DUN service, 0x1103, /dev/rfcomm0\n" "uuid16s are returned as a comma seperated list\n\n" "Upon device disconnection the script will be sent a HUP signal</span>" ) }, } def on_load(self, applet): self.signals = SignalTracker() self.signals.Handle("dbus", dbus.SystemBus(), self.on_device_property_changed, "PropertyChanged", "org.bluez.Device", path_keyword="path") self.scripts = {} def on_unload(self): self.signals.DisconnectAll() for k in self.scripts.iterkeys(): self.terminate_all_scripts(k) def on_device_property_changed(self, key, value, path): if key == "Connected" and not value: d = Device(path) self.terminate_all_scripts(d.Address) def on_rfcomm_connected(self, device, port, uuid): uuid16 = sdp_get_serial_type(device.Address, uuid) if SERIAL_PORT_SVCLASS_ID in uuid16: Notification( _("Serial port connected"), _("Serial port service on device <b>%s</b> now will be available via <b>%s</b>" ) % (device.Alias, port), pixbuf=get_icon("blueman-serial", 48), status_icon=self.Applet.Plugins.StatusIcon) self.call_script(device.Address, device.Alias, sdp_get_serial_name(device.Address, uuid), uuid16, port) def terminate_all_scripts(self, address): try: for p in self.scripts[address].itervalues(): dprint("Sending HUP to", p.pid) os.killpg(p.pid, signal.SIGHUP) except: pass def on_script_closed(self, pid, cond, (address, node)): del self.scripts[address][node] dprint("Script with PID", pid, "closed")
class PowerManager(AppletPlugin): __depends__ = ["StatusIcon", "Menu"] __unloadable__ = True __description__ = _("Controls Bluetooth adapter power states") __author__ = "Walmis" __icon__ = "gnome-power-manager" def on_load(self, applet): AppletPlugin.add_method(self.on_power_state_query) AppletPlugin.add_method(self.on_power_state_change_requested) AppletPlugin.add_method(self.on_power_state_changed) self.add_dbus_method(self.SetBluetoothStatus, in_signature="b", out_signature="") self.add_dbus_method(self.GetBluetoothStatus, in_signature="", out_signature="b") self.BluetoothStatusChanged = self.add_dbus_signal( "BluetoothStatusChanged", signature="b") self.Applet = applet self.item = create_menuitem(_("<b>Bluetooth Off</b>"), get_icon("gtk-stop", 16)) self.item.get_child().set_markup(_("<b>Turn Bluetooth Off</b>")) self.item.props.tooltip_text = _("Turn off all adapters") self.signals = SignalTracker() self.signals.Handle("dbus", dbus.SystemBus(), self.adapter_property_changed, "PropertyChanged", "org.bluez.Adapter", "org.bluez", path_keyword="path") self.signals.Handle(self.item, "activate", lambda x: self.on_bluetooth_toggled()) self.Applet.Plugins.Menu.Register(self, self.item, 0) self.adapter_state = True self.current_state = True self.power_changeable = True self.request_in_progress = False self.STATE_ON = 2 self.STATE_OFF = 1 self.STATE_OFF_FORCED = 0 def on_unload(self): self.signals.DisconnectAll() self.Applet.Plugins.Menu.Unregister(self) @property def CurrentState(self): return self.current_state def on_manager_state_changed(self, state): if state: def timeout(): self.adapter_state = self.get_adapter_state() self.RequestPowerState(self.adapter_state) gobject.timeout_add(1000, timeout) def get_adapter_state(self): adapters = self.Applet.Manager.ListAdapters() for adapter in adapters: props = adapter.GetProperties() if not props["Powered"]: return False return bool(adapters) def set_adapter_state(self, state): try: dprint(state) adapters = self.Applet.Manager.ListAdapters() for adapter in adapters: adapter.SetProperty("Powered", state) self.adapter_state = state except Exception as e: dprint("Exception occurred", e) class Callback(object): def __init__(self, parent, state): self.parent = parent self.num_cb = 0 self.called = 0 self.state = state self.success = False self.timer = gobject.timeout_add(5000, self.timeout) def __call__(self, result): self.called += 1 if result: self.success = True self.check() def check(self): if self.called == self.num_cb: dprint("callbacks done") self.parent.set_adapter_state(self.state) gobject.source_remove(self.timer) self.parent.request_in_progress = False def timeout(self): dprint("Timeout reached while setting power state") self.parent.UpdatePowerState() self.parent.request_in_progress = False def RequestPowerState(self, state): if self.current_state != state: if not self.request_in_progress: self.request_in_progress = True dprint("Requesting", state) cb = PowerManager.Callback(self, state) rets = self.Applet.Plugins.Run( "on_power_state_change_requested", self, state, cb) cb.num_cb = len(rets) cb.check() self.UpdatePowerState() else: dprint("Another request in progress") def on_power_state_change_requested(self, pm, state, cb): cb(None) def on_power_state_query(self, pm): if self.adapter_state: return self.STATE_ON else: return self.STATE_OFF def on_power_state_changed(self, manager, state): pass #queries other plugins to determine the current power state def UpdatePowerState(self): rets = self.Applet.Plugins.Run("on_power_state_query", self) off = True in map(lambda x: x < self.STATE_ON, rets) foff = self.STATE_OFF_FORCED in rets on = self.STATE_ON in rets new_state = True if foff or off: self.item.get_child().set_markup(_("<b>Turn Bluetooth On</b>")) self.item.props.tooltip_text = _("Turn on all adapters") self.item.set_image( gtk.image_new_from_pixbuf(get_icon("gtk-yes", 16))) if foff: self.item.props.sensitive = False else: self.item.props.sensitive = True new_state = False elif on and self.current_state != True: self.item.get_child().set_markup(_("<b>Turn Bluetooth Off</b>")) self.item.props.tooltip_text = _("Turn off all adapters") self.item.set_image( gtk.image_new_from_pixbuf(get_icon("gtk-stop", 16))) self.item.props.sensitive = True new_state = True dprint("off", off, "\nfoff", foff, "\non", on, "\ncurrent state", self.current_state, "\nnew state", new_state) if self.current_state != new_state: dprint("Signalling", new_state) self.current_state = new_state self.BluetoothStatusChanged(new_state) self.Applet.Plugins.Run("on_power_state_changed", self, new_state) self.Applet.Plugins.StatusIcon.IconShouldChange() #dbus method def SetBluetoothStatus(self, status): self.RequestPowerState(status) #dbus method def GetBluetoothStatus(self): return self.CurrentState def adapter_property_changed(self, key, value, path): if key == "Powered": if value and not self.CurrentState: dprint( "adapter powered on while in off state, turning bluetooth on" ) self.RequestPowerState(True) self.UpdatePowerState() def on_bluetooth_toggled(self): self.RequestPowerState(not self.CurrentState) def on_status_icon_query_icon(self): #opacity = 255 if self.GetBluetoothStatus() else 100 #pixbuf = opacify_pixbuf(pixbuf, opacity) #if opacity < 255: # x_size = int(pixbuf.props.height) # x = get_icon("blueman-x", x_size) # pixbuf = composite_icon(pixbuf, [(x, pixbuf.props.height - x_size, pixbuf.props.height - x_size, 255)]) #return pixbuf if not self.GetBluetoothStatus(): return ("blueman-tray-disabled", "bluetooth-disabled") def on_adapter_added(self, path): adapter = Bluez.Adapter(path) def on_ready(): if not self.adapter_state: adapter.SetProperty("Powered", False) else: adapter.SetProperty("Powered", True) wait_for_adapter(adapter, on_ready)
class DeviceList(GenericList): __gsignals__ = { #@param: device 'device-found': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), #@param: device TreeIter #note: None None is given when there ar no more rows, or when selected device is removed 'device-selected': ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT,) ), #@param: device, TreeIter, (key, value) #note: there is a special property "Fake", it's not a real property, #but it is used to notify when device changes state from "Fake" to a real BlueZ object #the callback would be called with Fake=False 'device-property-changed': ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT,) ), #@param: adapter, (key, value) 'adapter-property-changed': ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT,)), #@param: progress (0 to 1) 'discovery-progress': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_FLOAT,)), #@param: new adapter path, None if there are no more adapters 'adapter-changed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), #@param: adapter path 'adapter-added': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), 'adapter-removed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), } def __del__(self): dprint("deleting mainlist") def __init__(self, adapter=None, tabledata=None): if not tabledata: tabledata = [] def on_adapter_removed(path): self.emit("adapter-removed", path) if path == self.__adapter_path: self.clear() self.Adapter = None self.SetAdapter() def on_adapter_added(path): def on_activate(): dprint("adapter powered", path) if self.Adapter is None: self.SetAdapter(path) self.emit("adapter-added", path) a = Bluez.Adapter(path) wait_for_adapter(a, on_activate) #cache for fast lookup in the list self.address_to_row = {} self.path_to_row = {} self.monitored_devices = [] self.discovered_devices = [] self.signals = SignalTracker() try: self.Manager = Bluez.Manager("gobject") self.signals.Handle(self.Manager, on_adapter_removed, "AdapterRemoved") self.signals.Handle(self.Manager, on_adapter_added, "AdapterAdded") except: self.Manager = None self.__discovery_time = 0 self.__adapter_path = None self.Adapter = None self.discovering = False data = [] data = data + tabledata data = data + [ ["device", object], ["dbus_path", str] ] GenericList.__init__(self, data) self.adapter_signals = SignalTracker() self.device_signals = SignalTracker() self.SetAdapter(adapter) self.signals.Handle(self.selection, "changed", self.on_selection_changed) def destroy(self): dprint("destroying") self.adapter_signals.DisconnectAll() self.device_signals.DisconnectAll() self.signals.DisconnectAll() self.device_signals = None #self.clear() if len(self.liststore): for i in self.liststore: iter = i.iter device = self.get(iter, "device")["device"] #device.Destroy() GenericList.destroy(self) def on_selection_changed(self, selection): iter = self.selected() if iter: row = self.get(iter, "device") dev = row["device"] self.emit("device-selected", dev, iter) def on_device_found(self, address, props): if self.discovering: dprint("Device discovered", address) props["Address"] = address props["Fake"] = True dev = FakeDevice(props) device = Device(dev) if not address in self.discovered_devices: self.emit("device-found", device) self.discovered_devices.append(address) iter = self.find_device(dev) if not iter: self.device_add_event(device) iter = self.find_device(device) self.row_update_event(iter, "RSSI", props["RSSI"]) else: self.row_update_event(iter, "Alias", props["Alias"]) print "RSSI:", props["RSSI"] def on_property_changed(self, key, value): dprint("adapter propery changed", key, value) if key == "Discovering": if not value and self.discovering: self.StopDiscovery() self.discovered_devices = [] self.emit("adapter-property-changed", self.Adapter, (key, value)) def on_device_property_changed(self, key, value, path, *args, **kwargs): dprint("list: device_prop_ch", key, value, path, args, kwargs) iter = self.find_device_by_path(path) if iter != None: dev = self.get(iter, "device")["device"] self.row_update_event(iter, key, value) self.emit("device-property-changed", dev, iter, (key, value)) if key == "Connected": if value: self.monitor_power_levels(dev) else: r = gtk.TreeRowReference(self.props.model, self.props.model.get_path(iter)) self.level_setup_event(r, dev, None) elif key == "Paired": if value and dev.Temp: dev.Temp = False def monitor_power_levels(self, device): def update(row_ref, cinfo, address): if not row_ref.valid(): dprint("stopping monitor (row does not exist)") cinfo.deinit() self.monitored_devices.remove(props["Address"]) return False if not self.props.model: self.monitored_devices.remove(props["Address"]) return False iter = self.props.model.get_iter(row_ref.get_path()) device = self.get(iter, "device")["device"] if not device.Valid or not device.Connected: dprint("stopping monitor (not connected)") cinfo.deinit() self.level_setup_event(row_ref, device, None) self.monitored_devices.remove(props["Address"]) return False else: self.level_setup_event(row_ref, device, cinfo) return True props = device.GetProperties() if "Connected" in props and props["Connected"] and props["Address"] not in self.monitored_devices: dprint("starting monitor") iter = self.find_device(device) hci = os.path.basename(self.Adapter.GetObjectPath()) try: cinfo = conn_info(props["Address"], hci) except: dprint("Failed to get power levels") else: r = gtk.TreeRowReference(self.props.model, self.props.model.get_path(iter)) self.level_setup_event(r, device, cinfo) gobject.timeout_add(1000, update, r, cinfo, props["Address"]) self.monitored_devices.append(props["Address"]) ##### virtual funcs ##### #called when power levels need updating #if cinfo is None then info icons need to be removed def level_setup_event(self, iter, device, cinfo): pass #called when row needs to be initialized def row_setup_event(self, iter, device): pass #called when a property for a device changes def row_update_event(self, iter, key, value): pass #called when device needs to be added to the list #default action: append def device_add_event(self, device): self.AppendDevice(device) def device_remove_event(self, device, iter): self.RemoveDevice(device, iter) ######################### def on_device_created(self, path): dprint("created", path) iter = self.find_device_by_path(path) if iter == None: dev = Bluez.Device(path) dev = Device(dev) dev.Temp = True self.device_add_event(dev) def on_device_removed(self, path): iter = self.find_device_by_path(path) if iter: row = self.get(iter, "device") dev = row["device"] self.device_remove_event(dev, iter) def SetAdapter(self, adapter=None): self.clear() if self.discovering: self.emit("adapter-property-changed", self.Adapter, ("Discovering", False)) self.StopDiscovery() if adapter is not None and not re.match("hci[0-9]*", adapter): adapter = adapter_path_to_name(adapter) dprint(adapter) if self.Adapter is not None: self.adapter_signals.DisconnectAll() try: self.Adapter = self.Manager.GetAdapter(adapter) self.adapter_signals.Handle(self.Adapter, self.on_device_found, "DeviceFound") self.adapter_signals.Handle(self.Adapter, self.on_property_changed, "PropertyChanged") self.adapter_signals.Handle(self.Adapter, self.on_device_created, "DeviceCreated") self.adapter_signals.Handle(self.Adapter, self.on_device_removed, "DeviceRemoved") self.__adapter_path = self.Adapter.GetObjectPath() self.emit("adapter-changed", self.__adapter_path) except Bluez.errors.DBusNoSuchAdapterError as e: dprint(e) #try loading default adapter if len(self.Manager.ListAdapters()) > 0 and adapter != None: self.SetAdapter() else: self.Adapter = None self.emit("adapter-changed", None) except dbus.DBusServiceUnknownError: dprint("Dbus error while trying to get adapter.") self.Adapter = None self.emit("adapter-changed", None) def update_progress(self, time, totaltime): if not self.discovering: return False self.__discovery_time += time progress = self.__discovery_time / totaltime if progress >= 1.0: progress = 1.0 #if self.__discovery_time >= totaltime: #self.StopDiscovery() #return False self.emit("discovery-progress", progress) return True def add_device(self, device, append=True): iter = self.find_device(device) #device belongs to another adapter if not device.Fake: if not device.get_object_path().startswith(self.Adapter.GetObjectPath()): return if iter == None: dprint("adding new device") if append: iter = self.liststore.append() else: iter = self.liststore.prepend() self.set(iter, device=device) self.row_setup_event(iter, device) props = device.GetProperties() try: self.set(iter, dbus_path=device.GetObjectPath()) except: pass if not "Fake" in props: self.device_signals.Handle("bluez", device, self.on_device_property_changed, "PropertyChanged", sigid=device.GetObjectPath(), path_keyword="path") if props["Connected"]: self.monitor_power_levels(device) else: row = self.get(iter, "device") existing_dev = row["device"] props = existing_dev.GetProperties() props_new = device.GetProperties() #turn a Fake device to a Real device n = not "Fake" in props and not "Fake" in props_new if n: dprint("Updating existing dev") self.device_signals.Disconnect(existing_dev.GetObjectPath()) #existing_dev.Destroy() if ("Fake" in props and not "Fake" in props_new) or n: self.set(iter, device=device, dbus_path=device.GetObjectPath()) self.row_setup_event(iter, device) if not n: self.emit("device-property-changed", device, iter, ("Fake", False)) self.row_update_event(iter, "Fake", False) self.device_signals.Handle("bluez", device, self.on_device_property_changed, "PropertyChanged", sigid=device.GetObjectPath(), path_keyword="path") if props_new["Connected"]: self.monitor_power_levels(device) #turn a Real device to a Fake device elif not "Fake" in props and "Fake" in props_new: dprint("converting: real to discovered") self.set(iter, device=device, dbus_path=None) self.row_setup_event(iter, device) self.emit("device-property-changed", device, iter, ("Fake", True)) self.row_update_event(iter, "Fake", True) def DisplayKnownDevices(self, autoselect=False): self.clear() devices = self.Adapter.ListDevices() for device in devices: self.device_add_event(Device(device)) if autoselect: self.selection.select_path(0) def DiscoverDevices(self, time=10.24): if not self.discovering: self.__discovery_time = 0 self.Adapter.StartDiscovery() self.discovering = True T = 1.0 / 15 * 1000 gobject.timeout_add(int(T), self.update_progress, T / 1000, time) def IsValidAdapter(self): if self.Adapter == None: return False else: return True def GetAdapterPath(self): if self.IsValidAdapter(): return self.__adapter_path def StopDiscovery(self): self.discovering = False if self.Adapter != None: self.Adapter.StopDiscovery() def PrependDevice(self, device): self.add_device(device, False) def AppendDevice(self, device): self.add_device(device, True) def RemoveDevice(self, device, iter=None, force=False): dprint(device) if iter == None: iter = self.find_device(device) if not device.Temp and self.compare(self.selected(), iter): self.emit("device-selected", None, None) try: props = device.GetProperties() except: self.device_signals.Disconnect(device.get_object_path()) else: if not "Fake" in props: self.device_signals.Disconnect(device.GetObjectPath()) if device.Temp and not force: dprint("converting to fake") props = copy.deepcopy(props) props["Fake"] = True dev = FakeDevice(props) device = Device(dev) self.device_add_event(device) else: #device.Destroy() self.delete(iter) def GetSelectedDevice(self): selected = self.selected() if selected != None: row = self.get(selected, "device") device = row["device"] return device def clear(self): if len(self.liststore): for i in self.liststore: iter = i.iter device = self.get(iter, "device")["device"] self.RemoveDevice(device, iter, True) self.liststore.clear() self.emit("device-selected", None, None) self.address_to_row = {} self.path_to_row = {} def find_device(self, device): if type(device) == str: address = device else: address = device.Address try: row = self.address_to_row[address] if row.valid(): path = row.get_path() iter = self.props.model.get_iter(path) return iter else: del self.address_to_row[address] return None except KeyError: return None def find_device_by_path(self, path): try: row = self.path_to_row[path] if row.valid(): path = row.get_path() iter = self.props.model.get_iter(path) return iter else: del self.path_to_row[path] return None except KeyError: return None def do_cache(self, iter, kwargs): if "device" in kwargs: if kwargs["device"]: self.address_to_row[kwargs["device"].Address] = gtk.TreeRowReference(self.props.model, self.props.model.get_path(iter)) dprint("Caching new device %s" % kwargs["device"].Address) if "dbus_path" in kwargs: if kwargs["dbus_path"] != None: self.path_to_row[kwargs["dbus_path"]] = gtk.TreeRowReference(self.props.model, self.props.model.get_path(iter)) else: existing = self.get(iter, "dbus_path")["dbus_path"] if existing != None: del self.path_to_row[existing] def append(self, **columns): iter = GenericList.append(self, **columns) self.do_cache(iter, columns) def prepend(self, **columns): iter = GenericList.prepend(self, **columns) self.do_cache(iter, columns) def set(self, iter, **kwargs): self.do_cache(iter, kwargs) GenericList.set(self, iter, **kwargs)
class NetUsage(AppletPlugin, GObject.GObject): __depends__ = ["Menu"] __icon__ = "network-wireless" __description__ = _( "Allows you to monitor your (mobile broadband) network traffic usage. Useful for limited data access plans. This plugin tracks every device seperately." ) __author__ = "Walmis" __autoload__ = False __gsignals__ = { str('monitor-added'): (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_PYOBJECT, )), str('monitor-removed'): (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_PYOBJECT, )), #monitor, tx, rx str('stats'): (GObject.SignalFlags.NO_HOOKS, None, ( GObject.TYPE_PYOBJECT, GObject.TYPE_PYOBJECT, GObject.TYPE_PYOBJECT, )), } def on_load(self, applet): GObject.GObject.__init__(self) self.monitors = [] self.devices = weakref.WeakValueDictionary() self.signals = SignalTracker() bus = self.bus = dbus.SystemBus() self.signals.Handle('bluez', Network(), self.on_network_property_changed, 'PropertyChanged', path_keyword="path") item = create_menuitem(_("Network _Usage"), get_icon("network-wireless", 16)) item.props.tooltip_text = _("Shows network traffic usage") self.signals.Handle(item, "activate", self.activate_ui) self.Applet.Plugins.Menu.Register(self, item, 84, True) self.signals.Handle("dbus", bus, self.on_nm_ppp_stats, "PppStats", "org.freedesktop.NetworkManager.Device.Serial", path_keyword="path") self.nm_paths = {} def on_nm_ppp_stats(self, down, up, path): if not path in self.nm_paths: props = self.bus.call_blocking( "org.freedesktop.NetworkManager", path, "org.freedesktop.DBus.Properties", "GetAll", "s", ["org.freedesktop.NetworkManager.Device"]) if props["Driver"] == "bluetooth" and "rfcomm" in props[ "Interface"]: self.nm_paths[path] = True portid = int(props["Interface"].strip("rfcomm")) ls = rfcomm_list() for dev in ls: if dev["id"] == portid: adapter = self.Applet.Manager.get_adapter(dev["src"]) device = adapter.find_device(dev["dst"]) device = Device(device) self.monitor_interface(NMMonitor, device, path) return else: self.nm_paths[path] = False def on_network_property_changed(self, key, value, path): dprint(key, value, path) if key == "Interface" and value != "": d = BluezDevice(path) d = Device(d) self.monitor_interface(Monitor, d, value) def activate_ui(self, item): Dialog(self) def on_unload(self): self.signals.DisconnectAll() self.Applet.Plugins.Menu.Unregister(self) def monitor_interface(self, montype, *args): m = montype(*args) self.monitors.append(m) self.signals.Handle(m, "stats", self.on_stats, sigid=m) self.signals.Handle(m, "disconnected", self.on_monitor_disconnected, sigid=m) self.emit("monitor-added", m) def on_ppp_connected(self, device, rfcomm, ppp_port): self.monitor_interface(Monitor, device, ppp_port) def on_monitor_disconnected(self, monitor): self.monitors.remove(monitor) self.signals.Disconnect(monitor) self.emit("monitor-removed", monitor) def on_stats(self, monitor, tx, rx): self.emit("stats", monitor, tx, rx)
class Dialog: running = False def __init__(self, parent): if not Dialog.running: Dialog.running = True else: return self.config = None self.parent = parent builder = Gtk.Builder() builder.add_from_file(UI_PATH + "/net-usage.ui") builder.set_translation_domain("blueman") self.dialog = builder.get_object("dialog") self.dialog.connect("response", self.on_response) cr1 = Gtk.CellRendererText() cr1.props.ellipsize = Pango.EllipsizeMode.END self.devices = {} self.signals = SignalTracker() self.signals.Handle(parent, "monitor-added", self.monitor_added) self.signals.Handle(parent, "monitor-removed", self.monitor_removed) self.signals.Handle(parent, "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_object("e_ul") self.e_dl = builder.get_object("e_dl") self.e_total = builder.get_object("e_total") self.l_started = builder.get_object("l_started") self.l_duration = builder.get_object("l_duration") self.b_reset = builder.get_object("b_reset") self.b_reset.connect("clicked", self.on_reset) self.cb_device = builder.get_object("cb_device") 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 parent.monitors: if d == m.device.Address: iter = 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(iter) added = True break if not added: name = d if self.parent.Applet.Manager: for a in self.parent.Applet.Manager.list_adapters(): try: device = a.find_device(d) device = Device(device) name = self.get_caption(device.Alias, device.Address) except: pass 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: d = Gtk.MessageDialog( parent=self.dialog, flags=Gtk.DialogFlags.MODAL, type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.CLOSE, message_format= _("No usage statistics are available yet. Try establishing a connection first and then check this page." )) d.props.icon_name = "blueman" d.run() d.destroy() self.on_response(None, None) return self.dialog.show() def on_response(self, dialog, response): self.signals.DisconnectAll() Dialog.running = False self.dialog.destroy() def update_time(self): time = self.config["time"] if time: self.datetime = datetime.datetime.fromtimestamp(time) self.l_started.props.label = str(self.datetime) delta = datetime.datetime.now() - self.datetime d = gettext.ngettext("day", "days", delta.days) h = gettext.ngettext("hour", "hours", delta.seconds / 3600) m = gettext.ngettext("minute", "minutes", delta.seconds % 3600 / 60) self.l_duration.props.label = _("%d %s %d %s and %d %s") % ( delta.days, d, delta.seconds / 3600, h, delta.seconds % 3600 / 60, m) else: self.l_started.props.label = _("Unknown") self.l_duration.props.label = _("Unknown") def on_selection_changed(self, cb): iter = cb.get_active_iter() (addr, ) = self.liststore.get(iter, 0) self.config = Config("org.blueman.plugins.netusage", "/org/blueman/plugins/netusages/%s/" % addr) self.update_counts(self.config["tx"], self.config["rx"]) self.update_time() def get_caption(self, name, address): return "%s\n<small>%s</small>" % (cgi.escape(name), address) def update_counts(self, tx, rx): tx = int(tx) rx = int(rx) (num, suffix) = format_bytes(tx) self.e_ul.props.text = "%.2f %s" % (num, suffix) (num, suffix) = format_bytes(rx) self.e_dl.props.text = "%.2f %s" % (num, suffix) (num, suffix) = format_bytes(int(tx) + int(rx)) self.e_total.props.text = "%.2f %s" % (num, suffix) self.update_time() def on_reset(self, button): d = Gtk.MessageDialog( parent=self.dialog, flags=Gtk.DialogFlags.MODAL, type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO, message_format=_("Are you sure you want to reset the counter?")) res = d.run() d.destroy() if res == Gtk.ResponseType.YES: self.config["rx"] = 0 self.config["tx"] = 0 self.config["time"] = int(time.time()) self.update_counts(0, 0) def on_stats(self, parent, monitor, tx, rx): iter = self.cb_device.get_active_iter() (mon, ) = self.liststore.get(iter, 3) if mon == monitor: self.update_counts(tx, rx) def monitor_added(self, parent, monitor): for row in self.liststore: iter = row.iter (val, ) = self.liststore.get(iter, 0) if val == monitor.device.Address: self.liststore.set( iter, 1, self.get_caption(monitor.device.Alias, monitor.device.Address), 2, _("Connected:") + " " + monitor.interface, 3, monitor) return self.liststore.append([ monitor.device.Address, self.get_caption(monitor.device.Alias, monitor.device.Address), _("Connected:") + " " + monitor.interface, monitor ]) def monitor_removed(self, parent, monitor): for row in self.liststore: iter = row.iter (val, ) = self.liststore.get(iter, 0) if val == monitor.device.Address: self.liststore.set( iter, 1, self.get_caption(monitor.device.Alias, monitor.device.Address), 2, _("Not Connected"), 3, None) return
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.Fake = True 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.Device.Appearance = 0 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 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): if self.Fake: return [] 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): 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 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 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
class PowerManager(AppletPlugin): __depends__ = ["StatusIcon", "Menu"] __unloadable__ = True __description__ = _("Controls Bluetooth adapter power states") __author__ = "Walmis" __icon__ = "gnome-power-manager" __gsettings__ = { "schema": "org.blueman.plugins.powermanager", "path": None } __options__ = { "auto-power-on": { "type": bool, "default": True, "name": _("Auto power-on"), "desc": _("Automatically power on adapters") } } def on_load(self, applet): AppletPlugin.add_method(self.on_power_state_query) AppletPlugin.add_method(self.on_power_state_change_requested) AppletPlugin.add_method(self.on_power_state_changed) self.Applet = applet self.item = create_menuitem("Should be overwritten", get_icon("blueman-disabled", 16)) self.item.get_child().get_children()[1].set_markup_with_mnemonic(_("<b>Bluetooth _Off</b>")) self.item.props.tooltip_text = _("Turn off all adapters") self.signals = SignalTracker() self.signals.Handle('bluez', Bluez.Adapter(), self.adapter_property_changed, "PropertyChanged", path_keyword="path") self.signals.Handle(self.item, "activate", lambda x: self.on_bluetooth_toggled()) self.Applet.Plugins.Menu.Register(self, self.item, 0) self.adapter_state = True self.current_state = True self.request_in_progress = False self.STATE_ON = 2 self.STATE_OFF = 1 self.STATE_OFF_FORCED = 0 def on_unload(self): self.signals.DisconnectAll() self.Applet.Plugins.Menu.Unregister(self) @property def CurrentState(self): return self.current_state def on_manager_state_changed(self, state): if state: def timeout(): self.adapter_state = self.get_adapter_state() if self.get_option("auto-power-on"): self.RequestPowerState(True, force=True) else: self.RequestPowerState(self.adapter_state) GObject.timeout_add(1000, timeout) def get_adapter_state(self): adapters = self.Applet.Manager.list_adapters() for adapter in adapters: props = adapter.get_properties() if not props["Powered"]: return False return bool(adapters) def set_adapter_state(self, state): try: dprint(state) adapters = self.Applet.Manager.list_adapters() for adapter in adapters: adapter.set("Powered", state) self.adapter_state = state except Exception as e: dprint("Exception occurred", e) class Callback(object): def __init__(self, parent, state): self.parent = parent self.num_cb = 0 self.called = 0 self.state = state self.success = False self.timer = GObject.timeout_add(5000, self.timeout) def __call__(self, result): self.called += 1 if result: self.success = True self.check() def check(self): if self.called == self.num_cb: dprint("callbacks done") self.parent.set_adapter_state(self.state) GObject.source_remove(self.timer) self.parent.request_in_progress = False def timeout(self): dprint("Timeout reached while setting power state") self.parent.UpdatePowerState() self.parent.request_in_progress = False def RequestPowerState(self, state, force=False): if self.current_state != state or force: if not self.request_in_progress: self.request_in_progress = True dprint("Requesting", state) cb = PowerManager.Callback(self, state) rets = self.Applet.Plugins.Run("on_power_state_change_requested", self, state, cb) cb.num_cb = len(rets) cb.check() self.UpdatePowerState() else: dprint("Another request in progress") def on_power_state_change_requested(self, pm, state, cb): cb(None) def on_power_state_query(self, pm): if self.adapter_state: return self.STATE_ON else: return self.STATE_OFF def on_power_state_changed(self, manager, state): pass #queries other plugins to determine the current power state def UpdatePowerState(self): rets = self.Applet.Plugins.Run("on_power_state_query", self) off = True in map(lambda x: x < self.STATE_ON, rets) foff = self.STATE_OFF_FORCED in rets on = self.STATE_ON in rets icon, label = self.item.get_child().get_children() new_state = True if foff or off: label.set_markup_with_mnemonic(_("<b>Turn Bluetooth _On</b>")) icon.set_from_pixbuf(get_icon("blueman", 16)) self.item.props.tooltip_text = _("Turn on all adapters") if foff: self.item.props.sensitive = False else: self.item.props.sensitive = True new_state = False elif on and self.current_state != True: label.set_markup_with_mnemonic(_("<b>Turn Bluetooth _Off</b>")) icon.set_from_pixbuf(get_icon("blueman-disabled", 16)) self.item.props.tooltip_text = _("Turn off all adapters") self.item.props.sensitive = True new_state = True dprint("off", off, "\nfoff", foff, "\non", on, "\ncurrent state", self.current_state, "\nnew state", new_state) if self.current_state != new_state: dprint("Signalling", new_state) self.current_state = new_state self.BluetoothStatusChanged(new_state) self.Applet.Plugins.Run("on_power_state_changed", self, new_state) self.Applet.Plugins.StatusIcon.IconShouldChange() @dbus.service.signal('org.blueman.Applet', signature="b") def BluetoothStatusChanged(self, status): pass @dbus.service.method('org.blueman.Applet', in_signature="b", out_signature="") def SetBluetoothStatus(self, status): self.RequestPowerState(status) @dbus.service.method('org.blueman.Applet', in_signature="", out_signature="b") def GetBluetoothStatus(self): return self.CurrentState def adapter_property_changed(self, key, value, path): if key == "Powered": if value and not self.CurrentState: dprint("adapter powered on while in off state, turning bluetooth on") self.RequestPowerState(True) self.UpdatePowerState() def on_bluetooth_toggled(self): self.RequestPowerState(not self.CurrentState) def on_status_icon_query_icon(self): if not self.GetBluetoothStatus(): return "blueman-disabled", "blueman-disabled" def on_adapter_added(self, path): adapter = Bluez.Adapter(path) def on_ready(): if not self.adapter_state: adapter.set("Powered", False) else: adapter.set("Powered", True) wait_for_adapter(adapter, on_ready)