class OdsBase(dbus.proxies.Interface, GObject.GObject): # def OdsMethod(fn): # def new(self, *args, **kwargs): # fn(self, *args, **kwargs) # getattr(super(OdsBase,self), fn.__name__)(*args, **kwargs) # return new def __init__(self, service_name, obj_path): self.bus = dbus.SessionBus() self._signals = SignalTracker() service = self.bus.get_object("org.openobex", obj_path) GObject.GObject.__init__(self) dbus.proxies.Interface.__init__(self, service, service_name) def DisconnectAll(self): self._signals.DisconnectAll() def Handle(self, signame, handler): self._signals.Handle("dbus", self.bus, handler, signame, self.dbus_interface, None, self.object_path) def GHandle(self, *args): self._signals.Handle("gobject", self, *args)
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 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 Networking(AppletPlugin): __icon__ = "network" __description__ = _("Manages local network services, like NAP bridges") __author__ = "Walmis" def on_load(self, applet): self.Applet = applet self.Signals = SignalTracker() self.Config = Config("org.blueman.network") self.Signals.Handle("gobject", self.Config, "changed", self.on_config_changed) self.load_nap_settings() def on_manager_state_changed(self, state): if state: self.update_status() def load_nap_settings(self): dprint("Loading NAP settings") def reply(): pass def err(excp): d = NetworkErrorDialog( excp, "You might not be able to connect to the Bluetooth network via this machine" ) d.expander.props.margin_left = 9 d.run() d.destroy() m = Mechanism() m.ReloadNetwork(reply_handler=reply, error_handler=err) def on_unload(self): self.Signals.DisconnectAll() def on_adapter_added(self, path): self.update_status() def update_status(self): self.set_nap(self.Config["nap-enable"]) def on_config_changed(self, config, key): if key == "nap-enable": self.set_nap(config[key]) def set_nap(self, on): dprint("set nap", on) if self.Applet.Manager != None: adapters = self.Applet.Manager.list_adapters() for adapter in adapters: s = NetworkServer(adapter.get_object_path()) if on: s.register("nap", "pan1") else: s.unregister("nap")
class KillSwitch(AppletPlugin): __author__ = "Walmis" __description__ = _( "Toggles a platform Bluetooth killswitch when Bluetooth power state changes. Useless with USB dongles." ) __depends__ = ["PowerManager", "StatusIcon"] __icon__ = "system-shutdown" __options__ = {"checked": {"type": bool, "default": False}} def on_load(self, applet): self.signals = SignalTracker() try: self.Manager = KillSwitchNG() self.signals.Handle(self.Manager, "switch-changed", self.on_switch_changed) dprint("Using the new killswitch system") except OSError as e: dprint("Using the old killswitch system, reason:", e) if _KillSwitch is None: raise Exception("Failed to initialize killswitch manager") else: self.Manager = _KillSwitch.Manager() if not self.get_option("checked"): GObject.timeout_add(1000, self.check) self.signals.Handle(self.Manager, "switch-added", self.on_switch_added) self.signals.Handle(self.Manager, "switch-removed", self.on_switch_removed) def on_switch_added(self, manager, switch): if switch.type == RFKillType.BLUETOOTH: dprint("killswitch registered", switch.idx) # if manager.HardBlocked: # self.Applet.Plugins.PowerManager.SetPowerChangeable(False) # # if not self.Manager.GetGlobalState(): # self.Applet.Plugins.PowerManager.SetBluetoothStatus(False) # # pm_state = self.Applet.Plugins.PowerManager.GetBluetoothStatus() # if self.Manager.GetGlobalState() != pm_state: # self.Manager.SetGlobalState(pm_state) def on_switch_changed(self, manager, switch): if switch.type == RFKillType.BLUETOOTH: s = manager.GetGlobalState() dprint("Global state:", s, "\nswitch.soft:", switch.soft, "\nswitch.hard:", switch.hard) self.Applet.Plugins.PowerManager.UpdatePowerState() self.Applet.Plugins.StatusIcon.QueryVisibility() def on_switch_removed(self, manager, switch): if switch.type == RFKillType.BLUETOOTH: if len(manager.devices) == 0: self.Applet.Plugins.StatusIcon.QueryVisibility() def on_power_state_query(self, manager): if self.Manager.HardBlocked: return manager.STATE_OFF_FORCED else: dprint(self.Manager.GetGlobalState()) if self.Manager.GetGlobalState(): return manager.STATE_ON else: return manager.STATE_OFF def check(self): try: if len(self.Manager.devices) == 0: self.set_option("checked", True) #this machine does not support bluetooth killswitch, let's unload self.Applet.Plugins.SetConfig("KillSwitch", False) except: pass def on_power_state_change_requested(self, manager, state, cb): dprint(state) def reply(*_): cb(True) def error(*_): cb(False) if not self.Manager.HardBlocked: self.Manager.SetGlobalState(state, reply_handler=reply, error_handler=error) else: cb(True) def on_unload(self): self.signals.DisconnectAll() def on_query_status_icon_visibility(self): if self.Manager.HardBlocked: return 1 state = self.Manager.GetGlobalState() if state: if isinstance(self.Manager, KillSwitchNG) and len( self.Manager.devices) > 0 and self.Applet.Manager: return 2 return 1 # StatusIcon.SHOW elif len(self.Manager.devices) > 0 and not state: #if killswitch removes the bluetooth adapter, dont hide the statusicon, #so that the user could turn bluetooth back on. return 2 # StatusIcon.FORCE_SHOW return 1
class DhcpClient(AppletPlugin): __description__ = _( "Provides a basic dhcp client for Bluetooth PAN connections.") __icon__ = "network" __author__ = "Walmis" __priority__ = 3 def on_load(self, applet): self.Signals = SignalTracker() self.add_dbus_method(self.DhcpClient, in_signature="s") self.Signals.Handle("dbus", dbus.SystemBus(), self.on_network_prop_changed, "PropertyChanged", "org.bluez.Network", path_keyword="path") self.quering = [] def on_unload(self): self.Signals.DisconnectAll() def DhcpClient(self, interface): self.dhcp_acquire(interface) def on_network_prop_changed(self, key, value, path): if key == "Interface": if value != "": self.dhcp_acquire(value) def dhcp_acquire(self, device): if device not in self.quering: self.quering.append(device) else: return if device != "": def reply(ip_address): Notification(_("Bluetooth Network"), _("Interface %(0)s bound to IP address %(1)s") % { "0": device, "1": ip_address }, pixbuf=get_icon("gtk-network", 48), status_icon=self.Applet.Plugins.StatusIcon) self.quering.remove(device) def err(msg): dprint(msg) Notification(_("Bluetooth Network"), _("Failed to obtain an IP address on %s") % (device), pixbuf=get_icon("gtk-network", 48), status_icon=self.Applet.Plugins.StatusIcon) self.quering.remove(device) Notification( _("Bluetooth Network"), _("Trying to obtain an IP address on %s\nPlease wait..." % device), pixbuf=get_icon("gtk-network", 48), status_icon=self.Applet.Plugins.StatusIcon) m = Mechanism() m.DhcpClient(device, reply_handler=reply, error_handler=err, timeout=120)
class NMMonitor(AppletPlugin, GObject.GObject): __gsignals__ = { #args: udi 'disconnected': (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_STRING, )), #args: udi 'modem-removed': (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_STRING, )), #args: udi, bdaddr 'modem-added': (GObject.SignalFlags.NO_HOOKS, None, ( GObject.TYPE_STRING, GObject.TYPE_STRING, )), } __icon__ = "network" __description__ = _( "Monitors NetworkManager's modem connections and automatically disconnects Bluetooth link after the network connection is closed" ) __author__ = "Walmis" def on_load(self, applet): GObject.GObject.__init__(self) self.bus = dbus.SystemBus() obj = self.bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager') self.hal_mgr = dbus.Interface(obj, 'org.freedesktop.Hal.Manager') self.monitored_udis = [] self.signals = SignalTracker() self.signals.Handle("dbus", self.bus, self.on_device_state_changed, "StateChanged", "org.freedesktop.NetworkManager.Device", path_keyword="udi") self.signals.Handle("dbus", self.bus, self.on_device_added, "DeviceAdded", "org.freedesktop.Hal.Manager") self.signals.Handle("dbus", self.bus, self.on_device_removed, "DeviceRemoved", "org.freedesktop.Hal.Manager") # self.signals.Handle("bluez", device.Device, self.on_device_propery_changed, "PropertyChanged") def on_unload(self): self.signals.DisconnectAll() def on_device_removed(self, udi): if udi in self.monitored_udis: self.monitored_udis.remove(udi) self.emit("modem-removed", udi) def on_device_added(self, udi): obj = self.bus.get_object('org.freedesktop.Hal', udi) device = dbus.Interface(obj, 'org.freedesktop.Hal.Device') try: if device.QueryCapability("modem") and device.GetPropertyString( "info.linux.driver") == "rfcomm": self.monitored_udis.append(udi) self.emit("modem-added", udi, device.GetPropertyString("info.bluetooth_address")) except: pass def on_device_state_changed(self, state, prev_state, reason, udi): if udi in self.monitored_udis: dprint("state=%u prev_state=%u reason=%u" % (state, prev_state, reason)) if state <= 3 and 3 < prev_state <= 8: self.emit("disconnected", udi)
class ConnectionHandler: def __init__(self, parent, device, uuid, reply, err): self.parent = parent self.device = device self.uuid = uuid self.reply = reply self.err = err self.rfcomm_dev = None self.timeout = None self.signals = SignalTracker() self.signals.Handle("dbus", self.parent.bus, self.on_mm_device_added, "DeviceAdded", "org.freedesktop.ModemManager") #for some reason these handlers take a reference and don't give it back #so i have to workaround :( w = weakref.ref(self) device.Services["serial"].Connect( uuid, reply_handler=lambda *args: w() and w().on_connect_reply(*args), error_handler=lambda *args: w() and w().on_connect_error(*args)) def __del__(self): dprint("deleting") def on_connect_reply(self, rfcomm): self.rfcomm_dev = rfcomm self.timeout = gobject.timeout_add(10000, self.on_timeout) def on_connect_error(self, *args): self.err(*args) self.cleanup() def cleanup(self): if self.timeout: gobject.source_remove(self.timeout) self.signals.DisconnectAll() del self.device def on_mm_device_added(self, path): dprint(path) props = self.parent.bus.call_blocking( "org.freedesktop.ModemManager", path, "org.freedesktop.DBus.Properties", "GetAll", "s", ["org.freedesktop.ModemManager.Modem"]) if self.rfcomm_dev and props["Driver"] == "bluetooth" and props[ "Device"] in self.rfcomm_dev: dprint("It's our bluetooth modem!") modem = get_icon("modem", 24) blueman = get_icon("blueman", 48) icon = composite_icon(blueman, [(modem, 24, 24, 255)]) Notification( _("Bluetooth Dialup"), _("DUN connection on %s will now be available in Network Manager" ) % self.device.Alias, pixbuf=icon, status_icon=self.parent.Applet.Plugins.StatusIcon) self.reply(self.rfcomm_dev) self.cleanup() def on_timeout(self): self.timeout = None self.err( dbus.DBusException( _("Modem Manager did not support the connection"))) self.cleanup()
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 NMPANSupport(AppletPlugin): __depends__ = ["DBusService"] __conflicts__ = ["DhcpClient", "NMIntegration"] __icon__ = "network" __author__ = "Walmis" __description__ = _("Provides support for Personal Area Networking (PAN) introduced in NetworkManager 0.8") __priority__ = 2 def on_load(self, applet): self.bus = dbus.SystemBus() self.nma = None self.nm = None self.nm_signals = SignalTracker() self.nma_signals = SignalTracker() self.watch1 = self.bus.watch_name_owner("org.freedesktop.NetworkManagerUserSettings", self.on_nma_owner_changed) self.watch2 = self.bus.watch_name_owner("org.freedesktop.NetworkManager", self.on_nm_owner_changed) self.client = gconf.client_get_default () def set_gconf(self, key, value): func = None if type(value) == str or type(value) == unicode: func = self.client.set_string elif type(value) == int: func = self.client.set_int elif type(value) == bool: func = self.client.set_bool elif type(value) == float: func = self.client.set_float elif type(value) == list: def x(key, val): self.client.set_list(key, gconf.VALUE_STRING, val) func = x elif type(value) == dbus.Array: if value.signature == "i": def x(key, val): self.client.set_list(key, gconf.VALUE_INT, val) func = x elif value.signature == "s": def x(key, val): self.client.set_list(key, gconf.VALUE_STRING, val) func = x else: raise AttributeError("Cant set this type in gconf") else: raise AttributeError("Cant set %s in gconf" % type(value)) func(key, value) def find_free_gconf_slot(self): dirs = list(self.client.all_dirs ("/system/networking/connections")) dirs.sort() i = 1 for d in dirs: try: d = int(os.path.basename(d)) except: continue if d != i: return i i+=1 return i def add_connection(self, params): slot = self.find_free_gconf_slot() base_path = "/system/networking/connections/%d" % slot for group, settings in params.iteritems(): path = base_path + "/%s" % group for k, v in settings.iteritems(): key = path + "/%s" % k self.set_gconf(key, v) def remove_connection(self, path): self.bus.call_blocking("org.freedesktop.NetworkManagerUserSettings", path, "org.freedesktop.NetworkManagerSettings.Connection", "Delete", "", []) def format_bdaddr(self, addr): return "%02X:%02X:%02X:%02X:%02X:%02X" % (addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]) def find_device(self, bdaddr): devices = self.nm.GetDevices() for dev in devices: try: d = self.bus.call_blocking("org.freedesktop.NetworkManager", dev, "org.freedesktop.DBus.Properties", "GetAll", "s", ["org.freedesktop.NetworkManager.Device.Bluetooth"]) if d["HwAddress"] == bdaddr: dprint(d["HwAddress"]) return dev except dbus.DBusException: pass def find_connection(self, address, t): conns = self.nma.ListConnections() for conn in conns: c = self.bus.call_blocking("org.freedesktop.NetworkManagerUserSettings", conn, "org.freedesktop.NetworkManagerSettings.Connection", "GetSettings", "", []) try: if (self.format_bdaddr(c["bluetooth"]["bdaddr"]) == address) and c["bluetooth"]["type"] == t: return conn except: pass def find_active_connection(self, address, type): props = self.bus.call_blocking("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.DBus.Properties", "GetAll", "s", ["org.freedesktop.NetworkManager"]) nma_connection = self.find_connection(address, type) if nma_connection: active_conns = props["ActiveConnections"] for conn in active_conns: conn_props = self.bus.call_blocking("org.freedesktop.NetworkManager", conn, "org.freedesktop.DBus.Properties", "GetAll", "s", ["org.freedesktop.NetworkManager.Connection.Active"]) if conn_props["Connection"] == nma_connection: return conn def on_nma_owner_changed(self, owner): if owner == "": self.nma = None else: service = self.bus.get_object("org.freedesktop.NetworkManagerUserSettings", "/org/freedesktop/NetworkManagerSettings") self.nma = dbus.proxies.Interface(service, "org.freedesktop.NetworkManagerSettings") def on_nm_owner_changed(self, owner): if owner == "": self.nm = None self.nm_signals.DisconnectAll() else: service = self.bus.get_object("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager") self.nm = dbus.proxies.Interface(service, "org.freedesktop.NetworkManager") def on_unload(self): self.nm_signals.DisconnectAll() self.nma_signals.DisconnectAll() self.watch1.cancel() self.watch2.cancel() def service_connect_handler(self, interface, object_path, method, args, ok, err): if interface == "org.bluez.Network" and method == "Connect": uuid = args[0] name = uuid16_to_name(uuid128_to_uuid16(uuid)) d = Device(object_path) conn = self.find_active_connection(d.Address, "panu") if conn: err(dbus.DBusException(_("Already connected"))) else: params = {} params["bluetooth"] = {"name": "bluetooth", "bdaddr": str(d.Address), "type" : "panu"} params["connection"] = {"autoconnect": False, "id": str("%s on %s") % (name, d.Alias), "uuid" : str(uuid1()), "type": "bluetooth"} params['ipv4'] = {'addresses': dbus.Array([], dbus.Signature("i")), 'dns': dbus.Array([], dbus.Signature("i")), "method": "auto", "routes": dbus.Array([], dbus.Signature("i"))} NewConnectionBuilder(self, params, ok, err) return True elif interface == "org.bluez.Network" and method == "Disconnect": d = Device(object_path) active_conn_path = self.find_active_connection(d.Address, "panu") if active_conn_path: self.bus.call_blocking("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager", "DeactivateConnection", "o", [active_conn_path]) ok() return True
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 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 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 ShowConnected(AppletPlugin): __author__ = "Walmis" __depends__ = ["StatusIcon"] __icon__ = "blueman-active" __description__ = _( "Adds an indication on the status icon when Bluetooth is active and shows the number of connections in the tooltip.") def on_load(self, applet): self.num_connections = 0 self.active = False self.initialized = False self.signals = SignalTracker() self.signals.Handle('bluez', bluez.Device(), self.on_device_property_changed, 'PropertyChanged') def on_unload(self): self.signals.DisconnectAll() self.Applet.Plugins.StatusIcon.SetTextLine(1, None) self.num_connections = 0 self.Applet.Plugins.StatusIcon.IconShouldChange() def on_status_icon_query_icon(self): if self.num_connections > 0: self.active = True # x_size = int(pixbuf.props.height) # x = get_icon("blueman-txrx", x_size) # pixbuf = composite_icon(pixbuf, # [(x, pixbuf.props.height - x_size, 0, 255)]) # # return pixbuf return ("blueman-active",) else: self.active = False def enumerate_connections(self): self.num_connections = 0 adapters = self.Applet.Manager.list_adapters() for adapter in adapters: devices = adapter.list_devices() for device in devices: props = device.get_properties() if "Connected" in props: if props["Connected"]: self.num_connections += 1 dprint("Found %d existing connections" % self.num_connections) if (self.num_connections > 0 and not self.active) or \ (self.num_connections == 0 and self.active): self.Applet.Plugins.StatusIcon.IconShouldChange() self.update_statusicon() def update_statusicon(self): if self.num_connections > 0: self.Applet.Plugins.StatusIcon.SetTextLine(0, _("Bluetooth Active")) self.Applet.Plugins.StatusIcon.SetTextLine(1, ngettext("<b>%d Active Connection</b>", "<b>%d Active Connections</b>", self.num_connections) % self.num_connections) else: self.Applet.Plugins.StatusIcon.SetTextLine(1, None) try: if self.Applet.Plugins.PowerManager.GetBluetoothStatus(): self.Applet.Plugins.StatusIcon.SetTextLine(0, _("Bluetooth Enabled")) except: #bluetooth should be always enabled if powermanager is #not loaded self.Applet.Plugins.StatusIcon.SetTextLine(0, _("Bluetooth Enabled")) def on_manager_state_changed(self, state): if state: if not self.initialized: GObject.timeout_add(0, self.enumerate_connections) self.initialized = True else: GObject.timeout_add(1000, self.enumerate_connections) else: self.num_connections = 0 self.update_statusicon() def on_device_property_changed(self, key, value): if key == "Connected": if value: self.num_connections += 1 else: self.num_connections -= 1 if (self.num_connections > 0 and not self.active) or \ (self.num_connections == 0 and self.active): self.Applet.Plugins.StatusIcon.IconShouldChange() self.update_statusicon() def on_adapter_added(self, adapter): self.enumerate_connections() def on_adapter_removed(self, adapter): self.enumerate_connections()
class NMPANSupport(AppletPlugin): __depends__ = ["DBusService"] __conflicts__ = ["DhcpClient"] __icon__ = "network" __author__ = "Walmis" __description__ = _( "Provides support for Personal Area Networking (PAN) introduced in NetworkManager 0.8" ) __priority__ = 2 def on_load(self, applet): self.bus = dbus.SystemBus() self.nma = None self.nm = None self.nm_signals = SignalTracker() self.nma_signals = SignalTracker() self.watches = [ self.bus.watch_name_owner("org.freedesktop.NetworkManager", self.on_nm_owner_changed) ] self.legacy = self.bus.name_has_owner( 'org.freedesktop.NetworkManagerUserSettings') if self.legacy: self.watches.append( self.bus.watch_name_owner( "org.freedesktop.NetworkManagerUserSettings", self.on_nma_owner_changed)) self.settings_bus = 'org.freedesktop.NetworkManagerUserSettings' self.settings_interface = 'org.freedesktop.NetworkManagerSettings' self.connection_settings_interface = 'org.freedesktop.NetworkManagerSettings.Connection' self.settings_path = "/org/freedesktop/NetworkManagerSettings" NewConnectionBuilder.DEVICE_STATE_DISCONNECTED = 3 NewConnectionBuilder.DEVICE_STATE_ACTIVATED = 8 NewConnectionBuilder.DEVICE_STATE_FAILED = 9 else: self.settings_bus = 'org.freedesktop.NetworkManager' self.settings_interface = 'org.freedesktop.NetworkManager.Settings' self.connection_settings_interface = 'org.freedesktop.NetworkManager.Settings.Connection' self.settings_path = "/org/freedesktop/NetworkManager/Settings" def remove_connection(self, path): self.bus.call_blocking(self.settings_bus, path, self.connection_settings_interface, "Delete", "", []) @staticmethod def format_bdaddr(addr): return "%02X:%02X:%02X:%02X:%02X:%02X" % (addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]) def find_device(self, bdaddr): devices = self.nm.GetDevices() for dev in devices: try: d = self.bus.call_blocking( "org.freedesktop.NetworkManager", dev, "org.freedesktop.DBus.Properties", "GetAll", "s", ["org.freedesktop.NetworkManager.Device.Bluetooth"]) if d["HwAddress"] == bdaddr: dprint(d["HwAddress"]) return dev except dbus.DBusException: pass def find_connection(self, address, t): conns = self.nma.ListConnections() for conn in conns: c = self.bus.call_blocking(self.settings_bus, conn, self.connection_settings_interface, "GetSettings", "", []) try: if (self.format_bdaddr(c["bluetooth"]["bdaddr"]) == address) and c["bluetooth"]["type"] == t: return conn except: pass def find_active_connection(self, address, type): props = self.bus.call_blocking("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.DBus.Properties", "GetAll", "s", ["org.freedesktop.NetworkManager"]) nma_connection = self.find_connection(address, type) if nma_connection: active_conns = props["ActiveConnections"] for conn in active_conns: conn_props = self.bus.call_blocking( "org.freedesktop.NetworkManager", conn, "org.freedesktop.DBus.Properties", "GetAll", "s", ["org.freedesktop.NetworkManager.Connection.Active"]) if conn_props["Connection"] == nma_connection: return conn def on_nma_owner_changed(self, owner): if owner == "": self.nma = None else: service = self.bus.get_object(self.settings_bus, self.settings_path) self.nma = dbus.proxies.Interface(service, self.settings_interface) def on_nm_owner_changed(self, owner): if owner == "": self.nm = None self.nm_signals.DisconnectAll() else: service = self.bus.get_object("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager") self.nm = dbus.proxies.Interface(service, "org.freedesktop.NetworkManager") if not self.legacy: self.on_nma_owner_changed(owner) def on_unload(self): self.nm_signals.DisconnectAll() self.nma_signals.DisconnectAll() for watch in self.watches: watch.cancel() def service_connect_handler(self, service, ok, err): if service.group != 'network': return if self.find_active_connection(service.device.Address, "panu"): err(dbus.DBusException(_("Already connected"))) else: NewConnectionBuilder(self, service, ok, err) return True def service_disconnect_handler(self, service, ok, err): if service.group != 'network': return d = service.device active_conn_path = self.find_active_connection(d.Address, "panu") if not active_conn_path: return self.bus.call_blocking("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager", "DeactivateConnection", "o", [active_conn_path]) ok() return True
class NMIntegration(AppletPlugin): __description__ = _( "<b>Deprecated</b>\nMakes DUN/PAN connections available for NetworkManager 0.7" ) __icon__ = "modem" __depends__ = ["DBusService"] __conflicts__ = ["PPPSupport", "DhcpClient"] __author__ = "Walmis" if HAL_ENABLED: __priority__ = 2 def on_load(self, applet): self.Signals = SignalTracker() self.Signals.Handle('bluez', Network(), self.on_network_prop_changed, 'PropertyChanged', path_keyword='path') def on_unload(self): self.Signals.DisconnectAll() def on_network_prop_changed(self, key, value, path): if key == "Interface": if value != "": m = Mechanism() m.HalRegisterNetDev(value) #in: bluez_device_path, rfcomm_device #@dbus.service.method(dbus_interface='org.blueman.Applet', in_signature="ss", out_signature="") def RegisterModem(self, device_path, rfcomm_device): dev = Bluez.Device(device_path) props = dev.get_properties() m = Mechanism() def reply(): dprint("Registered modem") def err(excp): d = Gtk.MessageDialog(None, type=Gtk.MessageType.WARNING) d.props.icon_name = "blueman" d.props.text = _("CDMA or GSM not supported") d.props.secondary_text = _( "The device %s does not appear to support GSM/CDMA.\nThis connection will not work." ) % props["Alias"] d.add_button(Gtk.STOCK_OK, Gtk.ResponseType.NO) resp = d.run() d.destroy() m.HalRegisterModemPort(rfcomm_device, props["Address"], reply_handler=reply, error_handler=err) #in: bluez_device_path, rfcomm_device #@dbus.service.method(dbus_interface='org.blueman.Applet', in_signature="s", out_signature="") def UnregisterModem(self, device): m = Mechanism() m.HalUnregisterModemPortDev(device) dprint("Unregistered modem") def on_rfcomm_connected(self, device, port, uuid): signals = SignalTracker() def modem_added(mon, udi, address): if device.Address == address: dprint(udi) device.udi = udi def modem_removed(mon, udi): if device.udi == udi: dprint(udi) signals.DisconnectAll() def disconnected(mon, udi): device.Services["serial"].Disconnect(port) self.UnregisterModem(port) def device_propery_changed(key, value): if key == "Connected" and not value: self.UnregisterModem(port) uuid16 = sdp_get_serial_type(device.Address, uuid) if DIALUP_NET_SVCLASS_ID in uuid16: try: signals.Handle(self.Applet.Plugins.NMMonitor, "modem-added", modem_added) signals.Handle(self.Applet.Plugins.NMMonitor, "modem-removed", modem_removed) signals.Handle(self.Applet.Plugins.NMMonitor, "disconnected", disconnected) except KeyError: pass signals.Handle("bluez", device.Device, device_propery_changed, "PropertyChanged") self.RegisterModem(device.get_object_path(), port) def rfcomm_connect_handler(self, device, uuid, reply_handler, error_handler): uuid16 = sdp_get_serial_type(device.Address, uuid) if DIALUP_NET_SVCLASS_ID in uuid16: device.Services["serial"].Connect(uuid, reply_handler=reply_handler, error_handler=error_handler) return True else: return False def on_rfcomm_disconnect(self, port): self.UnregisterModem(port)
class Networking(AppletPlugin): __icon__ = "network" __description__ = _("Manages local network services, like NAP bridges") __author__ = "Walmis" def on_load(self, applet): self.Applet = applet self.Signals = SignalTracker() self.Config = Config("network") self.Signals.Handle("gobject", self.Config, "property-changed", self.on_config_changed) self.load_nap_settings() def on_manager_state_changed(self, state): if state: self.update_status() def load_nap_settings(self): dprint("Loading NAP settings") def reply(): pass def err(excp): lines = str(excp).splitlines() d = Gtk.MessageDialog(None, buttons=Gtk.ButtonsType.OK, type=Gtk.MessageType.ERROR) d.props.text = _("Failed to apply network settings") d.props.secondary_text = lines[-1] + "\n\n" + _( "You might not be able to connect to the Bluetooth network via this machine" ) d.run() d.destroy() m = Mechanism() m.ReloadNetwork(reply_handler=reply, error_handler=err) def on_unload(self): self.Signals.DisconnectAll() def on_adapter_added(self, path): self.update_status() def update_status(self): self.set_nap(self.Config.props.nap_enable or False) def on_config_changed(self, config, key, value): if key == "nap_enable": self.set_nap(value) def set_nap(self, on): dprint("set nap", on) if self.Applet.Manager != None: adapters = self.Applet.Manager.list_adapters() for adapter in adapters: s = NetworkServer(adapter.get_object_path()) if on: s.register("nap", "pan1") else: s.unregister("nap")
class NewConnectionBuilder: def __init__(self, parent, params, ok_cb, err_cb): self.parent = parent self.params = params 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", "org.freedesktop.NetworkManagerSettings") self.device = self.parent.find_device(params["bluetooth"]["bdaddr"]) self.connection = self.parent.find_connection(params["bluetooth"]["bdaddr"], "panu") if not self.connection: parent.add_connection(params) 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) self.parent.nm.ActivateConnection("org.freedesktop.NetworkManagerUserSettings", self.connection, self.device, self.connection) 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 <= NMDeviceState.DISCONNECTED and NMDeviceState.DISCONNECTED < oldstate <= NMDeviceState.ACTIVATED: if self.err_cb: self.err_cb(dbus.DBusException("Connection was interrupted")) self.remove_connection() self.cleanup() elif state == NMDeviceState.FAILED: self.err_cb(dbus.DBusException("Network Manager Failed to activate the connection")) self.remove_connection() self.cleanup() elif state == NMDeviceState.ACTIVATED: self.ok_cb() self.err_cb = None self.ok_cb = None
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
class SerialManager(AppletPlugin): __icon__ = "blueman-serial" __description__ = _( "Standard SPP profile connection handler, allows executing custom actions" ) __author__ = "walmis" __gsettings__ = { "schema": "org.blueman.plugins.serialmanager", "path": None } __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('bluez', Bluez.Device(), self.on_device_property_changed, 'PropertyChanged', path_keyword="path") self.scripts = {} def on_unload(self): self.signals.DisconnectAll() for k in self.scripts.keys(): 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, service, port): device = service.device uuid16 = uuid128_to_uuid16(service.uuid) if SERIAL_PORT_SVCLASS_ID == 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, uuid16_to_name(uuid16), uuid16, port) def terminate_all_scripts(self, address): try: for p in self.scripts[address].values(): dprint("Sending HUP to", p.pid) os.killpg(p.pid, signal.SIGHUP) except: pass def on_script_closed(self, pid, cond, address_node): address, node = address_node del self.scripts[address][node] dprint("Script with PID", pid, "closed") def manage_script(self, address, node, process): if not address in self.scripts: self.scripts[address] = {} if node in self.scripts[address]: self.scripts[address][node].terminate() self.scripts[address][node] = process GObject.child_watch_add(process.pid, self.on_script_closed, (address, node)) def call_script(self, address, name, sv_name, uuid16, node): c = self.get_option("script") if c and c != "": args = c.split(" ") try: args += [ address, name, sv_name, ",".join(map(lambda x: hex(x), uuid16)), node ] dprint(args) p = Popen(args, preexec_fn=lambda: os.setpgid(0, 0)) self.manage_script(address, node, p) except Exception as e: Notification(_("Serial port connection script failed"), _("There was a problem launching script %s\n" "%s") % (c, str(e)), pixbuf=get_icon("blueman-serial", 48), status_icon=self.Applet.Plugins.StatusIcon) def on_rfcomm_disconnect(self, node): for k, v in self.scripts.items(): if node in v: dprint("Sending HUP to", v[node].pid) os.killpg(v[node].pid, signal.SIGHUP) def rfcomm_connect_handler(self, service, reply, err): if SERIAL_PORT_SVCLASS_ID == uuid128_to_uuid16(service.uuid): service.connect(reply_handler=reply, error_handler=err) return True else: return False def on_device_disconnect(self, device): self.terminate_all_scripts(device.Address) serial_services = [ service for service in device.get_services() if service.group == 'serial' ] if not serial_services: return ports = rfcomm_list() def flt(dev): if dev["dst"] == device.Address and dev["state"] == "connected": return dev["id"] active_ports = map(flt, ports) for port in active_ports: name = "/dev/rfcomm%d" % port try: dprint("Disconnecting", name) serial_services[0].disconnect(name) except: dprint("Failed to disconnect", name)
class ManagerDeviceMenu(gtk.Menu): __ops__ = {} __instances__ = [] def __init__(self, blueman): gtk.Menu.__init__(self) self.Blueman = blueman self.SelectedDevice = None self.is_popup = False #object, args, self.Signals = SignalTracker() self.MainSignals = SignalTracker() self.MainSignals.Handle("gobject", self.Blueman.List, "device-property-changed", self.on_device_property_changed) ManagerDeviceMenu.__instances__.append(self) self.Generate() def __del__(self): dprint("deleting devicemenu") # gobject.GObject.__del__(self) def popup(self, *args): self.is_popup = True self.MainSignals.DisconnectAll() self.MainSignals.Handle("gobject", self.Blueman.List, "device-property-changed", self.on_device_property_changed) def disconnectall(x): self.MainSignals.DisconnectAll() self.MainSignals.Handle("gobject", self, "selection-done", disconnectall) self.Generate() gtk.Menu.popup(self, *args) def clear(self): self.Signals.DisconnectAll() def each(child): self.remove(child) child.destroy() self.foreach(each) def set_op(self, device, message): ManagerDeviceMenu.__ops__[device.GetObjectPath()] = message for inst in ManagerDeviceMenu.__instances__: dprint("op: regenerating instance", inst) if inst.SelectedDevice == self.SelectedDevice and not ( inst.is_popup and not inst.props.visible): inst.Generate() def get_op(self, device): try: return ManagerDeviceMenu.__ops__[device.GetObjectPath()] except: return None def unset_op(self, device): del ManagerDeviceMenu.__ops__[device.GetObjectPath()] for inst in ManagerDeviceMenu.__instances__: dprint("op: regenerating instance", inst) if inst.SelectedDevice == self.SelectedDevice and not ( inst.is_popup and not inst.props.visible): inst.Generate() def service_property_changed(self, key, value): if key == "Connected": self.Generate() def on_connect(self, item, device, service_id, *args): def success(*args2): try: uuid16 = sdp_get_serial_type(device.Address, args[0]) except: uuid16 = 0 dprint("success", args2) prog.message(_("Success!")) if service_id == "serial" and SERIAL_PORT_SVCLASS_ID in uuid16: MessageArea.show_message( _("Serial port connected to %s") % args2[0], gtk.STOCK_DIALOG_INFO) else: MessageArea.close() self.unset_op(device) def fail(*args): prog.message(_("Failed")) self.unset_op(device) dprint("fail", args) MessageArea.show_message( _("Connection Failed: ") + e_(str(args[0]))) def cancel(prog, *args): try: svc.Disconnect(*args) except: pass prog.message(_("Cancelled")) self.unset_op(device) svc = device.Services[service_id] self.set_op(device, _("Connecting...")) prog = ManagerProgressbar(self.Blueman, False) try: appl = AppletService() except: dprint("** Failed to connect to applet") fail() return try: appl.SetTimeHint(gtk.get_current_event_time()) except: pass if service_id == "network": uuid = args[0] appl.ServiceProxy(svc.GetInterfaceName(), svc.GetObjectPath(), "Connect", [uuid], reply_handler=success, error_handler=fail, timeout=200) #prog.set_cancellable(True) #prog.connect("cancelled", cancel) elif service_id == "input": appl.ServiceProxy(svc.GetInterfaceName(), svc.GetObjectPath(), "Connect", [], reply_handler=success, error_handler=fail, timeout=200) #prog.connect("cancelled", cancel) elif service_id == "serial": uuid = str(args[0]) appl.RfcommConnect(device.GetObjectPath(), uuid, reply_handler=success, error_handler=fail, timeout=200) else: appl.ServiceProxy(svc.GetInterfaceName(), svc.GetObjectPath(), "Connect", [], reply_handler=success, error_handler=fail, timeout=200) prog.start() def on_disconnect(self, item, device, service_id, *args): svc = device.Services[service_id] if service_id == "serial": try: appl = AppletService() except: dprint("** Failed to connect to applet") else: appl.RfcommDisconnect(device.GetObjectPath(), args[0]) self.Generate() else: try: appl = AppletService() except: dprint("** Failed to connect to applet") return appl.ServiceProxy(svc.GetInterfaceName(), svc.GetObjectPath(), "Disconnect", []) def on_device_property_changed(self, List, device, iter, (key, value)): # print "menu:", key, value if List.compare(iter, List.selected()): if key == "Connected" \ or key == "Fake" \ or key == "UUIDs" \ or key == "Trusted" \ or key == "Paired": self.Generate()
class ManagerDeviceMenu(Gtk.Menu): __ops__ = {} __instances__ = [] def __init__(self, blueman): GObject.GObject.__init__(self) self.Blueman = blueman self.SelectedDevice = None self.is_popup = False #object, args, self.Signals = SignalTracker() self.MainSignals = SignalTracker() self.MainSignals.Handle("gobject", self.Blueman.List, "device-property-changed", self.on_device_property_changed) ManagerDeviceMenu.__instances__.append(self) self.Generate() def __del__(self): dprint("deleting devicemenu") # GObject.GObject.__del__(self) def popup(self, *args): self.is_popup = True self.MainSignals.DisconnectAll() self.MainSignals.Handle("gobject", self.Blueman.List, "device-property-changed", self.on_device_property_changed) def disconnectall(x): self.MainSignals.DisconnectAll() self.MainSignals.Handle("gobject", self, "selection-done", disconnectall) self.Generate() Gtk.Menu.popup(self, *args) def clear(self): self.Signals.DisconnectAll() def each(child, data): self.remove(child) child.destroy() self.foreach(each, None) def set_op(self, device, message): ManagerDeviceMenu.__ops__[device.get_object_path()] = message for inst in ManagerDeviceMenu.__instances__: dprint("op: regenerating instance", inst) if inst.SelectedDevice == self.SelectedDevice and not ( inst.is_popup and not inst.props.visible): inst.Generate() def get_op(self, device): try: return ManagerDeviceMenu.__ops__[device.get_object_path()] except: return None def unset_op(self, device): del ManagerDeviceMenu.__ops__[device.get_object_path()] for inst in ManagerDeviceMenu.__instances__: dprint("op: regenerating instance", inst) if inst.SelectedDevice == self.SelectedDevice and not ( inst.is_popup and not inst.props.visible): inst.Generate() def service_property_changed(self, key, value): if key == "Connected": self.Generate() def on_connect(self, _item, service): device = service.device def success(*args2): dprint("success", args2) prog.message(_("Success!")) if isinstance(service, SerialPort ) and SERIAL_PORT_SVCLASS_ID == uuid128_to_uuid16( service.uuid): MessageArea.show_message( _("Serial port connected to %s") % args2[0], "dialog-information") else: MessageArea.close() self.unset_op(device) def fail(*args): prog.message(_("Failed")) self.unset_op(device) dprint("fail", args) MessageArea.show_message( _("Connection Failed: ") + e_(str(args[0]))) self.set_op(device, _("Connecting...")) prog = ManagerProgressbar(self.Blueman, False) try: appl = AppletService() except: dprint("** Failed to connect to applet") fail() return try: appl.SetTimeHint(Gtk.get_current_event_time()) except: pass appl.connect_service(device.get_object_path(), service.uuid, reply_handler=success, error_handler=fail, timeout=200) prog.start() def on_disconnect(self, item, service, port=0): try: appl = AppletService() except: dprint("** Failed to connect to applet") return appl.disconnect_service(service.device.get_object_path(), service.uuid, port) self.Generate() def on_device_property_changed(self, List, device, iter, key_value): key, value = key_value # print "menu:", key, value if List.compare(iter, List.selected()): if key == "Connected" \ or key == "Fake" \ or key == "UUIDs" \ or key == "Trusted" \ or key == "Paired": self.Generate() def Generate(self): self.clear() appl = AppletService() items = [] if not self.is_popup or self.props.visible: selected = self.Blueman.List.selected() if not selected: return device = self.Blueman.List.get(selected, "device")["device"] else: (x, y) = self.Blueman.List.get_pointer() path = self.Blueman.List.get_path_at_pos(x, y) if path != None: device = self.Blueman.List.get(path[0], "device")["device"] else: return if not device.Valid: return self.SelectedDevice = device op = self.get_op(device) if op != None: item = create_menuitem(op, get_icon("network-transmit-recieve", 16)) item.props.sensitive = False item.show() self.append(item) return rets = self.Blueman.Plugins.Run("on_request_menu_items", self, device) for ret in rets: if ret: for (item, pos) in ret: items.append((pos, item)) if device.Fake: item = create_menuitem(_("_Add Device"), get_icon("list-add", 16)) self.Signals.Handle("gobject", item, "activate", lambda x: self.Blueman.add_device(device)) item.show() self.append(item) item.props.tooltip_text = _( "Add this device to known devices list") item = create_menuitem(_("_Setup..."), get_icon("document-properties", 16)) self.append(item) self.Signals.Handle("gobject", item, "activate", lambda x: self.Blueman.setup(device)) item.show() item.props.tooltip_text = _( "Run the setup assistant for this device") item = create_menuitem(_("_Pair"), get_icon("dialog-password", 16)) self.Signals.Handle("gobject", item, "activate", lambda x: self.Blueman.bond(device)) self.append(item) item.show() item.props.tooltip_text = _("Pair with the device") item = Gtk.SeparatorMenuItem() item.show() self.append(item) send_item = create_menuitem(_("Send a _File..."), get_icon("edit-copy", 16)) self.Signals.Handle("gobject", send_item, "activate", lambda x: self.Blueman.send(device)) send_item.show() self.append(send_item) else: dprint(device.Alias) item = None have_disconnectables = False have_connectables = False if True in map(lambda x: x[0] >= 100 and x[0] < 200, items): have_disconnectables = True if True in map(lambda x: x[0] < 100, items): have_connectables = True if True in map(lambda x: x[0] >= 200, items) and (have_connectables or have_disconnectables): item = Gtk.SeparatorMenuItem() item.show() items.append((199, item)) if have_connectables: item = Gtk.MenuItem() label = Gtk.Label() label.set_markup(_("<b>Connect To:</b>")) label.props.xalign = 0.0 label.show() item.add(label) item.props.sensitive = False item.show() items.append((0, item)) if have_disconnectables: item = Gtk.MenuItem() label = Gtk.Label() label.set_markup(_("<b>Disconnect:</b>")) label.props.xalign = 0.0 label.show() item.add(label) item.props.sensitive = False item.show() items.append((99, item)) items.sort(key=itemgetter(0)) for priority, item in items: self.append(item) if items != []: item = Gtk.SeparatorMenuItem() item.show() self.append(item) del items send_item = create_menuitem(_("Send a _File..."), get_icon("edit-copy", 16)) send_item.props.sensitive = False self.append(send_item) send_item.show() browse_item = create_menuitem(_("_Browse Device..."), get_icon("document-open", 16)) browse_item.props.sensitive = False self.append(browse_item) browse_item.show() uuids = device.UUIDs for uuid in uuids: uuid16 = uuid128_to_uuid16(uuid) if uuid16 == OBEX_OBJPUSH_SVCLASS_ID: self.Signals.Handle("gobject", send_item, "activate", lambda x: self.Blueman.send(device)) send_item.props.sensitive = True if uuid16 == OBEX_FILETRANS_SVCLASS_ID: self.Signals.Handle("gobject", browse_item, "activate", lambda x: self.Blueman.browse(device)) browse_item.props.sensitive = True item = Gtk.SeparatorMenuItem() item.show() self.append(item) item = create_menuitem(_("_Pair"), get_icon("dialog-password", 16)) item.props.tooltip_text = _("Create pairing with the device") self.append(item) item.show() if not device.Paired: self.Signals.Handle("gobject", item, "activate", lambda x: self.Blueman.bond(device)) else: item.props.sensitive = False if not device.Trusted: item = create_menuitem(_("_Trust"), get_icon("blueman-trust", 16)) self.Signals.Handle( "gobject", item, "activate", lambda x: self.Blueman.toggle_trust(device)) self.append(item) item.show() else: item = create_menuitem(_("_Untrust"), get_icon("blueman-untrust", 16)) self.append(item) self.Signals.Handle( "gobject", item, "activate", lambda x: self.Blueman.toggle_trust(device)) item.show() item.props.tooltip_text = _("Mark/Unmark this device as trusted") item = create_menuitem(_("_Setup..."), get_icon("document-properties", 16)) self.append(item) self.Signals.Handle("gobject", item, "activate", lambda x: self.Blueman.setup(device)) item.show() item.props.tooltip_text = _( "Run the setup assistant for this device") def on_rename(_item, device): def on_response(dialog, response_id): if response_id == Gtk.ResponseType.ACCEPT: device.set('Alias', alias_entry.get_text()) elif response_id == 1: device.set('Alias', '') dialog.destroy() builder = Gtk.Builder() builder.set_translation_domain("blueman") builder.add_from_file(UI_PATH + "/rename-device.ui") dialog = builder.get_object("dialog") dialog.set_transient_for(self.Blueman.window) dialog.props.icon_name = "blueman" alias_entry = builder.get_object("alias_entry") alias_entry.set_text(device.Alias) dialog.connect("response", on_response) dialog.present() item = Gtk.MenuItem.new_with_label("Rename device...") self.Signals.Handle(item, 'activate', on_rename, device) self.append(item) item.show() item = Gtk.SeparatorMenuItem() item.show() self.append(item) item = create_menuitem(_("_Remove..."), get_icon("edit-delete", 16)) self.Signals.Handle(item, "activate", lambda x: self.Blueman.remove(device)) self.append(item) item.show() item.props.tooltip_text = _( "Remove this device from the known devices list") item = Gtk.SeparatorMenuItem() item.show() self.append(item) item = create_menuitem(_("_Disconnect"), get_icon("network-offline", 16)) item.props.tooltip_text = _("Forcefully disconnect the device") self.append(item) item.show() def on_disconnect(item): def finished(*args): self.unset_op(device) self.set_op(device, _("Disconnecting...")) self.Blueman.disconnect(device, reply_handler=finished, error_handler=finished) if device.Connected: self.Signals.Handle(item, "activate", on_disconnect) else: item.props.sensitive = False
class SourceRedirector: instances = [] def __init__(self, module_id, device_path, pa_utils): if module_id in SourceRedirector.instances: return else: SourceRedirector.instances.append(module_id) self.module_id = module_id self.pa_utils = pa_utils self.device = Device(device_path) self.signals = SignalTracker() self.bus = dbus.SystemBus() self.signals.Handle("dbus", self.bus, self.on_source_prop_change, "PropertyChanged", "org.bluez.AudioSource", path=device_path) self.pacat = None self.parec = None self.loopback_id = None dprint("Starting source redirector") def sources_cb(sources): for k, v in sources.iteritems(): props = v["proplist"] if "bluetooth.protocol" in props: if props["bluetooth.protocol"] == "a2dp_source": if v["owner_module"] == self.module_id: dprint("Found source", k) self.start_redirect(k) return dprint("Source not found :(") self.pa_utils.ListSources(sources_cb) def start_redirect(self, source): def on_load(res): dprint("module-loopback load result", res) if res < 0: self.parec = Popen(["parec", "-d", str(source)], stdout=PIPE) self.pacat = Popen([ "pacat", "--client-name=Blueman", "--stream-name=%s" % self.device.Address, "--property=application.icon_name=blueman" ], stdin=self.parec.stdout) else: self.loopback_id = res self.pa_utils.LoadModule("module-loopback", "source=%d" % source, on_load) def on_source_prop_change(self, key, value): if key == "State": if value == "disconnected": if self.pacat: self.pacat.terminate() if self.parec: self.parec.terminate() if self.loopback_id: self.pa_utils.UnloadModule( self.loopback_id, lambda x: dprint("Loopback module unload result", x)) self.signals.DisconnectAll() SourceRedirector.instances.remove(self.module_id) del self.pa_utils def __del__(self): dprint("Destroying redirector")
class ManagerProgressbar(GObject.GObject): __gsignals__ = { 'cancelled': (GObject.SignalFlags.RUN_LAST, None, ()), } __instances__ = [] def __init__(self, blueman, cancellable=True, text=_("Connecting")): def on_enter(evbox, event): c = Gdk.Cursor.new(Gdk.CursorType.HAND2) self.window.get_window().set_cursor(c) def on_leave(evbox, event): self.window.get_window().set_cursor(None) def on_clicked(evbox, event): self.eventbox.props.sensitive = False self.emit("cancelled") GObject.GObject.__init__(self) self.Blueman = blueman self.cancellable = cancellable self.hbox = hbox = blueman.Builder.get_object("statusbar1") self.progressbar = Gtk.ProgressBar() self.signals = SignalTracker() self.button = Gtk.Image.new_from_pixbuf(get_icon("process-stop", 16)) self.eventbox = eventbox = Gtk.EventBox() eventbox.add(self.button) eventbox.props.tooltip_text = _("Cancel Operation") self.signals.Handle(eventbox, "enter-notify-event", on_enter) self.signals.Handle(eventbox, "leave-notify-event", on_leave) self.signals.Handle(eventbox, "button-press-event", on_clicked) self.progressbar.set_size_request(100, 15) self.progressbar.set_ellipsize(Pango.EllipsizeMode.END) self.progressbar.set_text(text) self.progressbar.set_pulse_step(0.05) self.window = blueman.Builder.get_object("window") hbox.pack_end(eventbox, True, False, 0) hbox.pack_end(self.progressbar, False, False, 0) if ManagerProgressbar.__instances__ != []: dprint("hiding", ManagerProgressbar.__instances__[-1]) ManagerProgressbar.__instances__[-1].hide() self.show() if not self.cancellable: self.eventbox.props.sensitive = False self.gsource = None self.finalized = False ManagerProgressbar.__instances__.append(self) def connect(self, *args): self.signals.Handle("gobject", super(ManagerProgressbar, self), *args) def show(self): if self.Blueman.Config.props.show_statusbar == False: self.Blueman.Builder.get_object("statusbar").props.visible = True # if self.Blueman.Stats.hbox.size_request()[0] + self.progressbar.size_request()[0] + 16 > self.Blueman.window.get_size()[0]: # self.Blueman.Stats.hbox.hide_all() self.progressbar.props.visible = True self.eventbox.props.visible = True self.button.props.visible = True def hide(self): self.Blueman.Stats.hbox.show_all() self.progressbar.props.visible = False self.eventbox.props.visible = False self.button.props.visible = False def message(self, msg, timeout=1500): self.stop() self.set_label(msg) self.set_cancellable(False) GObject.timeout_add(timeout, self.finalize) def finalize(self): if not self.finalized: self.hide() self.stop() Gdk.Window.set_cursor(self.window.get_window(), None) self.hbox.remove(self.eventbox) self.hbox.remove(self.progressbar) # self.hbox.remove(self.seperator) self.finalized = True if ManagerProgressbar.__instances__[-1] == self: ManagerProgressbar.__instances__.pop() #remove all finalized instances for inst in reversed(ManagerProgressbar.__instances__): if inst.finalized: ManagerProgressbar.__instances__.pop() else: #show last active progress bar inst.show() break if ManagerProgressbar.__instances__ == []: if self.Blueman.Config.props.show_statusbar == False: self.Blueman.Builder.get_object( "statusbar").props.visible = False self.signals.DisconnectAll() def set_cancellable(self, b, hide=False): if b: self.eventbox.props.visible = True self.eventbox.props.sensitive = True else: if hide: self.eventbox.props.visible = False else: self.eventbox.props.sensitive = False def set_label(self, label): self.progressbar.props.text = label def fraction(self, frac): if not self.finalized: self.progressbar.set_fraction(frac) def started(self): return self.gsource != None def start(self): def pulse(): self.progressbar.pulse() return True if not self.gsource: self.gsource = GObject.timeout_add(1000 / 24, pulse) def stop(self): if self.gsource != None: GObject.source_remove(self.gsource) self.progressbar.set_fraction(0.0)
class DiscvManager(AppletPlugin): __depends__ = ["Menu"] __author__ = "Walmis" __icon__ = "edit-find" __description__ = _( "Provides a menu item for making the default adapter temporarily visible when it is set to hidden by default" ) __gsettings__ = { "schema": "org.blueman.plugins.discvmanager", "path": None } __options__ = { "time": { "type": int, "default": 60, "name": _("Discoverable timeout"), "desc": _("Amount of time in seconds discoverable mode will last"), "range": (60, 600) } } def on_load(self, applet): self.Signals = SignalTracker() self.item = create_menuitem(_("_Make Discoverable"), get_icon("edit-find", 16)) self.item_label = self.item.get_child().get_children()[1] applet.Plugins.Menu.Register(self, self.item, 20, False) self.Applet = applet self.adapter = None self.time_left = -1 self.Signals.Handle(self.item, "activate", self.on_set_discoverable) self.item.props.tooltip_text = _( "Make the default adapter temporarily visible") self.timeout = None def on_unload(self): self.Applet.Plugins.Menu.Unregister(self) del self.item if self.timeout: GObject.source_remove(self.timeout) self.Signals.DisconnectAll() def on_manager_state_changed(self, state): if state: self.init_adapter() self.update_menuitems() else: self.Signals.Disconnect(0) self.adapter = None self.update_menuitems() def on_update(self): self.time_left -= 1 self.item_label.set_text_with_mnemonic( _("Discoverable... %ss") % self.time_left) self.item.props.sensitive = False return True def on_set_discoverable(self, item): if self.adapter: self.adapter.set("Discoverable", True) self.adapter.set("DiscoverableTimeout", self.get_option("time")) def init_adapter(self): try: self.adapter = self.Applet.Manager.get_adapter() except: self.adapter = None def on_adapter_removed(self, path): dprint(path) if path == self.adapter.get_object_path(): self.init_adapter() self.update_menuitems() def on_adapter_property_changed(self, path, key, value): if self.adapter and path == self.adapter.get_object_path(): dprint("prop", key, value) if key == "DiscoverableTimeout": if value == 0: #always visible if self.timeout != None: GObject.source_remove(self.timeout) self.time_left = -1 self.timeout = None else: if self.time_left > -1: if self.timeout != None: GObject.source_remove(self.timeout) self.time_left = value self.timeout = GObject.timeout_add(1000, self.on_update) return elif (key == "Discoverable" and not value) or (key == "Powered" and not value): dprint("Stop") if self.timeout != None: GObject.source_remove(self.timeout) self.time_left = -1 self.timeout = None self.update_menuitems() def update_menuitems(self): try: props = self.adapter.get_properties() except Exception as e: dprint("warning: Adapter is None") self.item.props.visible = False else: if (not props["Discoverable"] or props["DiscoverableTimeout"] > 0) and props["Powered"]: self.item.props.visible = True self.item_label.set_text_with_mnemonic(_("_Make Discoverable")) self.item.props.sensitive = True else: self.item.props.visible = False
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.xdg_screensaver("resume") self.signals.DisconnectAll() def on_device_property_changed(self, key, value, path): if key == "Connected": props = Device(path).get_properties() if not "Class" in props: return klass = props["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 %s %s" % (action, self.root_window_id) try: ret = launch(command, sn=False) if not ret: dprint("%s failed") pass if action == "suspend": self.wake_lock += 1 elif action == "resume": self.wake_lock = 0 except: dprint(traceback.format_exc())
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)