diff options
author | Bernie Innocenti <bernie@codewiz.org> | 2010-08-25 02:54:57 (GMT) |
---|---|---|
committer | Bernie Innocenti <bernie@codewiz.org> | 2010-08-25 02:54:57 (GMT) |
commit | 9e38b5be6f736f947763ca56435e455c20776754 (patch) | |
tree | b71a2f7493bbe5ba44c451520e9131d1f6f54921 /rpms | |
parent | 731c306f07c9c1f72019bb8ac6751fabdbcdd1fa (diff) |
Add patches for sl#1610 and sl#1673
sl#1673 obsoletes discard_network_connections.patch and causes
a ripple effect on several other patches.
Diffstat (limited to 'rpms')
-rw-r--r-- | rpms/sugar/accessibility_0001_cp_accessibility_keyboard.patch | 2 | ||||
-rw-r--r-- | rpms/sugar/discard_network_connections.patch | 46 | ||||
-rw-r--r-- | rpms/sugar/sl1610-default-ad-hoc-networks.patch | 1120 | ||||
-rw-r--r-- | rpms/sugar/sl1673-fix-network-disconnect-and-discard-history-v2.patch | 507 | ||||
-rw-r--r-- | rpms/sugar/sl1814-consolidate-activity-launch-entry-point.patch | 292 | ||||
-rw-r--r-- | rpms/sugar/sl1940-register-session-failed-fix.patch | 8 | ||||
-rw-r--r-- | rpms/sugar/sugar.spec | 6 |
7 files changed, 1928 insertions, 53 deletions
diff --git a/rpms/sugar/accessibility_0001_cp_accessibility_keyboard.patch b/rpms/sugar/accessibility_0001_cp_accessibility_keyboard.patch index 2b009f5..c1e426d 100644 --- a/rpms/sugar/accessibility_0001_cp_accessibility_keyboard.patch +++ b/rpms/sugar/accessibility_0001_cp_accessibility_keyboard.patch @@ -469,8 +469,8 @@ diff -u -r -N sugar-0.88.1.original/src/jarabe/model/Makefile.am sugar-0.88.1/sr --- sugar-0.88.1.original/src/jarabe/model/Makefile.am 2010-07-27 10:55:14.456503932 -0300 +++ sugar-0.88.1/src/jarabe/model/Makefile.am 2010-07-27 11:47:46.002753886 -0300 @@ -1,6 +1,7 @@ - sugardir = $(pythondir)/jarabe/model sugar_PYTHON = \ + adhoc.py \ __init__.py \ + accessibility.py \ buddy.py \ diff --git a/rpms/sugar/discard_network_connections.patch b/rpms/sugar/discard_network_connections.patch deleted file mode 100644 index 8a0943c..0000000 --- a/rpms/sugar/discard_network_connections.patch +++ /dev/null @@ -1,46 +0,0 @@ -From: Daniel Castelo - -diff -u -r -N sugar-0.88.1-copy/extensions/cpsection/network/model.py sugar-0.88.1/extensions/cpsection/network/model.py ---- sugar-0.88.1-copy/extensions/cpsection/network/model.py 2010-02-20 14:47:08.000000000 -0200 -+++ sugar-0.88.1/extensions/cpsection/network/model.py 2010-07-28 19:55:53.067894000 -0300 -@@ -15,10 +15,15 @@ - # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - # - -+import logging -+import os -+ - import dbus - from gettext import gettext as _ - import gconf - -+from sugar import env -+ - _NM_SERVICE = 'org.freedesktop.NetworkManager' - _NM_PATH = '/org/freedesktop/NetworkManager' - _NM_IFACE = 'org.freedesktop.NetworkManager' -@@ -116,7 +121,15 @@ - def clear_networks(): - """Clear saved passwords and network configurations. - """ -- pass -+ profile_path = env.get_profile_path() -+ config_path = os.path.join(profile_path, 'nm', 'connections.cfg') -+ config_file = open(config_path, 'w') -+ try: -+ config_file.write('') -+ except: -+ logging.exception('Can not write %s', config_path) -+ f.close() -+ return 1 - - def get_publish_information(): - client = gconf.client_get_default() -diff -u -r -N sugar-0.88.1-copy/extensions/cpsection/network/view.py sugar-0.88.1/extensions/cpsection/network/view.py ---- sugar-0.88.1-copy/extensions/cpsection/network/view.py 2010-02-20 14:47:08.000000000 -0200 -+++ sugar-0.88.1/extensions/cpsection/network/view.py 2010-07-28 19:54:18.746893000 -0300 -@@ -248,3 +248,4 @@ - - def __network_configuration_reset_cb(self, widget): - self._model.clear_networks() -+ self.needs_restart = True diff --git a/rpms/sugar/sl1610-default-ad-hoc-networks.patch b/rpms/sugar/sl1610-default-ad-hoc-networks.patch new file mode 100644 index 0000000..1db172f --- /dev/null +++ b/rpms/sugar/sl1610-default-ad-hoc-networks.patch @@ -0,0 +1,1120 @@ +From 5ff30eadf670f5225ae305f10e248c7d97a88fb4 Mon Sep 17 00:00:00 2001 +From: Simon Schampijer <simon@schampijer.de> +Date: Fri, 13 Aug 2010 13:14:29 +0200 +Subject: [PATCH] Add default Ad-hoc networks #1610 +Organization: Sugar Labs Foundation +X-Subversion: sucks + +This patch adds three default Ad-hoc networks, for channel 1, 6 and 11. They +are represented with designated icons in the neighborhood view. This will +mimic the mesh behavior on devices where mesh hardware is not available +and make the "under a tree"-scenario possible in those cases. If Sugar sees +no "known" network when it starts, it does autoconnect to an Ad-hoc network. + +http://wiki.sugarlabs.org/go/Features/Sugar_Adhoc_Networks +--- + data/sugar.schemas.in | 14 ++ + extensions/deviceicon/network.py | 116 +++------------ + src/jarabe/desktop/meshbox.py | 300 +++++++++++++++++++++++++++++++++----- + src/jarabe/model/Makefile.am | 1 + + src/jarabe/model/adhoc.py | 299 +++++++++++++++++++++++++++++++++++++ + src/jarabe/model/network.py | 42 +++++- + 6 files changed, 639 insertions(+), 133 deletions(-) + create mode 100644 src/jarabe/model/adhoc.py + +diff --git a/data/sugar.schemas.in b/data/sugar.schemas.in +index b9606ba..2e6b820 100644 +--- a/data/sugar.schemas.in ++++ b/data/sugar.schemas.in +diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py +@@ -329,5 +329,18 @@ + <long>GSM network personal unlock key configuration</long> + </locale> + </schema> ++ <schema> ++ <key>/schemas/desktop/sugar/network/adhoc</key> ++ <applyto>/desktop/sugar/network/adhoc</applyto> ++ <owner>sugar</owner> ++ <type>bool</type> ++ <default>true</default> ++ <locale name="C"> ++ <short>Show Sugar Ad-hoc networks</short> ++ <long>If TRUE, Sugar will show default Ad-hoc networks for ++ channel 1,6 and 11. If Sugar sees no "known" network when ++ it starts, it does autoconnect to an Ad-hoc network.</long> ++ </locale> ++ </schema> + </schemalist> + </gconfschemafile> +index b61de22..562d63b 100644 +--- a/extensions/deviceicon/network.py ++++ b/extensions/deviceicon/network.py +@@ -68,24 +68,16 @@ _GSM_STATE_CONNECTING = 2 + _GSM_STATE_CONNECTED = 3 + _GSM_STATE_FAILED = 4 + +-def frequency_to_channel(frequency): +- ftoc = { 2412: 1, 2417: 2, 2422: 3, 2427: 4, +- 2432: 5, 2437: 6, 2442: 7, 2447: 8, +- 2452: 9, 2457: 10, 2462: 11, 2467: 12, +- 2472: 13} +- return ftoc[frequency] + + class WirelessPalette(Palette): + __gtype_name__ = 'SugarWirelessPalette' + + __gsignals__ = { + 'deactivate-connection' : (gobject.SIGNAL_RUN_FIRST, +- gobject.TYPE_NONE, ([])), +- 'create-connection' : (gobject.SIGNAL_RUN_FIRST, +- gobject.TYPE_NONE, ([])), ++ gobject.TYPE_NONE, ([])) + } + +- def __init__(self, primary_text, can_create=True): ++ def __init__(self, primary_text): + Palette.__init__(self, label=primary_text) + + self._disconnect_item = None +@@ -119,12 +111,6 @@ class WirelessPalette(Palette): + self._disconnect_item.connect('activate', self.__disconnect_activate_cb) + self.menu.append(self._disconnect_item) + +- if can_create: +- self._adhoc_item = gtk.MenuItem(_('Create new wireless network')) +- self._adhoc_item.connect('activate', self.__adhoc_activate_cb) +- self.menu.append(self._adhoc_item) +- self._adhoc_item.show() +- + def set_connecting(self): + self.props.secondary_text = _('Connecting...') + +@@ -151,14 +137,8 @@ class WirelessPalette(Palette): + def __disconnect_activate_cb(self, menuitem): + self.emit('deactivate-connection') + +- def __adhoc_activate_cb(self, menuitem): +- self.emit('create-connection') +- + def _set_frequency(self, frequency): +- try: +- channel = frequency_to_channel(frequency) +- except KeyError: +- channel = 0 ++ channel = network.frequency_to_channel(frequency) + self._set_channel(channel) + + def _set_channel(self, channel): +@@ -391,7 +371,6 @@ class GsmPalette(Palette): + + class WirelessDeviceView(ToolButton): + +- _ICON_NAME = 'network-wireless' + FRAME_POSITION_RELATIVE = 302 + + def __init__(self, device): +@@ -410,7 +389,7 @@ class WirelessDeviceView(ToolButton): + self._active_ap_op = None + + self._icon = PulsingIcon() +- self._icon.props.icon_name = get_icon_state(self._ICON_NAME, 0) ++ self._icon.props.icon_name = get_icon_state('network-wireless', 0) + self._inactive_color = xocolor.XoColor( \ + "%s,%s" % (style.COLOR_BUTTON_GREY.get_svg(), + style.COLOR_TRANSPARENT.get_svg())) +@@ -424,8 +403,6 @@ class WirelessDeviceView(ToolButton): + self._palette = WirelessPalette(self._name) + self._palette.connect('deactivate-connection', + self.__deactivate_connection_cb) +- self._palette.connect('create-connection', +- self.__create_connection_cb) + self.set_palette(self._palette) + self._palette.set_group_id('frame') + +@@ -495,11 +472,6 @@ class WirelessDeviceView(ToolButton): + def __ap_properties_changed_cb(self, properties): + self._update_properties(properties) + +- def _name_encodes_colors(self): +- """Match #XXXXXX,#YYYYYY at the end of the network name""" +- return self._name[-7] == '#' and self._name[-8] == ',' \ +- and self._name[-15] == '#' +- + def _update_properties(self, properties): + if 'Mode' in properties: + self._mode = properties['Mode'] +@@ -515,11 +487,9 @@ class WirelessDeviceView(ToolButton): + self._frequency = properties['Frequency'] + + if self._color == None: +- if self._mode == network.NM_802_11_MODE_ADHOC \ +- and self._name_encodes_colors(): +- encoded_color = self._name.split("#", 1) +- if len(encoded_color) == 2: +- self._color = xocolor.XoColor('#' + encoded_color[1]) ++ if self._mode == network.NM_802_11_MODE_ADHOC and \ ++ network.is_sugar_adhoc_network(self._name): ++ self._color = profile.get_color() + else: + sha_hash = hashlib.sha1() + data = self._name + hex(self._flags) +@@ -555,14 +525,24 @@ class WirelessDeviceView(ToolButton): + else: + state = network.DEVICE_STATE_UNKNOWN + +- if state == network.DEVICE_STATE_ACTIVATED: +- icon_name = '%s-connected' % self._ICON_NAME +- else: +- icon_name = self._ICON_NAME ++ if self._mode != network.NM_802_11_MODE_ADHOC and \ ++ network.is_sugar_adhoc_network(self._name) == False: ++ if state == network.DEVICE_STATE_ACTIVATED: ++ icon_name = '%s-connected' % 'network-wireless' ++ else: ++ icon_name = 'network-wireless' + +- icon_name = get_icon_state(icon_name, self._strength) +- if icon_name: +- self._icon.props.icon_name = icon_name ++ icon_name = get_icon_state(icon_name, self._strength) ++ if icon_name: ++ self._icon.props.icon_name = icon_name ++ else: ++ channel = network.frequency_to_channel(self._frequency) ++ if state == network.DEVICE_STATE_ACTIVATED: ++ self._icon.props.icon_name = 'network-adhoc-%s-connected' \ ++ % channel ++ else: ++ self._icon.props.icon_name = 'network-adhoc-%s' % channel ++ self._icon.props.base_color = profile.get_color() + + if state == network.DEVICE_STATE_PREPARE or \ + state == network.DEVICE_STATE_CONFIG or \ +@@ -601,54 +581,6 @@ class WirelessDeviceView(ToolButton): + netmgr.DeactivateConnection(conn_o) + break + +- def __create_connection_cb(self, palette, data=None): +- """Create an 802.11 IBSS network. +- +- The user's color is encoded at the end of the network name. The network +- name is truncated so that it does not exceed the 32 byte SSID limit. +- """ +- client = gconf.client_get_default() +- nick = client.get_string('/desktop/sugar/user/nick').decode('utf-8') +- color = client.get_string('/desktop/sugar/user/color') +- color_suffix = ' %s' % color +- +- format = _('%s\'s network').encode('utf-8') +- extra_length = (len(format) - len('%s')) + len(color_suffix) +- name_limit = 32 - extra_length +- +- # truncate the nick and use a regex to drop any partial characters +- # at the end +- nick = nick.encode('utf-8')[:name_limit] +- pattern = "([\xf6-\xf7][\x80-\xbf]{0,2}|[\xe0-\xef][\x80-\xbf]{0,1}|[\xc0-\xdf])$" +- nick = re.sub(pattern, '', nick) +- +- connection_name = format % nick +- connection_name += color_suffix +- +- connection = network.find_connection_by_ssid(connection_name) +- if connection is None: +- settings = Settings() +- settings.connection.id = 'Auto ' + connection_name +- uuid = settings.connection.uuid = unique_id() +- settings.connection.type = '802-11-wireless' +- settings.wireless.ssid = dbus.ByteArray(connection_name) +- settings.wireless.band = 'bg' +- settings.wireless.mode = 'adhoc' +- settings.ip4_config = IP4Config() +- settings.ip4_config.method = 'link-local' +- +- connection = network.add_connection(uuid, settings) +- +- obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) +- netmgr = dbus.Interface(obj, _NM_IFACE) +- +- netmgr.ActivateConnection(network.SETTINGS_SERVICE, +- connection.path, +- self._device.object_path, +- '/', +- reply_handler=self.__activate_reply_cb, +- error_handler=self.__activate_error_cb) +- + def __activate_reply_cb(self, connection): + logging.debug('Network created: %s', connection) + +diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py +index bc7f59b..ae63ad2 100644 +--- a/src/jarabe/desktop/meshbox.py ++++ b/src/jarabe/desktop/meshbox.py +@@ -1,6 +1,6 @@ + # Copyright (C) 2006-2007 Red Hat, Inc. + # Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer +-# Copyright (C) 2009 One Laptop per Child ++# Copyright (C) 2009-2010 One Laptop per Child + # + # 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 +@@ -25,6 +25,7 @@ import hippo + import hippo + import gobject + import gtk ++import gconf + + from sugar.graphics.icon import CanvasIcon, Icon + from sugar.graphics.xocolor import XoColor +@@ -53,6 +54,7 @@ from jarabe.model.network import IP4Config + from jarabe.model.network import WirelessSecurity + from jarabe.model.network import AccessPoint + from jarabe.model.olpcmesh import OlpcMeshManager ++from jarabe.model.adhoc import get_adhoc_manager_instance + + _NM_SERVICE = 'org.freedesktop.NetworkManager' + _NM_IFACE = 'org.freedesktop.NetworkManager' +@@ -67,6 +69,7 @@ _NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active' + _AP_ICON_NAME = 'network-wireless' + _OLPC_MESH_ICON_NAME = 'network-mesh' + ++ + class WirelessNetworkView(CanvasPulsingIcon): + def __init__(self, initial_ap): + CanvasPulsingIcon.__init__(self, size=style.STANDARD_ICON_SIZE, +@@ -90,11 +93,9 @@ class WirelessNetworkView(CanvasPulsingIcon): + self._device_state = None + self._color = None + +- if self._mode == network.NM_802_11_MODE_ADHOC \ +- and self._name_encodes_colors(): +- encoded_color = self._name.split("#", 1) +- if len(encoded_color) == 2: +- self._color = xocolor.XoColor('#' + encoded_color[1]) ++ if self._mode == network.NM_802_11_MODE_ADHOC and \ ++ network.is_sugar_adhoc_network(self._name): ++ self._color = profile.get_color() + else: + sha_hash = hashlib.sha1() + data = self._name + hex(self._flags) +@@ -147,11 +152,6 @@ class WirelessNetworkView(CanvasPulsingIcon): + path=self._device.object_path, + dbus_interface=_NM_WIRELESS_IFACE) + +- def _name_encodes_colors(self): +- """Match #XXXXXX,#YYYYYY at the end of the network name""" +- return self._name[-7] == '#' and self._name[-8] == ',' \ +- and self._name[-15] == '#' +- + def _create_palette(self): + icon_name = get_icon_state(_AP_ICON_NAME, self._strength) + self._palette_icon = Icon(icon_name=icon_name, +@@ -222,21 +222,32 @@ class WirelessNetworkView(CanvasPulsingIcon): + else: + state = network.DEVICE_STATE_UNKNOWN + +- if state == network.DEVICE_STATE_ACTIVATED: +- connection = network.find_connection_by_ssid(self._name) +- if connection: +- if self._mode == network.NM_802_11_MODE_INFRA: +- connection.set_connected() +- +- icon_name = '%s-connected' % _AP_ICON_NAME +- else: +- icon_name = _AP_ICON_NAME +- +- icon_name = get_icon_state(icon_name, self._strength) +- if icon_name: ++ if self._mode == network.NM_802_11_MODE_ADHOC and \ ++ network.is_sugar_adhoc_network(self._name): ++ channel = max([1] + [ap.channel for ap in ++ self._access_points.values()]) ++ if state == network.DEVICE_STATE_ACTIVATED: ++ icon_name = 'network-adhoc-%s-connected' % channel ++ else: ++ icon_name = 'network-adhoc-%s' % channel + self.props.icon_name = icon_name + icon = self._palette.props.icon + icon.props.icon_name = icon_name ++ else: ++ if state == network.DEVICE_STATE_ACTIVATED: ++ connection = network.find_connection_by_ssid(self._name) ++ if connection is not None: ++ if self._mode == network.NM_802_11_MODE_INFRA: ++ connection.set_connected() ++ icon_name = '%s-connected' % _AP_ICON_NAME ++ else: ++ icon_name = _AP_ICON_NAME ++ ++ icon_name = get_icon_state(icon_name, self._strength) ++ if icon_name: ++ self.props.icon_name = icon_name ++ icon = self._palette.props.icon ++ icon.props.icon_name = icon_name + + if state == network.DEVICE_STATE_PREPARE or \ + state == network.DEVICE_STATE_CONFIG or \ +@@ -259,15 +268,15 @@ class WirelessNetworkView(CanvasPulsingI + self.props.base_color = self._color + + def _update_badge(self): +- if network.find_connection_by_ssid(self._name) is not None: +- self.props.badge_name = "emblem-favorite" +- self._palette_icon.props.badge_name = "emblem-favorite" +- elif self._flags == network.NM_802_11_AP_FLAGS_PRIVACY: +- self.props.badge_name = "emblem-locked" +- self._palette_icon.props.badge_name = "emblem-locked" +- else: +- self.props.badge_name = None +- self._palette_icon.props.badge_name = None ++ self.props.badge_name = None ++ self._palette_icon.props.badge_name = None ++ if self._mode != network.NM_802_11_MODE_ADHOC: ++ if network.find_connection_by_ssid(self._name) is not None: ++ self.props.badge_name = "emblem-favorite" ++ self._palette_icon.props.badge_name = "emblem-favorite" ++ elif self._flags == network.NM_802_11_AP_FLAGS_PRIVACY: ++ self.props.badge_name = "emblem-locked" ++ self._palette_icon.props.badge_name = "emblem-locked" + + def _disconnect_activate_cb(self, item): + connection = network.find_connection_by_ssid(self._name) +@@ -444,6 +455,139 @@ class WirelessNetworkView(CanvasPulsingIcon): + path=self._device.object_path, + dbus_interface=_NM_WIRELESS_IFACE) + ++class SugarAdhocView(CanvasPulsingIcon): ++ """To mimic the mesh behavior on devices where mesh hardware is ++ not available we support the creation of an Ad-hoc network on ++ three channels 1, 6, 11. This is the class for an icon ++ representing a channel in the neighborhood view. ++ ++ """ ++ ++ _ICON_NAME = 'network-adhoc-' ++ _NAME = 'Ad-hoc Network ' ++ ++ def __init__(self, channel): ++ CanvasPulsingIcon.__init__(self, ++ icon_name=self._ICON_NAME + str(channel), ++ size=style.STANDARD_ICON_SIZE, cache=True) ++ self._bus = dbus.SystemBus() ++ self._channel = channel ++ self._disconnect_item = None ++ self._connect_item = None ++ self._palette_icon = None ++ self._greyed_out = False ++ ++ get_adhoc_manager_instance().connect('members-changed', ++ self.__members_changed_cb) ++ get_adhoc_manager_instance().connect('state-changed', ++ self.__state_changed_cb) ++ ++ self.connect('button-release-event', self.__button_release_event_cb) ++ ++ pulse_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(), ++ style.COLOR_TRANSPARENT.get_svg())) ++ self.props.pulse_color = pulse_color ++ self._state_color = XoColor('%s,%s' % \ ++ (profile.get_color().get_stroke_color(), ++ style.COLOR_TRANSPARENT.get_svg())) ++ self.props.base_color = self._state_color ++ self._palette = self._create_palette() ++ self.set_palette(self._palette) ++ self._palette_icon.props.xo_color = self._state_color ++ ++ def _create_palette(self): ++ self._palette_icon = Icon( \ ++ icon_name=self._ICON_NAME + str(self._channel), ++ icon_size=style.STANDARD_ICON_SIZE) ++ ++ palette_ = palette.Palette(_("Ad-hoc Network %d") % self._channel, ++ icon=self._palette_icon) ++ ++ self._connect_item = MenuItem(_('Connect'), 'dialog-ok') ++ self._connect_item.connect('activate', self.__connect_activate_cb) ++ palette_.menu.append(self._connect_item) ++ ++ self._disconnect_item = MenuItem(_('Disconnect'), 'media-eject') ++ self._disconnect_item.connect('activate', ++ self.__disconnect_activate_cb) ++ palette_.menu.append(self._disconnect_item) ++ ++ return palette_ ++ ++ def __button_release_event_cb(self, icon, event): ++ get_adhoc_manager_instance().activate_channel(self._channel) ++ ++ def __connect_activate_cb(self, icon): ++ get_adhoc_manager_instance().activate_channel(self._channel) ++ ++ def __disconnect_activate_cb(self, icon): ++ get_adhoc_manager_instance().deactivate_active_channel() ++ ++ def __state_changed_cb(self, adhoc_manager, channel, device_state): ++ if self._channel == channel: ++ state = device_state ++ else: ++ state = network.DEVICE_STATE_UNKNOWN ++ ++ if state == network.DEVICE_STATE_ACTIVATED: ++ icon_name = '%s-connected' % (self._ICON_NAME + str(self._channel)) ++ else: ++ icon_name = self._ICON_NAME + str(self._channel) ++ ++ self.props.base_color = self._state_color ++ self._palette_icon.props.xo_color = self._state_color ++ ++ if icon_name is not None: ++ self.props.icon_name = icon_name ++ icon = self._palette.props.icon ++ icon.props.icon_name = icon_name ++ ++ if state in [network.DEVICE_STATE_PREPARE, ++ network.DEVICE_STATE_CONFIG, ++ network.DEVICE_STATE_NEED_AUTH, ++ network.DEVICE_STATE_IP_CONFIG]: ++ if self._disconnect_item: ++ self._disconnect_item.show() ++ self._connect_item.hide() ++ self._palette.props.secondary_text = _('Connecting...') ++ self.props.pulsing = True ++ elif state == network.DEVICE_STATE_ACTIVATED: ++ if self._disconnect_item: ++ self._disconnect_item.show() ++ self._connect_item.hide() ++ self._palette.props.secondary_text = _('Connected') ++ self.props.pulsing = False ++ else: ++ if self._disconnect_item: ++ self._disconnect_item.hide() ++ self._connect_item.show() ++ self._palette.props.secondary_text = None ++ self.props.pulsing = False ++ ++ def _update_color(self): ++ if self._greyed_out: ++ self.props.base_color = XoColor('#D5D5D5,#D5D5D5') ++ else: ++ self.props.base_color = self._state_color ++ ++ def __members_changed_cb(self, adhoc_manager, channel, has_members): ++ if channel == self._channel: ++ if has_members == True: ++ self._state_color = profile.get_color() ++ self.props.base_color = self._state_color ++ self._palette_icon.props.xo_color = self._state_color ++ else: ++ color = '%s,%s' % (profile.get_color().get_stroke_color(), ++ style.COLOR_TRANSPARENT.get_svg()) ++ self._state_color = XoColor(color) ++ self.props.base_color = self._state_color ++ self._palette_icon.props.xo_color = self._state_color ++ ++ def set_filter(self, query): ++ name = self._NAME + str(self._channel) ++ self._greyed_out = name.lower().find(query) == -1 ++ self._update_color() ++ + + class OlpcMeshView(CanvasPulsingIcon): + def __init__(self, mesh_mgr, channel): +@@ -765,13 +909,19 @@ class MeshToolbar(gtk.Toolbar): + return False + + +-class DeviceObserver(object): +- def __init__(self, box, device): +- self._box = box ++class DeviceObserver(gobject.GObject): ++ __gsignals__ = { ++ 'access-point-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ++ ([gobject.TYPE_PYOBJECT])), ++ 'access-point-removed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ++ ([gobject.TYPE_PYOBJECT])) ++ } ++ def __init__(self, device): ++ gobject.GObject.__init__(self) + self._bus = dbus.SystemBus() +- self._device = device ++ self.device = device + +- wireless = dbus.Interface(self._device, _NM_WIRELESS_IFACE) ++ wireless = dbus.Interface(device, _NM_WIRELESS_IFACE) + wireless.GetAccessPoints(reply_handler=self._get_access_points_reply_cb, + error_handler=self._get_access_points_error_cb) + +@@ -787,30 +937,33 @@ class DeviceObserver(object): + def _get_access_points_reply_cb(self, access_points_o): + for ap_o in access_points_o: + ap = self._bus.get_object(_NM_SERVICE, ap_o) +- self._box.add_access_point(self._device, ap) ++ self.emit('access-point-added', ap) + + def _get_access_points_error_cb(self, err): + logging.error('Failed to get access points: %s', err) + + def __access_point_added_cb(self, access_point_o): + ap = self._bus.get_object(_NM_SERVICE, access_point_o) +- self._box.add_access_point(self._device, ap) ++ self.emit('access-point-added', ap) + + def __access_point_removed_cb(self, access_point_o): +- self._box.remove_access_point(access_point_o) ++ self.emit('access-point-removed', access_point_o) + + def disconnect(self): + self._bus.remove_signal_receiver(self.__access_point_added_cb, + signal_name='AccessPointAdded', +- path=self._device.object_path, ++ path=self.device.object_path, + dbus_interface=_NM_WIRELESS_IFACE) + self._bus.remove_signal_receiver(self.__access_point_removed_cb, + signal_name='AccessPointRemoved', +- path=self._device.object_path, ++ path=self.device.object_path, + dbus_interface=_NM_WIRELESS_IFACE) + + + class NetworkManagerObserver(object): ++ ++ _SHOW_ADHOC_GCONF_KEY = '/desktop/sugar/network/adhoc' ++ + def __init__(self, box): + self._box = box + self._bus = None +@@ -818,6 +971,9 @@ class NetworkManagerObserver(object): + self._netmgr = None + self._olpc_mesh_device_o = None + ++ client = gconf.client_get_default() ++ self._have_adhoc_networks = client.get_bool(self._SHOW_ADHOC_GCONF_KEY) ++ + def listen(self): + try: + self._bus = dbus.SystemBus() +@@ -836,6 +992,9 @@ class NetworkManagerObserver(object): + self._bus.add_signal_receiver(self.__device_removed_cb, + signal_name='DeviceRemoved', + dbus_interface=_NM_IFACE) ++ self._bus.add_signal_receiver(self.__properties_changed_cb, ++ signal_name='PropertiesChanged', ++ dbus_interface=_NM_IFACE) + + settings = network.get_settings() + if settings is not None: +@@ -879,7 +1038,13 @@ class NetworkManagerObserver(object): + + device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType') + if device_type == network.DEVICE_TYPE_802_11_WIRELESS: +- self._devices[device_o] = DeviceObserver(self._box, device) ++ self._devices[device_o] = DeviceObserver(device) ++ self._devices[device_o].connect('access-point-added', ++ self.__ap_added_cb) ++ self._devices[device_o].connect('access-point-removed', ++ self.__ap_removed_cb) ++ if self._have_adhoc_networks: ++ self._box.add_adhoc_networks(device) + elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH: + self._olpc_mesh_device_o = device_o + self._box.enable_olpc_mesh(device) +@@ -895,11 +1060,30 @@ class NetworkManagerObserver(object): + observer = self._devices[device_o] + observer.disconnect() + del self._devices[device_o] ++ if self._have_adhoc_networks: ++ self._box.remove_adhoc_networks() + return + + if self._olpc_mesh_device_o == device_o: + self._box.disable_olpc_mesh(device_o) + ++ def __ap_added_cb(self, device_observer, access_point): ++ self._box.add_access_point(device_observer.device, access_point) ++ ++ def __ap_removed_cb(self, device_observer, access_point_o): ++ self._box.remove_access_point(access_point_o) ++ ++ def __properties_changed_cb(self, properties): ++ if 'WirelessHardwareEnabled' in properties: ++ if properties['WirelessHardwareEnabled']: ++ if not self._have_adhoc_networks: ++ self._box.remove_adhoc_networks() ++ elif properties['WirelessHardwareEnabled']: ++ for device in self._devices: ++ if self._have_adhoc_networks: ++ self._box.add_adhoc_networks(device) ++ ++ + class MeshBox(gtk.VBox): + __gtype_name__ = 'SugarMeshBox' + +@@ -909,6 +1093,8 @@ class MeshBox(gtk.VBox): + gobject.GObject.__init__(self) + + self.wireless_networks = {} ++ self._adhoc_manager = None ++ self._adhoc_networks = [] + + self._model = neighborhood.get_model() + self._buddies = {} +@@ -1066,6 +1252,15 @@ class MeshBox(gtk.VBox): + ap.disconnect() + return + ++ if self._adhoc_manager is not None and \ ++ network.is_sugar_adhoc_network(ap.name) and \ ++ ap.mode == network.NM_802_11_MODE_ADHOC: ++ if old_hash is None: # new Ad-hoc network finished initializing ++ self._adhoc_manager.add_access_point(ap) ++ # we are called as well in other cases but we do not need to ++ # act here as we don't display signal strength for Ad-hoc networks ++ return ++ + if old_hash is None: # new AP finished initializing + self._add_ap_to_network(ap) + return +@@ -1088,6 +1283,11 @@ class MeshBox(gtk.VBox): + ap.initialize() + + def remove_access_point(self, ap_o): ++ if self._adhoc_manager is not None: ++ if self._adhoc_manager.is_sugar_adhoc_access_point(ap_o): ++ self._adhoc_manager.remove_access_point(ap_o) ++ return ++ + # we don't keep an index of ap object path to network, but since + # we'll only ever have a handful of networks, just try them all... + for net in self.wireless_networks.values(): +@@ -1104,6 +1304,26 @@ class MeshBox(gtk.VBox): + # it (e.g. olpc-mesh adhoc network) + logging.debug('Can not remove access point %s' % ap_o) + ++ def add_adhoc_networks(self, device): ++ if self._adhoc_manager is None: ++ self._adhoc_manager = get_adhoc_manager_instance() ++ self._adhoc_manager.start_listening(device) ++ self._add_adhoc_network_icon(1) ++ self._add_adhoc_network_icon(6) ++ self._add_adhoc_network_icon(11) ++ self._adhoc_manager.autoconnect() ++ ++ def remove_adhoc_networks(self): ++ for icon in self._adhoc_networks: ++ icon.disconnect() ++ self._layout.remove(icon) ++ self._adhoc_networks = [] ++ ++ def _add_adhoc_network_icon(self, channel): ++ icon = SugarAdhocView(channel) ++ self._layout.add(icon) ++ self._adhoc_networks.append(icon) ++ + def _add_olpc_mesh_icon(self, mesh_mgr, channel): + icon = OlpcMeshView(mesh_mgr, channel) + self._layout.add(icon) +diff --git a/src/jarabe/model/Makefile.am b/src/jarabe/model/Makefile.am +index e9f0700..4650c3b 100644 +--- a/src/jarabe/model/Makefile.am ++++ b/src/jarabe/model/Makefile.am +@@ -1,5 +1,6 @@ + sugardir = $(pythondir)/jarabe/model + sugar_PYTHON = \ ++ adhoc.py \ + __init__.py \ + buddy.py \ + bundleregistry.py \ +diff --git a/src/jarabe/model/adhoc.py b/src/jarabe/model/adhoc.py +new file mode 100644 +index 0000000..65dac01 +--- /dev/null ++++ b/src/jarabe/model/adhoc.py +@@ -0,0 +1,299 @@ ++# Copyright (C) 2010 One Laptop per Child ++# ++# 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 ++ ++import dbus ++import gobject ++ ++from jarabe.model import network ++from jarabe.model.network import Settings ++from sugar.util import unique_id ++from jarabe.model.network import IP4Config ++ ++_NM_SERVICE = 'org.freedesktop.NetworkManager' ++_NM_IFACE = 'org.freedesktop.NetworkManager' ++_NM_PATH = '/org/freedesktop/NetworkManager' ++_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device' ++_NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless' ++_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint' ++_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active' ++ ++ ++_adhoc_manager_instance = None ++def get_adhoc_manager_instance(): ++ global _adhoc_manager_instance ++ if _adhoc_manager_instance is None: ++ _adhoc_manager_instance = AdHocManager() ++ return _adhoc_manager_instance ++ ++ ++class AdHocManager(gobject.GObject): ++ """To mimic the mesh behavior on devices where mesh hardware is ++ not available we support the creation of an Ad-hoc network on ++ three channels 1, 6, 11. If Sugar sees no "known" network when it ++ starts, it does autoconnect to an Ad-hoc network. ++ ++ """ ++ ++ __gsignals__ = { ++ 'members-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ++ ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])), ++ 'state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ++ ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])) ++ } ++ ++ _AUTOCONNECT_TIMEOUT = 30 ++ _CHANNEL_1 = 1 ++ _CHANNEL_6 = 6 ++ _CHANNEL_11 = 11 ++ ++ def __init__(self): ++ gobject.GObject.__init__(self) ++ ++ self._bus = dbus.SystemBus() ++ self._device = None ++ self._idle_source = 0 ++ self._listening_called = 0 ++ self._device_state = network.DEVICE_STATE_UNKNOWN ++ ++ self._current_channel = None ++ self._networks = {self._CHANNEL_1: None, ++ self._CHANNEL_6: None, ++ self._CHANNEL_11: None} ++ ++ def start_listening(self, device): ++ self._listening_called += 1 ++ if self._listening_called > 1: ++ raise RuntimeError('The start listening method can' \ ++ ' only be called once.') ++ ++ self._device = device ++ props = dbus.Interface(device, ++ 'org.freedesktop.DBus.Properties') ++ props.Get(_NM_DEVICE_IFACE, 'State', ++ reply_handler=self.__get_device_state_reply_cb, ++ error_handler=self.__get_state_error_cb) ++ ++ self._bus.add_signal_receiver(self.__device_state_changed_cb, ++ signal_name='StateChanged', ++ path=self._device.object_path, ++ dbus_interface=_NM_DEVICE_IFACE) ++ ++ self._bus.add_signal_receiver(self.__wireless_properties_changed_cb, ++ signal_name='PropertiesChanged', ++ path=self._device.object_path, ++ dbus_interface=_NM_WIRELESS_IFACE) ++ ++ def stop_listening(self): ++ self._bus.remove_signal_receiver(self.__device_state_changed_cb, ++ signal_name='StateChanged', ++ path=self._device.object_path, ++ dbus_interface=_NM_DEVICE_IFACE) ++ self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb, ++ signal_name='PropertiesChanged', ++ path=self._device.object_path, ++ dbus_interface=_NM_WIRELESS_IFACE) ++ ++ def __get_state_error_cb(self, err): ++ logging.debug('Error getting the device state: %s', err) ++ ++ def __get_device_state_reply_cb(self, state): ++ self._device_state = state ++ ++ def __device_state_changed_cb(self, new_state, old_state, reason): ++ self._device_state = new_state ++ self._update_state() ++ ++ def __wireless_properties_changed_cb(self, properties): ++ if 'ActiveAccessPoint' in properties and \ ++ properties['ActiveAccessPoint'] != '/': ++ active_ap = self._bus.get_object(_NM_SERVICE, ++ properties['ActiveAccessPoint']) ++ props = dbus.Interface(active_ap, dbus.PROPERTIES_IFACE) ++ props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True, ++ reply_handler=self.__get_all_ap_props_reply_cb, ++ error_handler=self.__get_all_ap_props_error_cb) ++ ++ def __get_all_ap_props_reply_cb(self, properties): ++ if properties['Mode'] == network.NM_802_11_MODE_ADHOC and \ ++ 'Frequency' in properties: ++ frequency = properties['Frequency'] ++ self._current_channel = network.frequency_to_channel(frequency) ++ else: ++ self._current_channel = None ++ self._update_state() ++ ++ def __get_all_ap_props_error_cb(self, err): ++ logging.error('Error getting the access point properties: %s', err) ++ ++ def _update_state(self): ++ self.emit('state-changed', self._current_channel, self._device_state) ++ ++ def _have_configured_connections(self): ++ return len(network.get_settings().connections) > 0 ++ ++ def autoconnect(self): ++ """Autoconnect to an Ad-hoc network""" ++ if self._have_configured_connections(): ++ self._autoconnect_adhoc_timer() ++ else: ++ self._autoconnect_adhoc() ++ ++ def _autoconnect_adhoc_timer(self): ++ """Start a timer which basically looks for 30 seconds of inactivity ++ on the device, then does autoconnect to an Ad-hoc network. ++ ++ """ ++ if self._idle_source != 0: ++ gobject.source_remove(self._idle_source) ++ self._idle_source = gobject.timeout_add_seconds( \ ++ self._AUTOCONNECT_TIMEOUT, self.__idle_check_cb) ++ ++ def __idle_check_cb(self): ++ if self._device_state == network.DEVICE_STATE_DISCONNECTED: ++ logging.debug("Connect to Ad-hoc network due to inactivity.") ++ self._autoconnect_adhoc() ++ return False ++ ++ def _autoconnect_adhoc(self): ++ """First we try if there is an Ad-hoc network that is used by other ++ learners in the area, if not we default to channel 1. ++ ++ """ ++ if self._networks[self._CHANNEL_1] is not None: ++ self._connect(self._CHANNEL_1) ++ elif self._networks[self._CHANNEL_6] is not None: ++ self._connect(self._CHANNEL_6) ++ elif self._networks[self._CHANNEL_11] is not None: ++ self._connect(self._CHANNEL_11) ++ else: ++ self._connect(self._CHANNEL_1) ++ ++ def activate_channel(self, channel): ++ """Activate a sugar Ad-hoc network. ++ ++ Keyword arguments: ++ channel -- Channel to connect to (should be 1, 6, 11) ++ ++ """ ++ self._connect(channel) ++ ++ def _connect(self, channel): ++ name = "Ad-hoc Network %d" % channel ++ connection = network.find_connection_by_ssid(name) ++ if connection is None: ++ settings = Settings() ++ settings.connection.id = name ++ settings.connection.uuid = unique_id() ++ settings.connection.type = '802-11-wireless' ++ settings.wireless.ssid = dbus.ByteArray(name) ++ settings.wireless.band = 'bg' ++ settings.wireless.channel = channel ++ settings.wireless.mode = 'adhoc' ++ settings.ip4_config = IP4Config() ++ settings.ip4_config.method = 'link-local' ++ ++ connection = network.add_connection(name, settings) ++ ++ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) ++ netmgr = dbus.Interface(obj, _NM_IFACE) ++ ++ netmgr.ActivateConnection(network.SETTINGS_SERVICE, ++ connection.path, ++ self._device.object_path, ++ '/', ++ reply_handler=self.__activate_reply_cb, ++ error_handler=self.__activate_error_cb) ++ ++ def deactivate_active_channel(self): ++ """Deactivate the current active channel.""" ++ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) ++ netmgr = dbus.Interface(obj, _NM_IFACE) ++ ++ netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE) ++ netmgr_props.Get(_NM_IFACE, 'ActiveConnections', \ ++ reply_handler=self.__get_active_connections_reply_cb, ++ error_handler=self.__get_active_connections_error_cb) ++ ++ def __get_active_connections_reply_cb(self, active_connections_o): ++ for connection_o in active_connections_o: ++ obj = self._bus.get_object(_NM_IFACE, connection_o) ++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) ++ state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State') ++ if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATED: ++ access_point_o = props.Get(_NM_ACTIVE_CONN_IFACE, ++ 'SpecificObject') ++ if access_point_o != '/': ++ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) ++ netmgr = dbus.Interface(obj, _NM_IFACE) ++ netmgr.DeactivateConnection(connection_o) ++ ++ def __get_active_connections_error_cb(self, err): ++ logging.error('Error getting the active connections: %s', err) ++ ++ def __activate_reply_cb(self, connection): ++ logging.debug('Ad-hoc network created: %s', connection) ++ ++ def __activate_error_cb(self, err): ++ logging.error('Failed to create Ad-hoc network: %s', err) ++ ++ def add_access_point(self, access_point): ++ """Add an access point to a network and notify the view to idicate ++ the member change. ++ ++ Keyword arguments: ++ access_point -- Access Point ++ ++ """ ++ if access_point.name.endswith(' 1'): ++ self._networks[self._CHANNEL_1] = access_point ++ self.emit('members-changed', self._CHANNEL_1, True) ++ elif access_point.name.endswith(' 6'): ++ self._networks[self._CHANNEL_6] = access_point ++ self.emit('members-changed', self._CHANNEL_6, True) ++ elif access_point.name.endswith('11'): ++ self._networks[self._CHANNEL_11] = access_point ++ self.emit('members-changed', self._CHANNEL_11, True) ++ ++ def is_sugar_adhoc_access_point(self, ap_object_path): ++ """Checks whether an access point is part of a sugar Ad-hoc network. ++ ++ Keyword arguments: ++ ap_object_path -- Access Point object path ++ ++ Return: Boolean ++ ++ """ ++ for access_point in self._networks.values(): ++ if access_point is not None: ++ if access_point.model.object_path == ap_object_path: ++ return True ++ return False ++ ++ def remove_access_point(self, ap_object_path): ++ """Remove an access point from a sugar Ad-hoc network. ++ ++ Keyword arguments: ++ ap_object_path -- Access Point object path ++ ++ """ ++ for channel in self._networks: ++ if self._networks[channel] is not None: ++ if self._networks[channel].model.object_path == ap_object_path: ++ self.emit('members-changed', channel, False) ++ self._networks[channel] = None ++ break +diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py +index 47db43f..984da67 100644 +--- a/src/jarabe/model/network.py ++++ b/src/jarabe/model/network.py +@@ -1,6 +1,6 @@ + # Copyright (C) 2008 Red Hat, Inc. + # Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer +-# Copyright (C) 2009 One Laptop per Child ++# Copyright (C) 2009-2010 One Laptop per Child + # Copyright (C) 2009 Paraguay Educa, Martin Abente + # Copyright (C) 2010 Plan Ceibal, Daniel Castelo + # +@@ -100,6 +100,39 @@ GSM_PUK_PATH = '/desktop/sugar/network/gsm/puk' + _nm_settings = None + _conn_counter = 0 + ++ ++def frequency_to_channel(frequency): ++ """Returns the channel matching a given radio channel frequency. If a ++ frequency is not in the dictionary channel 1 will be returned. ++ ++ Keyword arguments: ++ frequency -- The radio channel frequency in MHz. ++ ++ Return: Channel ++ ++ """ ++ ftoc = {2412: 1, 2417: 2, 2422: 3, 2427: 4, ++ 2432: 5, 2437: 6, 2442: 7, 2447: 8, ++ 2452: 9, 2457: 10, 2462: 11, 2467: 12, ++ 2472: 13} ++ if frequency not in ftoc: ++ logging.warning("The frequency %s can not be mapped to a channel, " \ ++ "defaulting to channel 1.", frequncy) ++ return 1 ++ return ftoc[frequency] ++ ++def is_sugar_adhoc_network(ssid): ++ """Checks whether an access point is a sugar Ad-hoc network. ++ ++ Keyword arguments: ++ ssid -- Ssid of the access point. ++ ++ Return: Boolean ++ ++ """ ++ return ssid.startswith('Ad-hoc Network') ++ ++ + class WirelessSecurity(object): + def __init__(self): + self.key_mgmt = None +@@ -127,6 +160,7 @@ class Wireless(object): + self.security = None + self.mode = None + self.band = None ++ self.channel = None + + def get_dict(self): + wireless = {'ssid': self.ssid} +@@ -136,6 +170,8 @@ class Wireless(object): + wireless['mode'] = self.mode + if self.band: + wireless['band'] = self.band ++ if self.channel: ++ wireless['channel'] = self.channel + return wireless + + +@@ -476,6 +512,7 @@ class AccessPoint(gobject.GObject): + self.wpa_flags = 0 + self.rsn_flags = 0 + self.mode = 0 ++ self.channel = 0 + + def initialize(self): + model_props = dbus.Interface(self.model, dbus.PROPERTIES_IFACE) +@@ -545,6 +582,9 @@ class AccessPoint(gobject.GObject): + self.rsn_flags = properties['RsnFlags'] + if 'Mode' in properties: + self.mode = properties['Mode'] ++ if 'Frequency' in properties: ++ self.channel = frequency_to_channel(properties['Frequency']) ++ + self._initialized = True + self.emit('props-changed', old_hash) + +-- +1.7.2.2 + diff --git a/rpms/sugar/sl1673-fix-network-disconnect-and-discard-history-v2.patch b/rpms/sugar/sl1673-fix-network-disconnect-and-discard-history-v2.patch new file mode 100644 index 0000000..1f06ce9 --- /dev/null +++ b/rpms/sugar/sl1673-fix-network-disconnect-and-discard-history-v2.patch @@ -0,0 +1,507 @@ +From 7ae1a9903237c0d26bebbf699084eb258a533173 Mon Sep 17 00:00:00 2001 +From: James Cameron <quozl@laptop.org> +Date: Tue, 25 May 2010 17:27:44 +1000 +Subject: [PATCH] fix network disconnect and discard history + +User interface changes: + +- enable the disconnect button on the access point menu in the + neighbourhood view, (rather than the button doing nothing), + +- fix the disconnect button on the wireless device icon in the frame + so that the disconnection remains effective, (rather than + disconnecting and then reconnecting automatically), + +- enable the discard network history button in the network control + panel, which also now forces a disconnect, and will be insensitive + if there are no networks to be discarded, (rather than the button + doing nothing), + +- enforce consistency between the neighbourhood view, the frame, and + the control panel, with respect to how the access point is shown. + +References: + + http://dev.laptop.org/ticket/9977 (fixes a workaround) + http://bugs.sugarlabs.org/ticket/1673 + http://bugs.sugarlabs.org/ticket/1802 + http://bugs.sugarlabs.org/ticket/1737 + http://bugs.sugarlabs.org/ticket/1736 + http://bugs.sugarlabs.org/ticket/1608 + http://dev.laptop.org/ticket/9788 +--- + extensions/cpsection/network/model.py | 12 ++++-- + extensions/cpsection/network/view.py | 8 ++++- + extensions/deviceicon/network.py | 37 ++++++++++--------- + src/jarabe/desktop/meshbox.py | 61 +++++++++++++++++++++---------- + src/jarabe/model/network.py | 62 ++++++++++++++++++++++++++------ + 5 files changed, 125 insertions(+), 55 deletions(-) + +diff --git a/extensions/cpsection/network/model.py b/extensions/cpsection/network/model.py +index e1c3dab..2bc5e3a 100644 +--- a/extensions/cpsection/network/model.py ++++ b/extensions/cpsection/network/model.py +@@ -17,6 +17,7 @@ + + import dbus + from gettext import gettext as _ ++from jarabe.model import network + import gconf + + _NM_SERVICE = 'org.freedesktop.NetworkManager' +@@ -68,7 +69,7 @@ def get_radio(): + try: + bus = dbus.SystemBus() + obj = bus.get_object(_NM_SERVICE, _NM_PATH) +- nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') ++ nm_props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) + except dbus.DBusException: + raise ReadError('%s service not available' % _NM_SERVICE) + +@@ -89,7 +90,7 @@ def set_radio(state): + try: + bus = dbus.SystemBus() + obj = bus.get_object(_NM_SERVICE, _NM_PATH) +- nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') ++ nm_props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) + except dbus.DBusException: + raise ReadError('%s service not available' % _NM_SERVICE) + nm_props.Set(_NM_IFACE, 'WirelessEnabled', True) +@@ -97,7 +98,7 @@ def set_radio(state): + try: + bus = dbus.SystemBus() + obj = bus.get_object(_NM_SERVICE, _NM_PATH) +- nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') ++ nm_props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) + except dbus.DBusException: + raise ReadError('%s service not available' % _NM_SERVICE) + nm_props.Set(_NM_IFACE, 'WirelessEnabled', False) +@@ -116,7 +117,10 @@ def clear_registration(): + def clear_networks(): + """Clear saved passwords and network configurations. + """ +- pass ++ network.clear_wifi_connections() ++ ++def count_networks(): ++ return network.count_wifi_connections() + + def get_publish_information(): + client = gconf.client_get_default() +diff --git a/extensions/cpsection/network/view.py b/extensions/cpsection/network/view.py +index 588daeb..b0f1336 100644 +--- a/extensions/cpsection/network/view.py ++++ b/extensions/cpsection/network/view.py +@@ -104,6 +104,8 @@ class Network(SectionView): + self._clear_history_button = gtk.Button() + self._clear_history_button.set_label(_('Discard network history')) + box_clear_history.pack_start(self._clear_history_button, expand=False) ++ if self._model.count_networks() == 0: ++ self._clear_history_button.set_sensitive(False) + self._clear_history_button.show() + box_wireless.pack_start(box_clear_history, expand=False) + box_clear_history.show() +@@ -217,7 +219,9 @@ class Network(SectionView): + self._radio_alert.props.msg = detail + self._radio_valid = False + else: +- self._radio_valid = True ++ self._radio_valid = True ++ if self._model.count_networks() != 0: ++ self._clear_history_button.set_sensitive(True) + + self._validate() + return False +@@ -248,3 +252,5 @@ class Network(SectionView): + + def __network_configuration_reset_cb(self, widget): + self._model.clear_networks() ++ if self._model.count_networks() == 0: ++ self._clear_history_button.set_sensitive(False) +diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py +index 94a4293..a828497 100644 +--- a/extensions/deviceicon/network.py ++++ b/extensions/deviceicon/network.py +@@ -352,8 +352,7 @@ class WirelessDeviceView(ToolButton): + self.set_palette(self._palette) + self._palette.set_group_id('frame') + +- self._device_props = dbus.Interface(self._device, +- 'org.freedesktop.DBus.Properties') ++ self._device_props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE) + self._device_props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True, + reply_handler=self.__get_device_props_reply_cb, + error_handler=self.__get_device_props_error_cb) +@@ -394,7 +393,7 @@ class WirelessDeviceView(ToolButton): + return + self._active_ap_op = active_ap_op + active_ap = self._bus.get_object(_NM_SERVICE, active_ap_op) +- props = dbus.Interface(active_ap, 'org.freedesktop.DBus.Properties') ++ props = dbus.Interface(active_ap, dbus.PROPERTIES_IFACE) + + props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True, + reply_handler=self.__get_all_ap_props_reply_cb, +@@ -508,17 +507,21 @@ class WirelessDeviceView(ToolButton): + self._icon.props.base_color = self._color + + def __deactivate_connection_cb(self, palette, data=None): ++ connection = network.find_connection_by_ssid(self._name) ++ if connection: ++ if self._mode == network.NM_802_11_MODE_INFRA: ++ connection.set_disconnected() ++ + if self._active_ap_op is not None: + obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) + netmgr = dbus.Interface(obj, _NM_IFACE) +- netmgr_props = dbus.Interface( +- netmgr, 'org.freedesktop.DBus.Properties') ++ netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE) + active_connections_o = netmgr_props.Get(_NM_IFACE, + 'ActiveConnections') + + for conn_o in active_connections_o: + obj = self._bus.get_object(_NM_IFACE, conn_o) +- props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') ++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) + ap_op = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject') + if ap_op == self._active_ap_op: + netmgr.DeactivateConnection(conn_o) +@@ -608,8 +611,7 @@ class OlpcMeshDeviceView(ToolButton): + self.set_palette(self._palette) + self._palette.set_group_id('frame') + +- self._device_props = dbus.Interface(self._device, +- 'org.freedesktop.DBus.Properties') ++ self._device_props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE) + self._device_props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True, + reply_handler=self.__get_device_props_reply_cb, + error_handler=self.__get_device_props_error_cb) +@@ -681,19 +683,19 @@ class OlpcMeshDeviceView(ToolButton): + def __deactivate_connection(self, palette, data=None): + obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) + netmgr = dbus.Interface(obj, _NM_IFACE) +- netmgr_props = dbus.Interface(netmgr, 'org.freedesktop.DBus.Properties') ++ netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE) + active_connections_o = netmgr_props.Get(_NM_IFACE, + 'ActiveConnections') + + for conn_o in active_connections_o: + # The connection path for a mesh connection is the device itself. + obj = self._bus.get_object(_NM_IFACE, conn_o) +- props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') ++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) + ap_op = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject') + + try: + obj = self._bus.get_object(_NM_IFACE, ap_op) +- props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') ++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) + type = props.Get(_NM_DEVICE_IFACE, 'DeviceType') + if type == network.DEVICE_TYPE_802_11_OLPC_MESH: + netmgr.DeactivateConnection(conn_o) +@@ -756,7 +758,7 @@ class GsmDeviceView(TrayIcon): + + self._palette = palette + +- props = dbus.Interface(self._device, 'org.freedesktop.DBus.Properties') ++ props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE) + props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True, + reply_handler=self.__current_state_check_cb, + error_handler=self.__current_state_check_error_cb) +@@ -785,12 +787,12 @@ class GsmDeviceView(TrayIcon): + def __gsm_disconnect_cb(self, palette, data=None): + obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) + netmgr = dbus.Interface(obj, _NM_IFACE) +- netmgr_props = dbus.Interface(netmgr, 'org.freedesktop.DBus.Properties') ++ netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE) + active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections') + + for conn_o in active_connections_o: + obj = self._bus.get_object(_NM_IFACE, conn_o) +- props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') ++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) + devices = props.Get(_NM_ACTIVE_CONN_IFACE, 'Devices') + if self._device.object_path in devices: + netmgr.DeactivateConnection( +@@ -910,7 +912,7 @@ class WiredDeviceObserver(object): + self._device_view = None + self._tray = tray + +- props = dbus.Interface(self._device, 'org.freedesktop.DBus.Properties') ++ props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE) + props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True, + reply_handler=self.__get_device_props_reply_cb, + error_handler=self.__get_device_props_error_cb) +@@ -938,8 +940,7 @@ class WiredDeviceObserver(object): + + def _update_state(self, state): + if state == network.DEVICE_STATE_ACTIVATED: +- props = dbus.Interface(self._device, +- 'org.freedesktop.DBus.Properties') ++ props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE) + address = props.Get(_NM_DEVICE_IFACE, 'Ip4Address') + speed = props.Get(_NM_WIRED_IFACE, 'Speed') + self._device_view = WiredDeviceView(speed, address) +@@ -997,7 +998,7 @@ class NetworkManagerObserver(object): + + def _check_device(self, device_op): + nm_device = self._bus.get_object(_NM_SERVICE, device_op) +- props = dbus.Interface(nm_device, 'org.freedesktop.DBus.Properties') ++ props = dbus.Interface(nm_device, dbus.PROPERTIES_IFACE) + + device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType') + if device_type == network.DEVICE_TYPE_802_3_ETHERNET: +diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py +index a04922b..280adb9 100644 +--- a/src/jarabe/desktop/meshbox.py ++++ b/src/jarabe/desktop/meshbox.py +@@ -86,7 +86,6 @@ class WirelessNetworkView(CanvasPulsingIcon): + self._rsn_flags = initial_ap.rsn_flags + self._device_caps = 0 + self._device_state = None +- self._connection = None + self._color = None + + if self._mode == network.NM_802_11_MODE_ADHOC \ +@@ -115,18 +114,9 @@ class WirelessNetworkView(CanvasPulsingIcon): + self.set_palette(self._palette) + self._palette_icon.props.xo_color = self._color + +- if network.find_connection_by_ssid(self._name) is not None: +- self.props.badge_name = "emblem-favorite" +- self._palette_icon.props.badge_name = "emblem-favorite" +- elif initial_ap.flags == network.NM_802_11_AP_FLAGS_PRIVACY: +- self.props.badge_name = "emblem-locked" +- self._palette_icon.props.badge_name = "emblem-locked" +- else: +- self.props.badge_name = None +- self._palette_icon.props.badge_name = None ++ self._update_badge() + +- interface_props = dbus.Interface(self._device, +- 'org.freedesktop.DBus.Properties') ++ interface_props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE) + interface_props.Get(_NM_DEVICE_IFACE, 'State', + reply_handler=self.__get_device_state_reply_cb, + error_handler=self.__get_device_state_error_cb) +@@ -174,6 +164,7 @@ class WirelessNetworkView(CanvasPulsingIcon): + def __device_state_changed_cb(self, new_state, old_state, reason): + self._device_state = new_state + self._update_state() ++ self._update_badge() + + def __update_active_ap(self, ap_path): + if ap_path in self._access_points: +@@ -214,6 +205,7 @@ class WirelessNetworkView(CanvasPulsingIcon): + def _update(self): + self._update_state() + self._update_color() ++ self._update_badge() + + def _update_state(self): + if self._active_ap is not None: +@@ -266,8 +258,40 @@ class WirelessNetworkView(CanvasPulsingIcon): + else: + self.props.base_color = self._color + ++ def _update_badge(self): ++ if network.find_connection_by_ssid(self._name) is not None: ++ self.props.badge_name = "emblem-favorite" ++ self._palette_icon.props.badge_name = "emblem-favorite" ++ elif self._flags == network.NM_802_11_AP_FLAGS_PRIVACY: ++ self.props.badge_name = "emblem-locked" ++ self._palette_icon.props.badge_name = "emblem-locked" ++ else: ++ self.props.badge_name = None ++ self._palette_icon.props.badge_name = None ++ + def _disconnect_activate_cb(self, item): +- pass ++ connection = network.find_connection_by_ssid(self._name) ++ if connection: ++ if self._mode == network.NM_802_11_MODE_INFRA: ++ connection.set_disconnected() ++ ++ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) ++ netmgr = dbus.Interface(obj, _NM_IFACE) ++ ++ netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE) ++ active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections') ++ ++ for conn_o in active_connections_o: ++ obj = self._bus.get_object(_NM_IFACE, conn_o) ++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) ++ state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State') ++ if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATED: ++ ap_o = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject') ++ if ap_o != '/' and self.find_ap(ap_o) is not None: ++ netmgr.DeactivateConnection(conn_o) ++ else: ++ logging.error('Could not determine AP for' ++ ' specific object %s' % conn_o) + + def _add_ciphers_from_flags(self, flags, pairwise): + ciphers = [] +@@ -456,14 +480,12 @@ class OlpcMeshView(CanvasPulsingIcon): + self._greyed_out = False + self._name = '' + self._device_state = None +- self._connection = None + self._active = False + device = mesh_mgr.mesh_device + + self.connect('button-release-event', self.__button_release_event_cb) + +- interface_props = dbus.Interface(device, +- 'org.freedesktop.DBus.Properties') ++ interface_props = dbus.Interface(device, dbus.PROPERTIES_IFACE) + interface_props.Get(_NM_DEVICE_IFACE, 'State', + reply_handler=self.__get_device_state_reply_cb, + error_handler=self.__get_device_state_error_cb) +@@ -849,13 +871,12 @@ class NetworkManagerObserver(object): + # FIXME It would be better to do all of this async, but I cannot think + # of a good way to. NM could really use some love here. + +- netmgr_props = dbus.Interface( +- self._netmgr, 'org.freedesktop.DBus.Properties') ++ netmgr_props = dbus.Interface(self._netmgr, dbus.PROPERTIES_IFACE) + active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections') + + for conn_o in active_connections_o: + obj = self._bus.get_object(_NM_IFACE, conn_o) +- props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') ++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) + state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State') + if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATING: + ap_o = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject') +@@ -879,7 +900,7 @@ class NetworkManagerObserver(object): + + def _check_device(self, device_o): + device = self._bus.get_object(_NM_SERVICE, device_o) +- props = dbus.Interface(device, 'org.freedesktop.DBus.Properties') ++ props = dbus.Interface(device, dbus.PROPERTIES_IFACE) + + device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType') + if device_type == network.DEVICE_TYPE_802_11_WIRELESS: +diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py +index 3a949da..33088c4 100644 +--- a/src/jarabe/model/network.py ++++ b/src/jarabe/model/network.py +@@ -330,6 +330,13 @@ class NMSettings(dbus.service.Object): + self.secrets_request.send(self, connection=sender, + response=kwargs['response']) + ++ def clear_wifi_connections(self): ++ for uuid in self.connections.keys(): ++ conn = self.connections[uuid] ++ if conn.type == NM_CONNECTION_TYPE_802_11_WIRELESS: ++ conn.Removed() ++ self.connections.pop(uuid) ++ + class SecretsResponse(object): + ''' Intermediate object to report the secrets from the dialog + back to the connection object and which will inform NM +@@ -358,6 +365,16 @@ class NMSettingsConnection(dbus.service.Object): + self._settings = settings + self._secrets = secrets + ++ @dbus.service.signal(dbus_interface=NM_CONNECTION_IFACE, ++ signature='') ++ def Removed(self): ++ pass ++ ++ @dbus.service.signal(dbus_interface=NM_CONNECTION_IFACE, ++ signature='a{sa{sv}}') ++ def Updated(self, settings): ++ pass ++ + def set_connected(self): + if self._settings.connection.type == NM_CONNECTION_TYPE_GSM: + self._settings.connection.timestamp = int(time.time()) +@@ -366,8 +383,17 @@ class NMSettingsConnection(dbus.service.Object): + self._settings.connection.autoconnect = True + self._settings.connection.timestamp = int(time.time()) + if self._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS: ++ self.Updated(self._settings.get_dict()) + self.save() + ++ def set_disconnected(self): ++ if self._settings.connection.type != NM_CONNECTION_TYPE_GSM and \ ++ self._settings.connection.autoconnect: ++ self._settings.connection.autoconnect = False ++ self._settings.connection.timestamp = None ++ self.Updated(self._settings.get_dict()) ++ self.save() ++ + def set_secrets(self, secrets): + self._secrets = secrets + if self._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS: +@@ -377,8 +403,7 @@ class NMSettingsConnection(dbus.service.Object): + return self._settings + + def save(self): +- profile_path = env.get_profile_path() +- config_path = os.path.join(profile_path, 'nm', 'connections.cfg') ++ config_path = _get_wifi_connections_path() + + config = ConfigParser.ConfigParser() + try: +@@ -477,8 +502,7 @@ class AccessPoint(gobject.GObject): + self.mode = 0 + + def initialize(self): +- model_props = dbus.Interface(self.model, +- 'org.freedesktop.DBus.Properties') ++ model_props = dbus.Interface(self.model, dbus.PROPERTIES_IFACE) + model_props.GetAll(NM_ACCESSPOINT_IFACE, byte_arrays=True, + reply_handler=self._ap_properties_changed_cb, + error_handler=self._get_all_props_error_cb) +@@ -590,19 +614,23 @@ def add_connection(uuid, settings, secrets=None): + _nm_settings.add_connection(uuid, conn) + return conn + +-def load_wifi_connections(): ++def _get_wifi_connections_path(): + profile_path = env.get_profile_path() +- config_path = os.path.join(profile_path, 'nm', 'connections.cfg') ++ return os.path.join(profile_path, 'nm', 'connections.cfg') + +- config = ConfigParser.ConfigParser() ++def _create_wifi_connections(config_path): ++ if not os.path.exists(os.path.dirname(config_path)): ++ os.makedirs(os.path.dirname(config_path), 0755) ++ f = open(config_path, 'w') ++ f.close() ++ ++def load_wifi_connections(): ++ config_path = _get_wifi_connections_path() + + if not os.path.exists(config_path): +- if not os.path.exists(os.path.dirname(config_path)): +- os.makedirs(os.path.dirname(config_path), 0755) +- f = open(config_path, 'w') +- config.write(f) +- f.close() ++ _create_wifi_connections(config_path) + ++ config = ConfigParser.ConfigParser() + try: + if not config.read(config_path): + logging.error('Error reading the nm config file') +@@ -708,3 +736,13 @@ def find_gsm_connection(): + + logging.debug('There is no gsm connection in the NMSettings.') + return None ++ ++def count_wifi_connections(): ++ return len(get_settings().connections) ++ ++def clear_wifi_connections(): ++ if _nm_settings is not None: ++ _nm_settings.clear_wifi_connections() ++ ++ config_path = _get_wifi_connections_path() ++ _create_wifi_connections(config_path) +-- +1.7.1 + diff --git a/rpms/sugar/sl1814-consolidate-activity-launch-entry-point.patch b/rpms/sugar/sl1814-consolidate-activity-launch-entry-point.patch new file mode 100644 index 0000000..03dd862 --- /dev/null +++ b/rpms/sugar/sl1814-consolidate-activity-launch-entry-point.patch @@ -0,0 +1,292 @@ +From 1a32f508e70ccbfe2f9dad65260727222c7a727b Mon Sep 17 00:00:00 2001 +From: Aleksey Lim <alsroot@member.fsf.org> +Date: Thu, 11 Mar 2010 15:55:05 +0000 +Subject: Use only one entry point for activity launch #1814 + + +diff --git a/src/jarabe/desktop/activitieslist.py b/src/jarabe/desktop/activitieslist.py +index 87f2af0..e14d0f7 100644 +--- a/src/jarabe/desktop/activitieslist.py ++++ b/src/jarabe/desktop/activitieslist.py +@@ -36,6 +36,7 @@ from sugar.activity.activityhandle import ActivityHandle + from jarabe.model import bundleregistry + from jarabe.view.palettes import ActivityPalette + from jarabe.view import launcher ++from jarabe.journal import misc + + class ActivitiesTreeView(gtk.TreeView): + __gtype_name__ = 'SugarActivitiesTreeView' +@@ -143,13 +144,7 @@ class ActivitiesTreeView(gtk.TreeView): + registry = bundleregistry.get_registry() + bundle = registry.get_bundle(row[ListModel.COLUMN_BUNDLE_ID]) + +- activity_id = activityfactory.create_activity_id() +- +- client = gconf.client_get_default() +- xo_color = XoColor(client.get_string('/desktop/sugar/user/color')) +- +- launcher.add_launcher(activity_id, bundle.get_icon(), xo_color) +- activityfactory.create(bundle, ActivityHandle(activity_id)) ++ misc.launch(bundle) + + def set_filter(self, query): + self._query = query.lower() +diff --git a/src/jarabe/desktop/favoritesview.py b/src/jarabe/desktop/favoritesview.py +index 9f3c37b..a843741 100644 +--- a/src/jarabe/desktop/favoritesview.py ++++ b/src/jarabe/desktop/favoritesview.py +@@ -484,16 +484,7 @@ class ActivityIcon(CanvasIcon): + if self._resume_mode and self._journal_entries: + self._resume(self._journal_entries[0]) + else: +- client = gconf.client_get_default() +- xo_color = XoColor(client.get_string('/desktop/sugar/user/color')) +- +- activity_id = activityfactory.create_activity_id() +- launcher.add_launcher(activity_id, +- self._activity_info.get_icon(), +- xo_color) +- +- handle = ActivityHandle(activity_id) +- activityfactory.create(self._activity_info, handle) ++ misc.launch(self._activity_info) + + def get_bundle_id(self): + return self._activity_info.get_bundle_id() +diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py +index a04922b..10aa514 100644 +--- a/src/jarabe/desktop/meshbox.py ++++ b/src/jarabe/desktop/meshbox.py +@@ -47,12 +47,12 @@ from jarabe.desktop.spreadlayout import SpreadLayout + from jarabe.desktop import keydialog + from jarabe.model import bundleregistry + from jarabe.model import network +-from jarabe.model import shell + from jarabe.model.network import Settings + from jarabe.model.network import IP4Config + from jarabe.model.network import WirelessSecurity + from jarabe.model.network import AccessPoint + from jarabe.model.olpcmesh import OlpcMeshManager ++from jarabe.journal import misc + + _NM_SERVICE = 'org.freedesktop.NetworkManager' + _NM_IFACE = 'org.freedesktop.NetworkManager' +@@ -654,21 +654,11 @@ class ActivityView(hippo.CanvasBox): + icon.destroy() + + def _clicked_cb(self, item): +- shell_model = shell.get_model() +- activity = shell_model.get_activity_by_id(self._model.get_id()) +- if activity: +- activity.get_window().activate(gtk.get_current_event_time()) +- return +- + bundle_id = self._model.get_bundle_id() + bundle = bundleregistry.get_registry().get_bundle(bundle_id) + +- launcher.add_launcher(self._model.get_id(), +- bundle.get_icon(), +- self._model.get_color()) +- +- handle = ActivityHandle(self._model.get_id()) +- activityfactory.create(bundle, handle) ++ misc.launch(bundle, activity_id=self._model.get_id(), ++ color=self._model.get_color()) + + def set_filter(self, query): + text_to_check = self._model.activity.props.name.lower() + \ +diff --git a/src/jarabe/frame/activitiestray.py b/src/jarabe/frame/activitiestray.py +index b5762ee..b7bf621 100644 +--- a/src/jarabe/frame/activitiestray.py ++++ b/src/jarabe/frame/activitiestray.py +@@ -49,6 +49,7 @@ from jarabe.view.pulsingicon import PulsingIcon + from jarabe.view import launcher + from jarabe.frame.frameinvoker import FrameWidgetInvoker + from jarabe.frame.notification import NotificationIcon ++from jarabe.journal import misc + import jarabe.frame + + +@@ -164,22 +165,10 @@ class ActivityInviteButton(BaseInviteButton): + + def _launch(self): + """Join the activity in the invite.""" +- +- shell_model = shell.get_model() +- activity = shell_model.get_activity_by_id(self._activity_model.get_id()) +- if activity: +- activity.get_window().activate(gtk.get_current_event_time()) +- return +- + registry = bundleregistry.get_registry() + bundle = registry.get_bundle(self._bundle_id) + +- launcher.add_launcher(self._activity_model.get_id(), +- bundle.get_icon(), +- self._activity_model.get_color()) +- +- handle = ActivityHandle(self._activity_model.get_id()) +- activityfactory.create(bundle, handle) ++ misc.launch(bundle, color=self._activity_model.get_color()) + + class PrivateInviteButton(BaseInviteButton): + """Invite to a private one to one channel""" +@@ -223,7 +212,7 @@ class PrivateInviteButton(BaseInviteButton): + + def _launch(self): + """Start the activity with private channel.""" +- activityfactory.create_with_uri(self._bundle, self._private_channel) ++ misc.launch(self._bundle, uri=self._private_channel) + + class BaseInvitePalette(Palette): + """Palette for frame or notification icon for invites.""" +@@ -272,8 +261,7 @@ class ActivityInvitePalette(BaseInvitePalette): + self.set_primary_text(self._bundle_id) + + def _join(self): +- handle = ActivityHandle(self._activity_model.get_id()) +- activityfactory.create(self._bundle, handle) ++ misc.launch(self._bundle, activity_id=self._activity_model.get_id()) + + def _decline(self): + invites = owner.get_model().get_invites() +@@ -298,7 +286,7 @@ class PrivateInvitePalette(BaseInvitePalette): + self.set_primary_text(self._bundle_id) + + def _join(self): +- activityfactory.create_with_uri(self._bundle, self._private_channel) ++ misc.launch(self._bundle, uri=self._private_channel) + + invites = owner.get_model().get_invites() + invites.remove_private_channel(self._private_channel) +diff --git a/src/jarabe/journal/misc.py b/src/jarabe/journal/misc.py +index 24ad216..65e5221 100644 +--- a/src/jarabe/journal/misc.py ++++ b/src/jarabe/journal/misc.py +@@ -168,7 +168,7 @@ def resume(metadata, bundle_id=None): + bundle.get_bundle_id()) + installed_bundle = registry.get_bundle(bundle.get_bundle_id()) + if installed_bundle: +- activityfactory.create(installed_bundle) ++ launch(installed_bundle) + else: + logging.error('Bundle %r is not installed.', + bundle.get_bundle_id()) +@@ -192,17 +192,11 @@ def resume(metadata, bundle_id=None): + logging.debug('activityfactory.creating with uri %s', uri) + + activity_bundle = registry.get_bundle(activities[0].get_bundle_id()) +- activityfactory.create_with_uri(activity_bundle, bundle.get_start_uri()) ++ launch(activity_bundle, uri=uri) ++ + else: + activity_id = metadata.get('activity_id', '') + +- if activity_id: +- shell_model = shell.get_model() +- activity = shell_model.get_activity_by_id(activity_id) +- if activity: +- activity.get_window().activate(gtk.get_current_event_time()) +- return +- + if bundle_id is None: + activities = get_activities(metadata) + if not activities: +@@ -213,20 +207,36 @@ def resume(metadata, bundle_id=None): + + bundle = registry.get_bundle(bundle_id) + +- + if metadata.get('mountpoint', '/') == '/': + object_id = metadata['uid'] + else: + object_id = model.copy(metadata, '/') + +- if activity_id: +- launcher.add_launcher(activity_id, bundle.get_icon(), +- get_icon_color(metadata)) +- handle = ActivityHandle(object_id=object_id, +- activity_id=activity_id) +- activityfactory.create(bundle, handle) +- else: +- activityfactory.create_with_object_id(bundle, object_id) ++ launch(bundle, activity_id=activity_id, object_id=object_id, ++ color=get_icon_color(metadata)) ++ ++def launch(bundle, activity_id=None, object_id=None, uri=None, color=None): ++ if activity_id is None: ++ activity_id = activityfactory.create_activity_id() ++ ++ logging.debug('launch bundle_id=%s activity_id=%s object_id=%s uri=%s', ++ bundle.get_bundle_id(), activity_id, object_id, uri) ++ ++ shell_model = shell.get_model() ++ activity = shell_model.get_activity_by_id(activity_id) ++ if activity is not None: ++ logging.debug('re-launch %r', activity.get_window()) ++ activity.get_window().activate(gtk.get_current_event_time()) ++ return ++ ++ if color is None: ++ client = gconf.client_get_default() ++ color = XoColor(client.get_string('/desktop/sugar/user/color')) ++ ++ launcher.add_launcher(activity_id, bundle.get_icon(), color) ++ activity_handle = ActivityHandle(activity_id=activity_id, ++ object_id=object_id, uri=uri) ++ activityfactory.create(bundle, activity_handle) + + def is_activity_bundle(metadata): + mime_type = metadata.get('mime_type', '') +diff --git a/src/jarabe/model/shell.py b/src/jarabe/model/shell.py +index e03e0f7..c1380d1 100644 +--- a/src/jarabe/model/shell.py ++++ b/src/jarabe/model/shell.py +@@ -559,6 +559,11 @@ class ShellModel(gobject.GObject): + raise ValueError("Activity service name '%s'" \ + " was not found in the bundle registry." + % service_name) ++ ++ home_activity = self.get_activity_by_id(activity_id) ++ if home_activity is not None: ++ self._remove_activity(home_activity) ++ + home_activity = Activity(activity_info, activity_id) + home_activity.props.launching = True + self._add_activity(home_activity) +diff --git a/src/jarabe/view/palettes.py b/src/jarabe/view/palettes.py +index 2beceff..0c0e957 100644 +--- a/src/jarabe/view/palettes.py ++++ b/src/jarabe/view/palettes.py +@@ -32,8 +32,8 @@ from sugar.activity import activityfactory + from sugar.activity.activityhandle import ActivityHandle + + from jarabe.model import shell +-from jarabe.view import launcher + from jarabe.view.viewsource import setup_view_source ++from jarabe.journal import misc + + class BasePalette(Palette): + def __init__(self, home_activity): +@@ -133,17 +133,7 @@ class ActivityPalette(Palette): + + def __start_activate_cb(self, menu_item): + self.popdown(immediate=True) +- +- client = gconf.client_get_default() +- xo_color = XoColor(client.get_string('/desktop/sugar/user/color')) +- +- activity_id = activityfactory.create_activity_id() +- launcher.add_launcher(activity_id, +- self._activity_info.get_icon(), +- xo_color) +- +- handle = ActivityHandle(activity_id) +- activityfactory.create(self._activity_info, handle) ++ misc.launch(self._activity_info) + + class JournalPalette(BasePalette): + def __init__(self, home_activity): +-- +1.6.5.3 + diff --git a/rpms/sugar/sl1940-register-session-failed-fix.patch b/rpms/sugar/sl1940-register-session-failed-fix.patch index e5060b2..261b4ee 100644 --- a/rpms/sugar/sl1940-register-session-failed-fix.patch +++ b/rpms/sugar/sl1940-register-session-failed-fix.patch @@ -18,7 +18,7 @@ index 47db43f..218752c 100644 from sugar import dispatch from sugar import env @@ -501,6 +502,16 @@ class NMSettingsConnection(dbus.service.Object): - if self._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS: + self.Updated(self._settings.get_dict()) self.save() + try: @@ -31,8 +31,8 @@ index 47db43f..218752c 100644 + except: + logging.error('Error calling libc.__res_init') + - def set_secrets(self, secrets): - self._secrets = secrets - if self._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS: + def set_disconnected(self): + if self._settings.connection.type != NM_CONNECTION_TYPE_GSM and \ + self._settings.connection.autoconnect: -- diff --git a/rpms/sugar/sugar.spec b/rpms/sugar/sugar.spec index 4bfa7ae..22df3a4 100644 --- a/rpms/sugar/sugar.spec +++ b/rpms/sugar/sugar.spec @@ -3,7 +3,7 @@ Summary: Constructionist learning platform Name: sugar Version: 0.88.1 -Release: 5.31dxo%{?dist} +Release: 5.34dxo%{?dist} URL: http://sugarlabs.org/ Source0: http://download.sugarlabs.org/sources/sucrose/glucose/%{name}/%{name}-%{version}.tar.bz2 @@ -30,7 +30,7 @@ Patch16: journal-xobundle-removal-wont-remove-installed-one.patch Patch18: disconnect-icon-in-wifi-palette-1736.patch Patch19: improve-activity-updater-icon.patch Patch20: indicate-inactive-state-in-mesh-device-icon.patch -Patch21: discard_network_connections.patch +Patch21: sl1673-fix-network-disconnect-and-discard-history-v2.patch #Patch22: sl1814-consolidate-activity-launch-entry-point.patch Patch23: sl1940-register-session-failed-fix.patch @@ -61,6 +61,7 @@ Patch504: sl2064-always-listen-for-NameOwnerChanged-DBus-message.patch Patch506: jasg-register-rename.patch Patch507: prevent-multiple-XS-icons-when-re-register.patch Patch508: microformat-updater.patch +Patch509: sl1610-default-ad-hoc-networks.patch # tch experimental patches patch601: bundle-Delete-profile-data-only-when-erased.patch @@ -198,6 +199,7 @@ multiple instances of sugar. %patch506 -p1 %patch507 -p1 %patch508 -p1 +%patch509 -p1 %patch601 -p1 %patch602 -p1 |