Esempio n. 1
0
class WlanApp:

  def __init__(self):
    self.prefix = 'W:'
    self.suffix = ' '
    self.tooltip_heading = 'Wireless LAN Status:\n'

    self.iface = None  # Set to interface name to override interface selection

    self.build_ui()

    # Needed by wpa_supplicant.core
    self.reactor = SelectReactor()
    thread = threading.Thread(target=self.reactor.run, kwargs={'installSignalHandlers': 0})
    thread.daemon = True
    thread.start()
    time.sleep(0.1)  # let reactor start

    self.wpasup = None
    self.wpasup_running = False
    self.wlan = None
    self.wlan_signal = None

    # Monitor the availability of wpa_supplicant via DBus
    self.dbus = SystemBus()
    # watch_name() fires an event as soon as GLib.MainLoop() starts, so we don't need to explicitly
    # call get_wpa_supplicant() here
    self.dbus.watch_name(BUS_NAME, 0, self.get_wpa_supplicant, self.get_wpa_supplicant)
    self.start_watch_thread()

  def build_ui(self):
    self.tray = tray = Gtkti.TrayIcon()
    self.eventbox = eventbox = Gtk.EventBox()
    eventbox.set_tooltip_text(self.tooltip_heading+'WPA Supplicant not running')
    tray.add(eventbox)
    self.tray_label = tray_label = Gtk.Label(self.prefix+'_'+self.suffix)
    eventbox.add(tray_label)
    tray.show_all()

    menu = Gtk.Menu()
    item_quit = Gtk.MenuItem('Quit')
    def quit(menu_item):
      if sys.version_info < (3, 0):
        os.kill(os.getpid(), signal.SIGINT)
      else:
        Gtk.main_quit()
    item_quit.connect('activate', quit)
    menu.append(item_quit)
    menu.show_all()
    def button_pressed(eventbox, event, menu=menu):
      if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3:
        menu.popup(None, None, None, None, event.button, event.time)
    eventbox.connect('button-press-event', button_pressed)

  # Update the UI (thread-safe)
  def update_ui(self):
    GLib.idle_add(self.gtk_update_ui)

  # Update the UI (within the GTK main thread ; not thread-safe)
  def gtk_update_ui(self):
    if not self.wpasup_running:
      display_str = '_'
      tooltip_str = 'WLAN Interface is down (WPA Supplicant is not running)'
    elif not self.wlan:
      display_str = '_'
      tooltip_str = 'WLAN Interface not found via WPA Supplicant'
    else:
      try:
        ifname = self.wlan.get_ifname()
        tooltip_str = ifname
        state = self.wlan.get_state()
        tooltip_str += ' '+state.title()
        if state == 'interface_disabled':
          display_str = '_'
        elif state == 'disconnected' or state == 'inactive':
          display_str = '-'
        elif state == 'scanning':
          display_str = '?'
        elif state == 'authenticating' or state == 'associating' or state == 'associated' or \
             state == '4way_handshake' or state == 'group_handshake':
          display_str = '@'
        elif state == 'completed':
          display_str = ''
          tooltip_str += ' Connected'
        elif state == 'unknown':
          display_str = '!'
        else:
          display_str = '!'
          print >> sys.stderr, 'Unknown wpa_supplicant state: '+state+' to '+self.wlan.get_current_bss().get_ssid()
        bss = self.wlan.get_current_bss()
        if bss:
          display_str += bss.get_ssid()
          tooltip_str += ' to '+bss.get_ssid()
      except:
        # This is expected if another thread sets self.wlan to None while the above code is
        # executing, or if wpa_supplicant shuts down while the above code is executing.  In either
        # case, another UI update should happen momentarily.
        display_str = '!'
        tooltip_str = 'Unknown (Exception Thrown)'
    self.tray_label.set_text(self.prefix+display_str+self.suffix)
    self.eventbox.set_tooltip_text(self.tooltip_heading+tooltip_str)

    # Return false to unregister this method as a GLib idle handler
    return False

  def select_wlan_interface(self, interfaces):
    if self.wlan_signal:
      wlan_signal = self.wlan_signal  # To avoid race conditions
      self.wlan_signal = None
      wlan_signal.cancel()
    self.wlan = None
    if interfaces:
      if self.iface:
        for interface in interfaces:
          if interface.get_ifname() == self.iface:
            self.wlan = interface
            break
      else:
        self.wlan = interfaces[0]
      self.wlan_signal = \
       self.wlan.register_signal('PropertiesChanged', lambda args: self.update_ui())
    self.update_ui()

  def scan_wpa_interfaces(self, args=None):
    self.wpa_interfaces = self.wpasup.get_interfaces()
    self.select_wlan_interface(self.wpa_interfaces)

  def wlan_interface_removed(self, path):
    # wpa_supplicant sends InterfaceRemoved just before shutting down, and get_interfaces() may
    # throw an exception if it is called while wpa_supplicant is shutting down.  So, instead of
    # calling scan_wpa_interfaces on InterfaceRemoved, it is probably better to keep a cache of the
    # list of interfaces and just delete the relevant interface from the cache.
    self.wpa_interfaces[:] = [i for i in self.wpa_interfaces if not i.get_path() == path]
    self.select_wlan_interface(self.wpa_interfaces)

  def get_wpa_supplicant(self, dbus_name_owner = None):
    if dbus_name_owner:
      self.wpasup_running = True
      if not self.wpasup:
        # Connect to wpa_supplicant
        self.wpasup = WpaSupplicantDriver(self.reactor).connect()
        self.wpasup.register_signal('InterfaceAdded', self.scan_wpa_interfaces)
        self.wpasup.register_signal('InterfaceRemoved', self.wlan_interface_removed)
        self.scan_wpa_interfaces()
      else:
        # If we don't do anything when wpa_supplicant vanishes, then our signals seem to remain
        # registered when wpa_supplicant re-appears.  However, wpa_supplicant doesn't seem to send
        # InterfaceAdded signals when it comes up, so we must explicitly re-scan the interfaces.
        self.scan_wpa_interfaces()
    else:
      self.wpasup_running = False
      self.select_wlan_interface([])

  def start_watch_thread(self):
    thread = threading.Thread(target=GLib.MainLoop().run)
    thread.daemon = True
    thread.start()
