Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
authorMarco Pesenti Gritti <mpgritti@gmail.com>2008-10-04 01:52:36 (GMT)
committer Marco Pesenti Gritti <mpgritti@gmail.com>2008-10-04 01:52:36 (GMT)
commit90b23a07560d4edf173764c3a3ff62507c759814 (patch)
tree56867225f1512c77f2784c4bdd13bec32772823f /extensions
parent8ca1368eec29f1378ac1d81e3494c6d503355d04 (diff)
Rework devices to be actually self contained plugins. A lot
of work is left to cleanup and simplify the code. I'm sorry for the large changes but the old design didn't really make any sense.
Diffstat (limited to 'extensions')
-rw-r--r--extensions/Makefile.am2
-rw-r--r--extensions/deviceicon/Makefile.am7
-rw-r--r--extensions/deviceicon/__init__.py0
-rw-r--r--extensions/deviceicon/battery.py220
-rw-r--r--extensions/deviceicon/speaker.py210
-rw-r--r--extensions/deviceicon/wireless.py429
6 files changed, 867 insertions, 1 deletions
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index 464800b..d402374 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -1 +1 @@
-SUBDIRS = cpsection
+SUBDIRS = cpsection deviceicon
diff --git a/extensions/deviceicon/Makefile.am b/extensions/deviceicon/Makefile.am
new file mode 100644
index 0000000..66268fd
--- /dev/null
+++ b/extensions/deviceicon/Makefile.am
@@ -0,0 +1,7 @@
+sugardir = $(pkgdatadir)/extensions/deviceicon
+
+sugar_PYTHON = \
+ __init__.py \
+ wireless.py \
+ battery.py \
+ speaker.py
diff --git a/extensions/deviceicon/__init__.py b/extensions/deviceicon/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/extensions/deviceicon/__init__.py
diff --git a/extensions/deviceicon/battery.py b/extensions/deviceicon/battery.py
new file mode 100644
index 0000000..37691b4
--- /dev/null
+++ b/extensions/deviceicon/battery.py
@@ -0,0 +1,220 @@
+# Copyright (C) 2006-2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from gettext import gettext as _
+
+import gobject
+import gtk
+import dbus
+
+from sugar import profile
+from sugar.graphics import style
+from sugar.graphics.icon import get_icon_state
+from sugar.graphics.tray import TrayIcon
+from sugar.graphics.palette import Palette
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+
+_ICON_NAME = 'battery'
+
+_STATUS_CHARGING = 0
+_STATUS_DISCHARGING = 1
+_STATUS_FULLY_CHARGED = 2
+
+_LEVEL_PROP = 'battery.charge_level.percentage'
+_CHARGING_PROP = 'battery.rechargeable.is_charging'
+_DISCHARGING_PROP = 'battery.rechargeable.is_discharging'
+
+class DeviceView(TrayIcon):
+
+ FRAME_POSITION_RELATIVE = 1000
+
+ def __init__(self, udi):
+ TrayIcon.__init__(self, icon_name=_ICON_NAME,
+ xo_color=profile.get_color())
+
+ self._model = DeviceModel(udi)
+ self.palette = BatteryPalette(_('My Battery'))
+ self.set_palette(self.palette)
+ self.palette.props.invoker = FrameWidgetInvoker(self)
+ self.palette.set_group_id('frame')
+
+ self._model.connect('notify::level',
+ self._battery_status_changed_cb)
+ self._model.connect('notify::charging',
+ self._battery_status_changed_cb)
+ self._model.connect('notify::discharging',
+ self._battery_status_changed_cb)
+ self._update_info()
+
+ def _update_info(self):
+ name = _ICON_NAME
+ current_level = self._model.props.level
+ xo_color = profile.get_color()
+ badge_name = None
+
+ if self._model.props.charging:
+ status = _STATUS_CHARGING
+ name += '-charging'
+ xo_color = XoColor('%s,%s' % (style.COLOR_WHITE.get_svg(),
+ style.COLOR_WHITE.get_svg()))
+ elif self._model.props.discharging:
+ status = _STATUS_DISCHARGING
+ if current_level <= 15:
+ badge_name = 'emblem-warning'
+ else:
+ status = _STATUS_FULLY_CHARGED
+
+ self.icon.props.icon_name = get_icon_state(name, current_level, step=-5)
+ self.icon.props.xo_color = xo_color
+ self.icon.props.badge_name = badge_name
+
+ self.palette.set_level(current_level)
+ self.palette.set_status(status)
+
+ def _battery_status_changed_cb(self, pspec, param):
+ self._update_info()
+
+class BatteryPalette(Palette):
+
+ def __init__(self, primary_text):
+ Palette.__init__(self, primary_text)
+
+ self._level = 0
+ self._progress_bar = gtk.ProgressBar()
+ self._progress_bar.set_size_request(
+ style.zoom(style.GRID_CELL_SIZE * 4), -1)
+ self._progress_bar.show()
+ self._status_label = gtk.Label()
+ self._status_label.show()
+
+ vbox = gtk.VBox()
+ vbox.pack_start(self._progress_bar)
+ vbox.pack_start(self._status_label)
+ vbox.show()
+
+ self.set_content(vbox)
+
+ def set_level(self, percent):
+ self._level = percent
+ fraction = percent / 100.0
+ self._progress_bar.set_fraction(fraction)
+
+ def set_status(self, status):
+ current_level = self._level
+ secondary_text = ''
+ status_text = '%s%%' % current_level
+
+ if status == _STATUS_CHARGING:
+ secondary_text = _('Charging')
+ elif status == _STATUS_DISCHARGING:
+ if current_level <= 15:
+ secondary_text = _('Very little power remaining')
+ else:
+ #TODO: make this less of an wild/educated guess
+ minutes_remaining = int(current_level / 0.59)
+ remaining_hourpart = minutes_remaining / 60
+ remaining_minpart = minutes_remaining % 60
+ secondary_text = _('%(hour)d:%(min).2d remaining'
+ % { 'hour': remaining_hourpart,
+ 'min': remaining_minpart})
+ else:
+ secondary_text = _('Charged')
+
+ self.props.secondary_text = secondary_text
+ self._status_label.set_text(status_text)
+
+class DeviceModel(gobject.GObject):
+ __gproperties__ = {
+ 'level' : (int, None, None, 0, 100, 0,
+ gobject.PARAM_READABLE),
+ 'charging' : (bool, None, None, False,
+ gobject.PARAM_READABLE),
+ 'discharging' : (bool, None, None, False,
+ gobject.PARAM_READABLE)
+ }
+
+ def __init__(self, udi):
+ gobject.GObject.__init__(self)
+
+ bus = dbus.Bus(dbus.Bus.TYPE_SYSTEM)
+ proxy = bus.get_object('org.freedesktop.Hal', udi,
+ follow_name_owner_changes=True)
+ self._battery = dbus.Interface(proxy, 'org.freedesktop.Hal.Device')
+ bus.add_signal_receiver(self._battery_changed,
+ 'PropertyModified',
+ 'org.freedesktop.Hal.Device',
+ 'org.freedesktop.Hal',
+ udi)
+
+ self._level = self._get_level()
+ self._charging = self._get_charging()
+ self._discharging = self._get_discharging()
+
+ def _get_level(self):
+ try:
+ return self._battery.GetProperty(_LEVEL_PROP)
+ except dbus.DBusException:
+ logging.error('Cannot access %s' % _LEVEL_PROP)
+ return 0
+
+ def _get_charging(self):
+ try:
+ return self._battery.GetProperty(_CHARGING_PROP)
+ except dbus.DBusException:
+ logging.error('Cannot access %s' % _CHARGING_PROP)
+ return False
+
+ def _get_discharging(self):
+ try:
+ return self._battery.GetProperty(_DISCHARGING_PROP)
+ except dbus.DBusException:
+ logging.error('Cannot access %s' % _DISCHARGING_PROP)
+ return False
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'level':
+ return self._level
+ if pspec.name == 'charging':
+ return self._charging
+ if pspec.name == 'discharging':
+ return self._discharging
+
+ def get_type(self):
+ return 'battery'
+
+ def _battery_changed(self, num_changes, changes_list):
+ for change in changes_list:
+ if change[0] == _LEVEL_PROP:
+ self._level = self._get_level()
+ self.notify('level')
+ elif change[0] == _CHARGING_PROP:
+ self._charging = self._get_charging()
+ self.notify('charging')
+ elif change[0] == _DISCHARGING_PROP:
+ self._discharging = self._get_discharging()
+ self.notify('discharging')
+
+def setup(tray):
+ bus = dbus.Bus(dbus.Bus.TYPE_SYSTEM)
+ proxy = bus.get_object('org.freedesktop.Hal',
+ '/org/freedesktop/Hal/Manager')
+ hal_manager = dbus.Interface(proxy, 'org.freedesktop.Hal.Manager')
+
+ for udi in hal_manager.FindDeviceByCapability('battery'):
+ tray.add_device(DeviceView(udi))
diff --git a/extensions/deviceicon/speaker.py b/extensions/deviceicon/speaker.py
new file mode 100644
index 0000000..70cd3dc
--- /dev/null
+++ b/extensions/deviceicon/speaker.py
@@ -0,0 +1,210 @@
+# Copyright (C) 2008 Martin Dengler
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+
+import gobject
+import gtk
+
+from sugar import profile
+from sugar.graphics import style
+from sugar.graphics.icon import get_icon_state, Icon
+from sugar.graphics.menuitem import MenuItem
+from sugar.graphics.tray import TrayIcon
+from sugar.graphics.palette import Palette
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+from jarabe.model import sound
+
+_ICON_NAME = 'speaker'
+
+class DeviceView(TrayIcon):
+
+ FRAME_POSITION_RELATIVE = 800
+
+ def __init__(self):
+ TrayIcon.__init__(self,
+ icon_name=_ICON_NAME,
+ xo_color=profile.get_color())
+
+ self._model = DeviceModel()
+ self.palette = SpeakerPalette(_('My Speakers'), model=self._model)
+ self.palette.props.invoker = FrameWidgetInvoker(self)
+ self.palette.set_group_id('frame')
+
+ self._model.connect('notify::level', self.__speaker_status_changed_cb)
+ self._model.connect('notify::muted', self.__speaker_status_changed_cb)
+
+ self.connect('expose-event', self.__expose_event_cb)
+
+ self._icon_widget.connect('button-press-event',
+ self.__update_mute_status)
+
+ self._update_info()
+
+ def _update_info(self):
+ name = _ICON_NAME
+ current_level = self._model.props.level
+ xo_color = profile.get_color()
+
+ if self._model.props.muted:
+ name += '-muted'
+ xo_color = XoColor('%s,%s' % (style.COLOR_WHITE.get_svg(),
+ style.COLOR_WHITE.get_svg()))
+
+ self.icon.props.icon_name = get_icon_state(name, current_level, step=-1)
+ self.icon.props.xo_color = xo_color
+
+ def __update_mute_status(self, *args):
+ self._model.props.muted = not self._model.props.muted
+
+ def __expose_event_cb(self, *args):
+ self._update_info()
+
+ def __speaker_status_changed_cb(self, pspec_, param_):
+ self._update_info()
+
+class SpeakerPalette(Palette):
+
+ def __init__(self, primary_text, model):
+ Palette.__init__(self, label=primary_text)
+
+ self._model = model
+
+ self.set_size_request(style.zoom(style.GRID_CELL_SIZE * 4), -1)
+
+ vbox = gtk.VBox()
+ self.set_content(vbox)
+ vbox.show()
+
+ vol_step = sound.VOLUME_STEP
+ self._adjustment = gtk.Adjustment(value=self._model.props.level,
+ lower=0,
+ upper=100 + vol_step,
+ step_incr=vol_step,
+ page_incr=vol_step,
+ page_size=vol_step)
+ self._hscale = gtk.HScale(self._adjustment)
+ self._hscale.set_digits(0)
+ self._hscale.set_draw_value(False)
+ vbox.add(self._hscale)
+ self._hscale.show()
+
+ self._mute_item = MenuItem('')
+ self._mute_icon = Icon(icon_size=gtk.ICON_SIZE_MENU)
+ self._mute_item.set_image(self._mute_icon)
+ self.menu.append(self._mute_item)
+ self._mute_item.show()
+
+ self._adjustment_handler_id = \
+ self._adjustment.connect('value_changed',
+ self.__adjustment_changed_cb)
+
+ self._model_notify_level_handler_id = \
+ self._model.connect('notify::level', self.__level_changed_cb)
+ self._model.connect('notify::muted', self.__muted_changed_cb)
+
+ self._mute_item.connect('activate', self.__mute_activate_cb)
+
+ self.connect('popup', self.__popup_cb)
+
+ def _update_muted(self):
+ if self._model.props.muted:
+ mute_item_text = _('Unmute')
+ mute_item_icon_name = 'dialog-ok'
+ else:
+ mute_item_text = _('Mute')
+ mute_item_icon_name = 'dialog-cancel'
+ self._mute_item.get_child().set_text(mute_item_text)
+ self._mute_icon.props.icon_name = mute_item_icon_name
+
+ def _update_level(self):
+ if self._adjustment.value != self._model.props.level:
+ self._adjustment.handler_block(self._adjustment_handler_id)
+ try:
+ self._adjustment.value = self._model.props.level
+ finally:
+ self._adjustment.handler_unblock(self._adjustment_handler_id)
+
+ def __adjustment_changed_cb(self, adj_):
+ self._model.handler_block(self._model_notify_level_handler_id)
+ try:
+ self._model.props.level = self._adjustment.value
+ finally:
+ self._model.handler_unblock(self._model_notify_level_handler_id)
+ self._model.props.muted = self._adjustment.value == 0
+
+ def __level_changed_cb(self, pspec_, param_):
+ self._update_level()
+
+ def __mute_activate_cb(self, menuitem_):
+ self._model.props.muted = not self._model.props.muted
+
+ def __muted_changed_cb(self, pspec_, param_):
+ self._update_muted()
+
+ def __popup_cb(self, palette_):
+ self._update_level()
+ self._update_muted()
+
+class DeviceModel(gobject.GObject):
+ __gproperties__ = {
+ 'level' : (int, None, None, 0, 100, 0, gobject.PARAM_READWRITE),
+ 'muted' : (bool, None, None, False, gobject.PARAM_READWRITE),
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ sound.muted_changed.connect(self.__muted_changed_cb)
+ sound.volume_changed.connect(self.__volume_changed_cb)
+
+ def __muted_changed_cb(self):
+ self.notify('muted')
+
+ def __volume_changed_cb(self):
+ self.notify('level')
+
+ def _get_level(self):
+ return sound.get_volume()
+
+ def _set_level(self, new_volume):
+ sound.set_volume(new_volume)
+
+ def _get_muted(self):
+ return sound.get_muted()
+
+ def _set_muted(self, mute):
+ sound.set_muted(mute)
+
+ def get_type(self):
+ return 'speaker'
+
+ def do_get_property(self, pspec):
+ if pspec.name == "level":
+ return self._get_level()
+ elif pspec.name == "muted":
+ return self._get_muted()
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == "level":
+ self._set_level(value)
+ elif pspec.name == "muted":
+ self._set_muted(value)
+
+def setup(tray):
+ tray.add_device(DeviceView())
diff --git a/extensions/deviceicon/wireless.py b/extensions/deviceicon/wireless.py
new file mode 100644
index 0000000..1544526
--- /dev/null
+++ b/extensions/deviceicon/wireless.py
@@ -0,0 +1,429 @@
+#
+# Copyright (C) 2006-2007 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from gettext import gettext as _
+
+import gobject
+import gtk
+
+from sugar.graphics.icon import get_icon_state
+from sugar.graphics.tray import TrayIcon
+from sugar.graphics import style
+from sugar.graphics.palette import Palette
+from sugar import profile
+
+from jarabe.model import network
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+
+_ICON_NAME = 'network-wireless'
+
+STATE_ACTIVATING = 0
+STATE_ACTIVATED = 1
+STATE_INACTIVE = 2
+
+nm_state_to_state = {
+ network.DEVICE_STATE_ACTIVATING : STATE_ACTIVATING,
+ network.DEVICE_STATE_ACTIVATED : STATE_ACTIVATED,
+ network.DEVICE_STATE_INACTIVE : STATE_INACTIVE
+}
+
+class WirelessDeviceView(TrayIcon):
+
+ FRAME_POSITION_RELATIVE = 300
+
+ def __init__(self, nm_device):
+ TrayIcon.__init__(self, icon_name=_ICON_NAME)
+
+ self.model = WirelessDeviceModel(nm_device)
+
+ meshdev = None
+ network_manager = network.get_manager()
+ for dev in network_manager.get_devices():
+ if dev.get_type() == network.DEVICE_TYPE_802_11_MESH_OLPC:
+ meshdev = dev
+ break
+
+ self._counter = 0
+ self.palette = WirelessPalette(self._get_palette_primary_text(),
+ meshdev)
+ self.set_palette(self.palette)
+ self.palette.props.invoker = FrameWidgetInvoker(self)
+ self.palette.set_group_id('frame')
+ self.palette.set_frequency(self._model.props.frequency)
+
+ self._model.connect('notify::name', self._name_changed_cb)
+ self._model.connect('notify::strength', self._strength_changed_cb)
+ self._model.connect('notify::state', self._state_changed_cb)
+
+ self._update_icon()
+ self._update_state()
+
+ def _get_palette_primary_text(self):
+ if self._model.props.state == STATE_INACTIVE:
+ return _("Disconnected")
+ return self._model.props.name
+
+ def _strength_changed_cb(self, model, pspec):
+ self._update_icon()
+ # Only update frequency periodically
+ if self._counter % 4 == 0:
+ self.palette.set_frequency(self._model.props.frequency)
+ self._counter += 1
+
+ def _name_changed_cb(self, model, pspec):
+ self.palette.set_primary_text(self._get_palette_primary_text())
+
+ def _state_changed_cb(self, model, pspec):
+ self._update_icon()
+ self._update_state()
+ self.palette.set_primary_text(self._get_palette_primary_text())
+
+ def _update_icon(self):
+ # keep this code in sync with view/home/MeshBox.py
+ strength = self._model.props.strength
+ if self._model.props.state == STATE_INACTIVE:
+ strength = 0
+ if self._model.props.state == STATE_ACTIVATED:
+ icon_name = '%s-connected' % _ICON_NAME
+ else:
+ icon_name = _ICON_NAME
+ icon_name = get_icon_state(icon_name, strength)
+ if icon_name:
+ self.icon.props.icon_name = icon_name
+
+ def _update_state(self):
+ # FIXME Change icon colors once we have real icons
+ state = self._model.props.state
+ if state == STATE_ACTIVATING:
+ self.icon.props.fill_color = style.COLOR_INACTIVE_FILL.get_svg()
+ self.icon.props.stroke_color = style.COLOR_INACTIVE_STROKE.get_svg()
+ elif state == STATE_ACTIVATED:
+ (stroke, fill) = self._model.get_active_network_colors()
+ self.icon.props.stroke_color = stroke
+ self.icon.props.fill_color = fill
+ elif state == STATE_INACTIVE:
+ self.icon.props.fill_color = style.COLOR_INACTIVE_FILL.get_svg()
+ self.icon.props.stroke_color = style.COLOR_INACTIVE_STROKE.get_svg()
+
+class WirelessPalette(Palette):
+ def __init__(self, primary_text, meshdev):
+ Palette.__init__(self, primary_text, menu_after_content=True)
+ self._meshdev = meshdev
+
+ self._chan_label = gtk.Label()
+ self._chan_label.show()
+
+ vbox = gtk.VBox()
+ vbox.pack_start(self._chan_label)
+ vbox.show()
+
+ if meshdev:
+ disconnect_item = gtk.MenuItem(_('Disconnect...'))
+ disconnect_item.connect('activate', self._disconnect_activate_cb)
+ self.menu.append(disconnect_item)
+ disconnect_item.show()
+
+ self.set_content(vbox)
+
+ def _disconnect_activate_cb(self, menuitem):
+ # Disconnection for an AP means activating the default mesh device
+ network_manager = network.get_manager()
+ if network_manager and self._meshdev:
+ network_manager.set_active_device(self._meshdev)
+
+ def set_frequency(self, freq):
+ try:
+ chan = network.freq_to_channel(freq)
+ except KeyError:
+ chan = 0
+ self._chan_label.set_text("%s: %d" % (_("Channel"), chan))
+
+class MeshDeviceView(TrayIcon):
+
+ FRAME_POSITION_RELATIVE = 400
+
+ def __init__(self, nm_device):
+ TrayIcon.__init__(self, icon_name='network-mesh')
+
+ self.model = MeshDeviceModel(nm_device)
+
+ self.palette = MeshPalette(_("Mesh Network"), self.model)
+ self.set_palette(self.palette)
+ self.palette.props.invoker = FrameWidgetInvoker(self)
+ self.palette.set_group_id('frame')
+
+ self.model.connect('notify::state', self._state_changed_cb)
+ self.model.connect('notify::activation-stage', self._state_changed_cb)
+ self._update_state()
+
+ def _state_changed_cb(self, model, pspec):
+ self._update_state()
+
+ def _update_state(self):
+ # FIXME Change icon colors once we have real icons
+ state = self._model.props.state
+ self.palette.update_state(state)
+
+ if state == STATE_ACTIVATING:
+ self.icon.props.fill_color = style.COLOR_INACTIVE_FILL.get_svg()
+ self.icon.props.stroke_color = style.COLOR_INACTIVE_STROKE.get_svg()
+ elif state == STATE_ACTIVATED:
+ self.icon.props.xo_color = profile.get_color()
+ elif state == STATE_INACTIVE:
+ self.icon.props.fill_color = style.COLOR_INACTIVE_FILL.get_svg()
+ self.icon.props.stroke_color = style.COLOR_INACTIVE_STROKE.get_svg()
+
+ if state == STATE_INACTIVE:
+ self.palette.set_primary_text(_("Mesh Network"))
+ else:
+ chan = network.freq_to_channel(self._model.props.frequency)
+ if chan > 0:
+ self.palette.set_primary_text(_("Mesh Network") + " %d" % chan)
+ self.palette.set_mesh_step(self._model.props.mesh_step, state)
+
+class MeshPalette(Palette):
+ def __init__(self, primary_text, model):
+ Palette.__init__(self, primary_text, menu_after_content=True)
+ self._model = model
+
+ self._step_label = gtk.Label()
+ self._step_label.show()
+
+ vbox = gtk.VBox()
+ vbox.pack_start(self._step_label)
+ vbox.show()
+
+ self.set_content(vbox)
+
+ self._disconnect_item = gtk.MenuItem(_('Disconnect...'))
+ self._disconnect_item.connect('activate', self._disconnect_activate_cb)
+ self.menu.append(self._disconnect_item)
+
+ def update_state(self, state):
+ if state == STATE_ACTIVATED:
+ self._disconnect_item.show()
+ else:
+ self._disconnect_item.hide()
+
+ def _disconnect_activate_cb(self, menuitem):
+ # Disconnection for an mesh means activating the default mesh device
+ # again without a channel
+ network_manager = network.get_manager()
+ nm_device = self._model.get_nm_device()
+ if network_manager and nm_device:
+ network_manager.set_active_device(nm_device)
+
+ def set_mesh_step(self, step, state):
+ label = ""
+ if step == 1:
+ if state == STATE_ACTIVATED:
+ label = _("Connected to a School Mesh Portal")
+ elif state == STATE_ACTIVATING:
+ label = _("Looking for a School Mesh Portal...")
+ elif step == 3:
+ if state == STATE_ACTIVATED:
+ label = _("Connected to an XO Mesh Portal")
+ elif state == STATE_ACTIVATING:
+ label = _("Looking for an XO Mesh Portal...")
+ elif step == 4:
+ if state == STATE_ACTIVATED:
+ label = _("Connected to a Simple Mesh")
+ elif state == STATE_ACTIVATING:
+ label = _("Starting a Simple Mesh")
+
+ if len(label):
+ self._step_label.set_text(label)
+ else:
+ logging.debug("Unhandled mesh step %d" % step)
+ self._step_label.set_text(_("Unknown Mesh"))
+
+class WirelessDeviceModel(gobject.GObject):
+ __gproperties__ = {
+ 'strength' : (int, None, None, 0, 100, 0,
+ gobject.PARAM_READABLE),
+ 'state' : (int, None, None, STATE_ACTIVATING,
+ STATE_INACTIVE, 0, gobject.PARAM_READABLE),
+ 'activation-stage': (int, None, None, 0, 7, 0, gobject.PARAM_READABLE),
+ 'frequency': (float, None, None, 0, 2.72, 0, gobject.PARAM_READABLE),
+ 'mesh-step': (int, None, None, 0, 4, 0, gobject.PARAM_READABLE),
+ }
+
+ def __init__(self, nm_device):
+ gobject.GObject.__init__(self)
+
+ self._nm_device = nm_device
+
+ self._nm_device.connect('strength-changed',
+ self._strength_changed_cb)
+ self._nm_device.connect('state-changed',
+ self._state_changed_cb)
+ self._nm_device.connect('activation-stage-changed',
+ self._activation_stage_changed_cb)
+
+ def _strength_changed_cb(self, nm_device):
+ self.notify('strength')
+
+ def _state_changed_cb(self, nm_device):
+ self.notify('state')
+
+ def _activation_stage_changed_cb(self, nm_device):
+ self.notify('activation-stage')
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'strength':
+ return self._nm_device.get_strength()
+ elif pspec.name == 'state':
+ nm_state = self._nm_device.get_state()
+ return nm_state_to_state[nm_state]
+ elif pspec.name == 'activation-stage':
+ return self._nm_device.get_activation_stage()
+ elif pspec.name == 'frequency':
+ return self._nm_device.get_frequency()
+ elif pspec.name == 'mesh-step':
+ return self._nm_device.get_mesh_step()
+
+ def get_type(self):
+ return 'mesh'
+
+ def get_id(self):
+ return str(self._nm_device.get_op())
+
+ def get_nm_device(self):
+ return self._nm_device
+
+class MeshDeviceModel(gobject.GObject):
+ __gproperties__ = {
+ 'name' : (str, None, None, None,
+ gobject.PARAM_READABLE),
+ 'strength' : (int, None, None, 0, 100, 0,
+ gobject.PARAM_READABLE),
+ 'state' : (int, None, None, STATE_ACTIVATING,
+ STATE_INACTIVE, 0, gobject.PARAM_READABLE),
+ 'frequency': (float, None, None, 0.0, 9999.99, 0.0,
+ gobject.PARAM_READABLE)
+ }
+
+ def __init__(self, nm_device):
+ gobject.GObject.__init__(self)
+
+ self._nm_device = nm_device
+
+ self._nm_device.connect('strength-changed',
+ self._strength_changed_cb)
+ self._nm_device.connect('ssid-changed',
+ self._ssid_changed_cb)
+ self._nm_device.connect('state-changed',
+ self._state_changed_cb)
+
+ def _strength_changed_cb(self, nm_device):
+ self.notify('strength')
+
+ def _ssid_changed_cb(self, nm_device):
+ self.notify('name')
+
+ def _state_changed_cb(self, nm_device):
+ self.notify('state')
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'strength':
+ return self._nm_device.get_strength()
+ elif pspec.name == 'name':
+ logging.debug('wireless.Device.props.name: %s' %
+ self._nm_device.get_ssid())
+ return self._nm_device.get_ssid()
+ elif pspec.name == 'state':
+ nm_state = self._nm_device.get_state()
+ return nm_state_to_state[nm_state]
+ elif pspec.name == 'frequency':
+ return self._nm_device.get_frequency()
+
+ def get_type(self):
+ return 'wireless'
+
+ def get_id(self):
+ return str(self._nm_device.get_op())
+
+ def get_active_network_colors(self):
+ net = self._nm_device.get_active_network()
+ if not net:
+ return (None, None)
+ return net.get_colors()
+
+_devices = {}
+_sigids = {}
+
+def setup(tray):
+ network_manager = network.get_manager()
+ if not network_manager:
+ return
+
+ for dev in network_manager.get_devices():
+ _check_network_device(dev)
+
+ network_manager.connect('device-added',
+ _network_device_added_cb, tray)
+ network_manager.connect('device-activating',
+ _network_device_activating_cb, tray)
+ network_manager.connect('device-removed',
+ _network_device_removed_cb, tray)
+
+def _network_device_added_cb(manager, nm_device, tray):
+ state = nm_device.get_state()
+ if state == network.DEVICE_STATE_ACTIVATING or \
+ state == network.DEVICE_STATE_ACTIVATED:
+ _check_network_device(tray, nm_device)
+
+def _network_device_activating_cb(manager, nm_device, tray):
+ _check_network_device(tray, nm_device)
+
+def _network_device_removed_cb(manager, nm_device, tray):
+ if _devices.has_key(str(nm_device.get_op())):
+ tray.remove_device(_devices[str(nm_device.get_op())])
+
+def _check_network_device(tray, nm_device):
+ if not nm_device.is_valid():
+ logging.debug("Device %s not valid" % nm_device.get_op())
+ return
+
+ dtype = nm_device.get_type()
+ if dtype == network.DEVICE_TYPE_802_11_WIRELESS \
+ or dtype == network.DEVICE_TYPE_802_11_MESH_OLPC:
+ _add_network_device(tray, nm_device)
+
+def _network_device_state_changed_cb(model, param, tray, dev):
+ if dev.props.state == STATE_INACTIVE:
+ tray.remove_device(dev)
+
+def _add_network_device(tray, nm_device):
+ if _devices.has_key(str(nm_device.get_op())):
+ logging.debug("Tried to add device %s twice" % nm_device.get_op())
+ return
+
+ dtype = nm_device.get_type()
+ if dtype == network.DEVICE_TYPE_802_11_WIRELESS:
+ dev = WirelessDeviceView(nm_device)
+ tray.add_device(dev)
+ sigid = dev.model.connect('notify::state',
+ _network_device_state_changed_cb, tray, dev)
+ _sigids[dev] = sigid
+ if dtype == network.DEVICE_TYPE_802_11_MESH_OLPC:
+ dev = MeshDeviceView(nm_device)
+ tray.add_device(dev)
+ sigid = dev.model.connect('notify::state',
+ _network_device_state_changed_cb, tray, dev)
+ _sigids[dev] = sigid