Esempio n. 2
0
class PowerMonitor(metaclass=Singleton):
    """
    Watches for changes to the system's suspend state and
    screensaver, signalling devices to suspend if necessary.
    """
    def __init__(self):
        self._logger = Log.get('uchroma.power')
        self._name_watchers = []
        self._running = False
        self._sleeping = False
        self._user_active = False

        self._session_bus = SessionBus()
        self._system_bus = SystemBus()
        self._dm = UChromaDeviceManager() #singleton


    def _suspend(self, sleeping, fast):
        if self._sleeping == sleeping:
            return

        self._sleeping = sleeping
        for name, device in self._dm.devices.items():
            if sleeping:
                self._logger.info("Suspending device: %s", name)
                device.suspend(fast=fast)
            else:
                self._logger.info("Resuming device: %s", name)
                device.resume()


    def _prepare_for_sleep(self, sleeping):
        self._suspend(sleeping, True)


    def _active_changed(self, active):
        self._suspend(active, False)


    def _is_user_active(self):
        user = self._system_bus.get(LOGIN_SERVICE, "/org/freedesktop/login1/user/self")
        self._logger.info("is_user_active: %s %s", user, user.Display)
        return user is not None and user.Display[0] != ''


    def _user_changed(self, changed):
        is_active = self._is_user_active()
        if is_active != self._user_active:
            self._user_active = is_active
            self._suspend(not self._user_active, True)


    def start(self):
        """
        Connects to the PrepareForSleep signal from login1 to monitor
        system suspend, and sets up watches for known screensaver
        instances.
        """
        if self._running:
            return

        for name, path in SCREENSAVERS:
            def connect_screensaver(*args, bus_name=name, object_path=path):
                """
                Connects the callback when the service appears.
                """
                try:
                    saver = self._session_bus.get(bus_name=bus_name, object_path=object_path)
                    saver.ActiveChanged.connect(self._active_changed)
                    self._logger.info("Connected screensaver: %s:%s %s", bus_name, object_path, args)

                except Exception:
                    self._logger.warn("Could not connect to %s:%s service", bus_name, object_path)


            self._name_watchers.append(self._session_bus.watch_name( \
                    name, name_appeared=connect_screensaver))


        def connect_login1(*args):
            try:
                login1 = self._system_bus.get(LOGIN_SERVICE)
                login1.PrepareForSleep.connect(self._prepare_for_sleep)
                self._logger.info("Connected to %s %s", LOGIN_SERVICE, args)

                user = self._system_bus.get(LOGIN_SERVICE, "/org/freedesktop/login1/user/self")
                user.PropertiesChanged.connect(self._user_changed)

            except Exception:
                self._logger.warn("Could not connect to login1 service")

        self._name_watchers.append(self._system_bus.watch_name( \
                LOGIN_SERVICE, name_appeared=connect_login1))

        self._running = True


    def stop(self):
        """
        Disable the monitor
        """
        if not self._running:
            return

        for watcher in self._name_watchers:
            watcher.unwatch()

        self._name_watchers.clear()

        self._running = False
Esempio n. 3
0
class WlanApp:
    def __init__(self):
        self.prefix = 'W:'
        self.suffix = ' '
        self.tooltip_heading = 'Wireless LAN Status:\n'

        self.iface = None  # Set to interface name to override interface selection

        self.build_ui()

        # Needed by wpa_supplicant.core
        self.reactor = SelectReactor()
        thread = threading.Thread(target=self.reactor.run,
                                  kwargs={'installSignalHandlers': 0})
        thread.daemon = True
        thread.start()
        time.sleep(0.1)  # let reactor start

        self.wpasup = None
        self.wpasup_running = False
        self.wlan = None
        self.wlan_signal = None

        # Monitor the availability of wpa_supplicant via DBus
        self.dbus = SystemBus()
        # watch_name() fires an event as soon as GLib.MainLoop() starts, so we don't need to explicitly
        # call get_wpa_supplicant() here
        self.dbus.watch_name(BUS_NAME, 0, self.get_wpa_supplicant,
                             self.get_wpa_supplicant)
        self.start_watch_thread()

    def build_ui(self):
        self.tray = tray = Gtkti.TrayIcon()
        self.eventbox = eventbox = Gtk.EventBox()
        if background_color:
            css = Gtk.CssProvider()
            css.load_from_data(
                ('* { background-color: ' + background_color + '; }').encode())
            Gtk.StyleContext.add_provider_for_screen(
                Gdk.Screen.get_default(), css,
                Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
        eventbox.set_tooltip_text(self.tooltip_heading +
                                  'WPA Supplicant not running')
        tray.add(eventbox)
        self.tray_label = tray_label = Gtk.Label(label=self.prefix + '_' +
                                                 self.suffix)
        eventbox.add(tray_label)
        tray.show_all()

        menu = Gtk.Menu()
        item_quit = Gtk.MenuItem(label='Quit')

        def quit(menu_item):
            if sys.version_info < (3, 0):
                os.kill(os.getpid(), signal.SIGINT)
            else:
                Gtk.main_quit()

        item_quit.connect('activate', quit)
        menu.append(item_quit)
        menu.show_all()

        def button_pressed(eventbox, event, menu=menu):
            if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3:
                menu.popup(None, None, None, None, event.button, event.time)

        eventbox.connect('button-press-event', button_pressed)

    # Update the UI (thread-safe)
    def update_ui(self):
        GLib.idle_add(self.gtk_update_ui)

    # Update the UI (within the GTK main thread ; not thread-safe)
    def gtk_update_ui(self):
        if not self.wpasup_running:
            display_str = '_'
            tooltip_str = 'WLAN Interface is down (WPA Supplicant is not running)'
        elif not self.wlan:
            display_str = '_'
            tooltip_str = 'WLAN Interface not found via WPA Supplicant'
        else:
            try:
                ifname = self.wlan.get_ifname()
                tooltip_str = ifname
                state = self.wlan.get_state()
                tooltip_str += ' ' + state.title()
                if state == 'interface_disabled':
                    display_str = '_'
                elif state == 'disconnected' or state == 'inactive':
                    display_str = '-'
                elif state == 'scanning':
                    display_str = '?'
                elif state == 'authenticating' or state == 'associating' or state == 'associated' or \
                     state == '4way_handshake' or state == 'group_handshake':
                    display_str = '@'
                elif state == 'completed':
                    display_str = ''
                    tooltip_str += ' Connected'
                elif state == 'unknown':
                    display_str = '!'
                else:
                    display_str = '!'
                    print >> sys.stderr, 'Unknown wpa_supplicant state: ' + state + ' to ' + self.wlan.get_current_bss(
                    ).get_ssid()
                bss = self.wlan.get_current_bss()
                if bss:
                    display_str += bss.get_ssid()
                    tooltip_str += ' to ' + bss.get_ssid()
            except:
                # This is expected if another thread sets self.wlan to None while the above code is
                # executing, or if wpa_supplicant shuts down while the above code is executing.  In either
                # case, another UI update should happen momentarily.
                display_str = '!'
                tooltip_str = 'Unknown (Exception Thrown)'
        self.tray_label.set_text(self.prefix + display_str + self.suffix)
        self.eventbox.set_tooltip_text(self.tooltip_heading + tooltip_str)

        # Return false to unregister this method as a GLib idle handler
        return False

    def select_wlan_interface(self, interfaces):
        if self.wlan_signal:
            wlan_signal = self.wlan_signal  # To avoid race conditions
            self.wlan_signal = None
            wlan_signal.cancel()
        self.wlan = None
        if interfaces:
            if self.iface:
                for interface in interfaces:
                    if interface.get_ifname() == self.iface:
                        self.wlan = interface
                        break
            else:
                self.wlan = interfaces[0]
            self.wlan_signal = \
             self.wlan.register_signal('PropertiesChanged', lambda args: self.update_ui())
        self.update_ui()

    def scan_wpa_interfaces(self, args=None):
        self.wpa_interfaces = self.wpasup.get_interfaces()
        self.select_wlan_interface(self.wpa_interfaces)

    def wlan_interface_removed(self, path):
        # wpa_supplicant sends InterfaceRemoved just before shutting down, and get_interfaces() may
        # throw an exception if it is called while wpa_supplicant is shutting down.  So, instead of
        # calling scan_wpa_interfaces on InterfaceRemoved, it is probably better to keep a cache of the
        # list of interfaces and just delete the relevant interface from the cache.
        self.wpa_interfaces[:] = [
            i for i in self.wpa_interfaces if not i.get_path() == path
        ]
        self.select_wlan_interface(self.wpa_interfaces)

    def get_wpa_supplicant(self, dbus_name_owner=None):
        if dbus_name_owner:
            self.wpasup_running = True
            if not self.wpasup:
                # Connect to wpa_supplicant
                self.wpasup = WpaSupplicantDriver(self.reactor).connect()
                self.wpasup.register_signal('InterfaceAdded',
                                            self.scan_wpa_interfaces)
                self.wpasup.register_signal('InterfaceRemoved',
                                            self.wlan_interface_removed)
                self.scan_wpa_interfaces()
            else:
                # If we don't do anything when wpa_supplicant vanishes, then our signals seem to remain
                # registered when wpa_supplicant re-appears.  However, wpa_supplicant doesn't seem to send
                # InterfaceAdded signals when it comes up, so we must explicitly re-scan the interfaces.
                self.scan_wpa_interfaces()
        else:
            self.wpasup_running = False
            self.select_wlan_interface([])

    def start_watch_thread(self):
        thread = threading.Thread(target=GLib.MainLoop().run)
        thread.daemon = True
        thread.start()