Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar

This commit is contained in:
Simon McVittie 2007-08-30 15:38:05 +01:00
commit 93dd18ff0a
12 changed files with 330 additions and 150 deletions

5
NEWS
View File

@ -1,3 +1,8 @@
* Add badges to infrastructure access points in mesh view (dcbw)
* Add palette to Wireless device on Home view showing channel (dcbw)
Snapshot 23ad88db0c
* Re-share an activity when it gets launched from the journal if it was * Re-share an activity when it gets launched from the journal if it was
shared before (dcbw) shared before (dcbw)
* Update to new tubes API (cassidy) * Update to new tubes API (cassidy)

View File

@ -25,6 +25,7 @@ import gobject
import gtk import gtk
from hardware import nminfo from hardware import nminfo
from sugar.graphics import xocolor
IW_AUTH_ALG_OPEN_SYSTEM = 0x00000001 IW_AUTH_ALG_OPEN_SYSTEM = 0x00000001
IW_AUTH_ALG_SHARED_KEY = 0x00000002 IW_AUTH_ALG_SHARED_KEY = 0x00000002
@ -91,14 +92,16 @@ class Network(gobject.GObject):
gobject.TYPE_NONE, ([])) gobject.TYPE_NONE, ([]))
} }
def __init__(self, op): def __init__(self, client, op):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._client = client
self._op = op self._op = op
self._ssid = None self._ssid = None
self._mode = None self._mode = None
self._strength = 0 self._strength = 0
self._caps = 0 self._caps = 0
self._valid = False self._valid = False
self._favorite = False
self._state = NETWORK_STATE_NOTCONNECTED self._state = NETWORK_STATE_NOTCONNECTED
obj = sys_bus.get_object(NM_SERVICE, self._op) obj = sys_bus.get_object(NM_SERVICE, self._op)
@ -129,6 +132,12 @@ class Network(gobject.GObject):
self.emit('initialized', self._valid) self.emit('initialized', self._valid)
return return
fav_nets = []
if self._client.nminfo:
fav_nets = self._client.nminfo.get_networks()
if self._ssid in fav_nets:
self._favorite = True
self._valid = True self._valid = True
logging.debug("Net(%s): caps 0x%X" % (self._ssid, self._caps)) logging.debug("Net(%s): caps 0x%X" % (self._ssid, self._caps))
self.emit('initialized', self._valid) self.emit('initialized', self._valid)
@ -138,6 +147,16 @@ class Network(gobject.GObject):
self._valid = False self._valid = False
self.emit('initialized', self._valid) self.emit('initialized', self._valid)
def get_colors(self):
import sha
sh = sha.new()
data = self._ssid + hex(self._caps) + hex(self._mode)
sh.update(data)
h = hash(sh.digest())
idx = h % len(xocolor._colors)
# stroke, fill
return (xocolor._colors[idx][0], xocolor._colors[idx][1])
def get_ssid(self): def get_ssid(self):
return self._ssid return self._ssid
@ -173,6 +192,9 @@ class Network(gobject.GObject):
def is_valid(self): def is_valid(self):
return self._valid return self._valid
def is_favorite(self):
return self._favorite
class Device(gobject.GObject): class Device(gobject.GObject):
__gsignals__ = { __gsignals__ = {
'initialized': (gobject.SIGNAL_RUN_FIRST, 'initialized': (gobject.SIGNAL_RUN_FIRST,
@ -193,8 +215,9 @@ class Device(gobject.GObject):
([gobject.TYPE_PYOBJECT])) ([gobject.TYPE_PYOBJECT]))
} }
def __init__(self, op): def __init__(self, client, op):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._client = client
self._op = op self._op = op
self._iface = None self._iface = None
self._type = DEVICE_TYPE_UNKNOWN self._type = DEVICE_TYPE_UNKNOWN
@ -202,25 +225,27 @@ class Device(gobject.GObject):
self._active = False self._active = False
self._act_stage = 0 self._act_stage = 0
self._strength = 0 self._strength = 0
self._freq = 0.0
self._link = False self._link = False
self._valid = False self._valid = False
self._networks = {} self._networks = {}
self._caps = 0 self._caps = 0
self._state = DEVICE_STATE_INACTIVE self._state = DEVICE_STATE_INACTIVE
self._active_network = None self._active_network = None
self._active_net_sigid = 0
obj = sys_bus.get_object(NM_SERVICE, self._op) obj = sys_bus.get_object(NM_SERVICE, self._op)
dev = dbus.Interface(obj, NM_IFACE_DEVICES) self.dev = dbus.Interface(obj, NM_IFACE_DEVICES)
dev.getProperties(reply_handler=self._update_reply_cb, self.dev.getProperties(reply_handler=self._update_reply_cb,
error_handler=self._update_error_cb) error_handler=self._update_error_cb)
def _is_activating(self): def _is_activating(self):
if self._active and self._act_stage >= 1 and self._act_stage <= 7: if self._active and self._act_stage >= 1 and self._act_stage <= 6:
return True return True
return False return False
def _is_activated(self): def _is_activated(self):
if self._active and self._act_stage == 8: if self._active and self._act_stage == 7:
return True return True
return False return False
@ -260,7 +285,7 @@ class Device(gobject.GObject):
def _update_networks(self, net_ops, active_op): def _update_networks(self, net_ops, active_op):
for op in net_ops: for op in net_ops:
net = Network(op) net = Network(self._client, op)
self._networks[op] = net self._networks[op] = net
net.connect('initialized', lambda *args: self._net_initialized_cb(active_op, *args)) net.connect('initialized', lambda *args: self._net_initialized_cb(active_op, *args))
@ -307,6 +332,16 @@ class Device(gobject.GObject):
ret.append(net.get_op()) ret.append(net.get_op())
return ret return ret
def get_frequency(self):
freq = 0.0
try:
freq = self.dev.getFrequency(timeout=3000)
except dbus.DBusException, e:
pass
# Hz -> GHz
self._freq = freq / 1000000000.0
return self._freq
def get_strength(self): def get_strength(self):
return self._strength return self._strength
@ -325,7 +360,7 @@ class Device(gobject.GObject):
def network_appeared(self, network): def network_appeared(self, network):
if self._networks.has_key(network): if self._networks.has_key(network):
return return
net = Network(network) net = Network(self._client, network)
self._networks[network] = net self._networks[network] = net
net.connect('initialized', lambda *args: self._net_initialized_cb(None, *args)) net.connect('initialized', lambda *args: self._net_initialized_cb(None, *args))
@ -345,9 +380,14 @@ class Device(gobject.GObject):
# Make sure the old one doesn't get a stuck state # Make sure the old one doesn't get a stuck state
if self._active_network: if self._active_network:
self._active_network.set_state(NETWORK_STATE_NOTCONNECTED) self._active_network.set_state(NETWORK_STATE_NOTCONNECTED)
self._active_network.disconnect(self._active_net_sigid)
self._active_network = network self._active_network = network
if self._active_network:
self._active_net_sigid = self._active_network.connect("initialized",
self._active_net_initialized);
# don't emit ssid-changed for networks that are not yet valid # don't emit ssid-changed for networks that are not yet valid
if self._valid: if self._valid:
if self._active_network and self._active_network.is_valid(): if self._active_network and self._active_network.is_valid():
@ -355,6 +395,10 @@ class Device(gobject.GObject):
elif not self._active_network: elif not self._active_network:
self.emit('ssid-changed') self.emit('ssid-changed')
def _active_net_initialized(self, net, user_data=None):
if self._active_network and self._active_network.is_valid():
self.emit('ssid-changed')
def _get_active_net_cb(self, state, net_op): def _get_active_net_cb(self, state, net_op):
if not self._networks.has_key(net_op): if not self._networks.has_key(net_op):
self.set_active_network(None) self.set_active_network(None)
@ -390,9 +434,7 @@ class Device(gobject.GObject):
if state == DEVICE_STATE_INACTIVE: if state == DEVICE_STATE_INACTIVE:
self.set_active_network(None) self.set_active_network(None)
else: else:
obj = sys_bus.get_object(NM_SERVICE, self._op) self.dev.getActiveNetwork(reply_handler=lambda *args: self._get_active_net_cb(state, *args),
dev = dbus.Interface(obj, NM_IFACE_DEVICES)
dev.getActiveNetwork(reply_handler=lambda *args: self._get_active_net_cb(state, *args),
error_handler=self._get_active_net_error_cb) error_handler=self._get_active_net_error_cb)
def get_ssid(self): def get_ssid(self):
@ -401,6 +443,9 @@ class Device(gobject.GObject):
elif not self._active_network: elif not self._active_network:
return None return None
def get_active_network(self):
return self._active_network
def get_type(self): def get_type(self):
return self._type return self._type
@ -470,7 +515,7 @@ class NMClient(gobject.GObject):
def _add_device(self, dev_op): def _add_device(self, dev_op):
if self._devices.has_key(dev_op): if self._devices.has_key(dev_op):
return return
dev = Device(dev_op) dev = Device(self, dev_op)
self._devices[dev_op] = dev self._devices[dev_op] = dev
dev.connect('init-failed', self._dev_init_failed_cb) dev.connect('init-failed', self._dev_init_failed_cb)
dev.connect('initialized', self._dev_initialized_cb) dev.connect('initialized', self._dev_initialized_cb)

View File

@ -27,7 +27,9 @@ class Device(device.Device):
'strength' : (int, None, None, 0, 100, 0, 'strength' : (int, None, None, 0, 100, 0,
gobject.PARAM_READABLE), gobject.PARAM_READABLE),
'state' : (int, None, None, device.STATE_ACTIVATING, 'state' : (int, None, None, device.STATE_ACTIVATING,
device.STATE_INACTIVE, 0, gobject.PARAM_READABLE) device.STATE_INACTIVE, 0, gobject.PARAM_READABLE),
'frequency': (float, None, None, 0.0, 9999.99, 0.0,
gobject.PARAM_READABLE)
} }
def __init__(self, nm_device): def __init__(self, nm_device):
@ -60,9 +62,18 @@ class Device(device.Device):
elif pspec.name == 'state': elif pspec.name == 'state':
nm_state = self._nm_device.get_state() nm_state = self._nm_device.get_state()
return device._nm_state_to_state[nm_state] return device._nm_state_to_state[nm_state]
elif pspec.name == 'frequency':
return self._nm_device.get_frequency()
def get_type(self): def get_type(self):
return 'network.wireless' return 'network.wireless'
def get_id(self): def get_id(self):
return str(self._nm_device.get_op()) 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()

View File

@ -15,9 +15,14 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from gettext import gettext as _
import gtk
from sugar.graphics.icon import get_icon_state from sugar.graphics.icon import get_icon_state
from sugar.graphics.icon import CanvasIcon from sugar.graphics.icon import CanvasIcon
from sugar.graphics import style from sugar.graphics import style
from sugar.graphics.palette import Palette
from model.devices.network import wireless from model.devices.network import wireless
from model.devices import device from model.devices import device
@ -28,26 +33,42 @@ class DeviceView(CanvasIcon):
def __init__(self, model): def __init__(self, model):
CanvasIcon.__init__(self, size=style.MEDIUM_ICON_SIZE) CanvasIcon.__init__(self, size=style.MEDIUM_ICON_SIZE)
self._model = model self._model = model
self._palette = WirelessPalette(self._get_palette_primary_text())
self.set_palette(self._palette)
self._counter = 0
self._palette.set_frequency(self._model.props.frequency)
model.connect('notify::name', self._name_changed_cb) model.connect('notify::name', self._name_changed_cb)
model.connect('notify::strength', self._strength_changed_cb) model.connect('notify::strength', self._strength_changed_cb)
model.connect('notify::state', self._state_changed_cb) model.connect('notify::state', self._state_changed_cb)
self.set_tooltip(self._model.props.name)
self._update_icon() self._update_icon()
self._update_state() self._update_state()
def _get_palette_primary_text(self):
if self._model.props.state == device.STATE_INACTIVE:
return _("Disconnected")
return self._model.props.name
def _strength_changed_cb(self, model, pspec): def _strength_changed_cb(self, model, pspec):
self._update_icon() 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): def _name_changed_cb(self, model, pspec):
self.palette.set_primary_text(self._model.props.name) self.palette.set_primary_text(self._get_palette_primary_text())
def _state_changed_cb(self, model, pspec): def _state_changed_cb(self, model, pspec):
self._update_state() self._update_state()
self.palette.set_primary_text(self._get_palette_primary_text())
def _update_icon(self): def _update_icon(self):
icon_name = get_icon_state(_ICON_NAME, self._model.props.strength) strength = self._model.props.strength
if self._model.props.state == device.STATE_INACTIVE:
strength = 0
icon_name = get_icon_state(_ICON_NAME, strength)
if icon_name: if icon_name:
self.props.icon_name = icon_name self.props.icon_name = icon_name
@ -58,8 +79,35 @@ class DeviceView(CanvasIcon):
self.props.fill_color = style.COLOR_INACTIVE_FILL.get_svg() self.props.fill_color = style.COLOR_INACTIVE_FILL.get_svg()
self.props.stroke_color = style.COLOR_INACTIVE_STROKE.get_svg() self.props.stroke_color = style.COLOR_INACTIVE_STROKE.get_svg()
elif state == device.STATE_ACTIVATED: elif state == device.STATE_ACTIVATED:
self.props.fill_color = None (stroke, fill) = self._model.get_active_network_colors()
self.props.stroke_color = None self.props.stroke_color = stroke
self.props.fill_color = fill
elif state == device.STATE_INACTIVE: elif state == device.STATE_INACTIVE:
self.props.fill_color = style.COLOR_INACTIVE_FILL.get_svg() self.props.fill_color = style.COLOR_INACTIVE_FILL.get_svg()
self.props.stroke_color = style.COLOR_INACTIVE_STROKE.get_svg() self.props.stroke_color = style.COLOR_INACTIVE_STROKE.get_svg()
class WirelessPalette(Palette):
def __init__(self, primary_text):
Palette.__init__(self, primary_text)
self._chan_label = gtk.Label()
self._chan_label.show()
vbox = gtk.VBox()
vbox.pack_start(self._chan_label)
vbox.show()
self.set_content(vbox)
def set_frequency(self, freq):
chans = { 2.412: 1, 2.417: 2, 2.422: 3, 2.427: 4,
2.432: 5, 2.437: 6, 2.442: 7, 2.447: 8,
2.452: 9, 2.457: 10, 2.462: 11, 2.467: 12,
2.472: 13
}
try:
chan = chans[freq]
except KeyError:
chan = 0
self._chan_label.set_text("%s: %d" % (_("Channel"), chan))

View File

@ -36,6 +36,9 @@ from view.BuddyIcon import BuddyIcon
from view.pulsingicon import PulsingIcon from view.pulsingicon import PulsingIcon
from view.home.snowflakelayout import SnowflakeLayout from view.home.snowflakelayout import SnowflakeLayout
from hardware.nmclient import NM_802_11_CAP_PROTO_WEP, NM_802_11_CAP_PROTO_WPA, NM_802_11_CAP_PROTO_WPA2
_ICON_NAME = 'network-wireless' _ICON_NAME = 'network-wireless'
class AccessPointView(PulsingIcon): class AccessPointView(PulsingIcon):
@ -49,20 +52,21 @@ class AccessPointView(PulsingIcon):
model.connect('notify::name', self._name_changed_cb) model.connect('notify::name', self._name_changed_cb)
model.connect('notify::state', self._state_changed_cb) model.connect('notify::state', self._state_changed_cb)
import sha (stroke, fill) = model.get_nm_network().get_colors()
sh = sha.new() self._device_stroke = stroke
data = self._model.props.name + hex(self._model.props.capabilities) + \ self._device_fill = fill
hex(self._model.props.mode)
sh.update(data)
h = hash(sh.digest())
idx = h % len(xocolor._colors)
self._device_stroke = xocolor._colors[idx][0]
self._device_fill = xocolor._colors[idx][1]
self._update_icon() self._update_icon()
self._update_name() self._update_name()
self._update_state() self._update_state()
# Update badge
caps = model.props.capabilities
if model.get_nm_network().is_favorite():
self.props.badge_name = "badge-star"
elif (caps & NM_802_11_CAP_PROTO_WEP) or (caps & NM_802_11_CAP_PROTO_WPA) or (caps & NM_802_11_CAP_PROTO_WPA2):
self.props.badge_name = "badge-locked"
def _strength_changed_cb(self, model, pspec): def _strength_changed_cb(self, model, pspec):
self._update_icon() self._update_icon()
@ -88,7 +92,7 @@ class AccessPointView(PulsingIcon):
def _update_icon(self): def _update_icon(self):
icon_name = get_icon_state(_ICON_NAME, self._model.props.strength) icon_name = get_icon_state(_ICON_NAME, self._model.props.strength)
if icon_name: if icon_name:
self.props.icon_name = icon_name self.props.icon_name = icon_name
def _update_state(self): def _update_state(self):
if self._model.props.state == accesspointmodel.STATE_CONNECTING: if self._model.props.state == accesspointmodel.STATE_CONNECTING:

View File

@ -122,7 +122,8 @@ class ActivityCreationHandler(gobject.GObject):
error_handler=self._notify_launch_error_handler) error_handler=self._notify_launch_error_handler)
if not os.path.exists('/etc/olpc-security'): if not os.path.exists('/etc/olpc-security'):
self._factory.create(self._activity_handle.get_dict(), handle = self._activity_handle.get_dict()
self._factory.create(dbus.Dictionary(handle, signature='ss'),
timeout=120 * 1000, timeout=120 * 1000,
reply_handler=self._no_reply_handler, reply_handler=self._no_reply_handler,
error_handler=self._create_error_handler) error_handler=self._create_error_handler)

View File

@ -67,15 +67,13 @@ class ActivityHandle(object):
def get_dict(self): def get_dict(self):
"""Retrieve our settings as a dictionary""" """Retrieve our settings as a dictionary"""
result = { } result = { 'activity_id' : self.activity_id }
if self.activity_id:
result['activity_id'] = str(self.activity_id)
if self.pservice_id: if self.pservice_id:
result['pservice_id'] = str(self.pservice_id) result['pservice_id'] = self.pservice_id
if self.object_id: if self.object_id:
result['object_id'] = str(self.object_id) result['object_id'] = self.object_id
if self.uri: if self.uri:
result['uri'] = str(self.uri) result['uri'] = self.uri
return result return result

View File

@ -249,5 +249,8 @@ def unmount(mount_point_id):
def mounts(): def mounts():
return dbus_helpers.mounts() return dbus_helpers.mounts()
def complete_indexing():
return dbus_helpers.complete_indexing()
def get_unique_values(key): def get_unique_values(key):
return dbus_helpers.get_unique_values(key) return dbus_helpers.get_unique_values(key)

View File

@ -88,3 +88,6 @@ def mounts():
def get_unique_values(key): def get_unique_values(key):
return _get_data_store().get_uniquevaluesfor(key, dbus.Dictionary({}, signature='ss')) return _get_data_store().get_uniquevaluesfor(key, dbus.Dictionary({}, signature='ss'))
def complete_indexing():
return _get_data_store().complete_indexing()

View File

@ -73,10 +73,6 @@ class Palette(gtk.Window):
DEFAULT = 0 DEFAULT = 0
AT_CURSOR = 1 AT_CURSOR = 1
AROUND = 2 AROUND = 2
BOTTOM = 3
LEFT = 4
RIGHT = 5
TOP = 6
PRIMARY = 0 PRIMARY = 0
SECONDARY = 1 SECONDARY = 1
@ -106,6 +102,7 @@ class Palette(gtk.Window):
self.palette_state = self.PRIMARY self.palette_state = self.PRIMARY
self._current_alignment = None
self._old_alloc = None self._old_alloc = None
self._full_request = [0, 0] self._full_request = [0, 0]
self._cursor_x = 0 self._cursor_x = 0
@ -278,21 +275,26 @@ class Palette(gtk.Window):
self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
self._update_accept_focus() self._update_accept_focus()
def _in_screen(self, x, y): def _in_screen(self, rect):
[width, height] = self._full_request
screen_area = self._invoker.get_screen_area() screen_area = self._invoker.get_screen_area()
return rect.x >= screen_area.x and \
rect.y >= screen_area.y and \
rect.x + rect.width <= screen_area.width and \
rect.y + rect.height <= screen_area.height
return x >= screen_area.x and \ def _get_rectangle(self, alignments, full=False, inv_rect=None):
y >= screen_area.y and \ palette_halign = alignments[0]
x + width <= screen_area.width and \ palette_valign = alignments[1]
y + height <= screen_area.height invoker_halign = alignments[2]
invoker_valign = alignments[3]
def _get_position(self, palette_halign, palette_valign,
invoker_halign, invoker_valign, inv_rect=None):
if inv_rect == None: if inv_rect == None:
inv_rect = self._invoker.get_rect() inv_rect = self._invoker.get_rect()
palette_width, palette_height = self.size_request() if full:
palette_width, palette_height = self._full_request
else:
palette_width, palette_height = self.size_request()
x = inv_rect.x + inv_rect.width * invoker_halign + \ x = inv_rect.x + inv_rect.width * invoker_halign + \
palette_width * palette_halign palette_width * palette_halign
@ -300,53 +302,24 @@ class Palette(gtk.Window):
y = inv_rect.y + inv_rect.height * invoker_valign + \ y = inv_rect.y + inv_rect.height * invoker_valign + \
palette_height * palette_valign palette_height * palette_valign
return int(x), int(y) return gtk.gdk.Rectangle(int(x), int(y),
palette_width, palette_height)
def _get_left_position(self, inv_rect=None): def _get_around_alignments(self):
x, y = self._get_position(-1.0, 0.0, 0.0, 0.0, inv_rect) return [(0.0, 0.0, 0.0, 1.0),
if not self._in_screen(x, y): (-1.0, 0.0, 1.0, 1.0),
x, y = self._get_position(-1.0, -1.0, 0.0, 1.0, inv_rect) (0.0, 0.0, 1.0, 0.0),
return x, y (0.0, -1.0, 1.0, 1.0),
(0.0, -1.0, 0.0, 0.0),
(-1.0, -1.0, 1.0, 0.0),
(-1.0, 0.0, 0.0, 0.0),
(-1.0, -1.0, 0.0, 1.0)]
def _get_right_position(self, inv_rect=None): def _get_at_cursor_alignments(self, inv_rect=None):
x, y = self._get_position(0.0, 0.0, 1.0, 0.0, inv_rect) return [(0.0, 0.0, 1.0, 1.0),
if not self._in_screen(x, y): (0.0, -1.0, 1.0, 0.0),
x, y = self._get_position(0.0, -1.0, 1.0, 1.0, inv_rect) (-1.0, -1.0, 0.0, 0.0),
return x, y (-1.0, 0.0, 0.0, 1.0)]
def _get_top_position(self, inv_rect=None):
x, y = self._get_position(0.0, -1.0, 0.0, 0.0, inv_rect)
if not self._in_screen(x, y):
x, y = self._get_position(-1.0, -1.0, 1.0, 0.0, inv_rect)
return x, y
def _get_bottom_position(self, inv_rect=None):
x, y = self._get_position(0.0, 0.0, 0.0, 1.0, inv_rect)
if not self._in_screen(x, y):
x, y = self._get_position(-1.0, 0.0, 1.0, 1.0, inv_rect)
return x, y
def _get_around_position(self, inv_rect=None):
x, y = self._get_bottom_position(inv_rect)
if not self._in_screen(x, y):
x, y = self._get_right_position(inv_rect)
if not self._in_screen(x, y):
x, y = self._get_top_position(inv_rect)
if not self._in_screen(x, y):
x, y = self._get_left_position(inv_rect)
return x, y
def _get_at_cursor_position(self, inv_rect=None):
x, y = self._get_position(0.0, 0.0, 1.0, 1.0, inv_rect)
if not self._in_screen(x, y):
x, y = self._get_position(0.0, -1.0, 1.0, 0.0, inv_rect)
if not self._in_screen(x, y):
x, y = self._get_position(-1.0, -1.0, 0.0, 0.0, inv_rect)
if not self._in_screen(x, y):
x, y = self._get_position(-1.0, 0.0, 0.0, 1.0, inv_rect)
return x, y
def _update_full_request(self): def _update_full_request(self):
state = self.palette_state state = self.palette_state
@ -374,25 +347,24 @@ class Palette(gtk.Window):
else: else:
position = self._position position = self._position
inv_rect = None
if position == self.AT_CURSOR: if position == self.AT_CURSOR:
dist = style.PALETTE_CURSOR_DISTANCE dist = style.PALETTE_CURSOR_DISTANCE
rect = gtk.gdk.Rectangle(self._cursor_x - dist, inv_rect = gtk.gdk.Rectangle(self._cursor_x - dist,
self._cursor_y - dist, self._cursor_y - dist,
dist * 2, dist * 2) dist * 2, dist * 2)
x, y = self._get_at_cursor_position(rect) alignments = self._get_around_alignments()[:]
elif position == self.AROUND: if self._current_alignment is not None:
x, y = self._get_around_position() alignments.remove(self._current_alignment)
elif position == self.BOTTOM: alignments.insert(0, self._current_alignment)
x, y = self._get_bottom_position()
elif position == self.LEFT:
x, y = self._get_left_position()
elif position == self.RIGHT:
x, y = self._get_right_position()
elif position == self.TOP:
x, y = self._get_top_position()
self.move(x, y) for align in alignments:
rect = self._get_rectangle(align, inv_rect=inv_rect)
if self._in_screen(rect):
break
self.move(rect.x, rect.y)
def _show(self): def _show(self):
if self._up: if self._up:
@ -404,6 +376,12 @@ class Palette(gtk.Window):
self._palette_popup_sid = _palette_observer.connect( self._palette_popup_sid = _palette_observer.connect(
'popup', self._palette_observer_popup_cb) 'popup', self._palette_observer_popup_cb)
for align in self._get_around_alignments():
rect = self._get_rectangle(align, full=True)
if self._in_screen(rect):
self._current_alignment = align
break
self._update_position() self._update_position()
self.menu.set_active(True) self.menu.set_active(True)
self.show() self.show()
@ -659,11 +637,11 @@ class CanvasInvoker(Invoker):
context = self._item.get_context() context = self._item.get_context()
if context: if context:
x, y = context.translate_to_screen(self._item) x, y = context.translate_to_screen(self._item)
width, height = self._item.get_allocation()
width, height = self._item.get_allocation() return gtk.gdk.Rectangle(x, y, width, height)
else:
return gtk.gdk.Rectangle(x, y, width, height) return gtk.gdk.Rectangle()
def _motion_notify_event_cb(self, button, event): def _motion_notify_event_cb(self, button, event):
if event.detail == hippo.MOTION_DETAIL_ENTER: if event.detail == hippo.MOTION_DETAIL_ENTER:
self.emit('mouse-enter') self.emit('mouse-enter')

View File

@ -22,13 +22,17 @@ from sugar.graphics import style
from sugar.graphics.toolbutton import ToolButton from sugar.graphics.toolbutton import ToolButton
from sugar.graphics.icon import Icon from sugar.graphics.icon import Icon
_PREVIOUS_PAGE = 0
_NEXT_PAGE = 1
class _TrayViewport(gtk.Viewport): class _TrayViewport(gtk.Viewport):
__gproperties__ = { __gproperties__ = {
'can-scroll' : (bool, None, None, False, 'can-scroll' : (bool, None, None, False,
gobject.PARAM_READABLE), gobject.PARAM_READABLE),
} }
def __init__(self): def __init__(self, orientation):
self.orientation = orientation
self._can_scroll = False self._can_scroll = False
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
@ -36,26 +40,47 @@ class _TrayViewport(gtk.Viewport):
self.set_shadow_type(gtk.SHADOW_NONE) self.set_shadow_type(gtk.SHADOW_NONE)
self.traybar = gtk.Toolbar() self.traybar = gtk.Toolbar()
self.traybar.set_orientation(orientation)
self.traybar.set_show_arrow(False) self.traybar.set_show_arrow(False)
self.add(self.traybar) self.add(self.traybar)
self.traybar.show() self.traybar.show()
self.connect('size_allocate', self._size_allocate_cb) self.connect('size_allocate', self._size_allocate_cb)
def scroll_right(self): def scroll(self, direction):
adj = self.get_hadjustment() if direction == _PREVIOUS_PAGE:
new_value = adj.value + self.allocation.width self._scroll_previous()
adj.value = min(new_value, adj.upper - self.allocation.width) elif direction == _NEXT_PAGE:
self._scroll_next()
def scroll_left(self): def _scroll_next(self):
adj = self.get_hadjustment() if self.orientation == gtk.ORIENTATION_HORIZONTAL:
new_value = adj.value - self.allocation.width adj = self.get_hadjustment()
adj.value = max(adj.lower, new_value) new_value = adj.value + self.allocation.width
adj.value = min(new_value, adj.upper - self.allocation.width)
else:
adj = self.get_vadjustment()
new_value = adj.value + self.allocation.height
adj.value = min(new_value, adj.upper - self.allocation.height)
def _scroll_previous(self):
if self.orientation == gtk.ORIENTATION_HORIZONTAL:
adj = self.get_hadjustment()
new_value = adj.value - self.allocation.width
adj.value = max(adj.lower, new_value)
else:
adj = self.get_vadjustment()
new_value = adj.value - self.allocation.height
adj.value = max(adj.lower, new_value)
def do_size_request(self, requisition): def do_size_request(self, requisition):
child_requisition = self.child.size_request() child_requisition = self.child.size_request()
requisition[0] = 0 if self.orientation == gtk.ORIENTATION_HORIZONTAL:
requisition[1] = child_requisition[1] requisition[0] = 0
requisition[1] = child_requisition[1]
else:
requisition[0] = child_requisition[0]
requisition[1] = 0
def do_get_property(self, pspec): def do_get_property(self, pspec):
if pspec.name == 'can-scroll': if pspec.name == 'can-scroll':
@ -63,19 +88,23 @@ class _TrayViewport(gtk.Viewport):
def _size_allocate_cb(self, viewport, allocation): def _size_allocate_cb(self, viewport, allocation):
bar_requisition = self.traybar.get_child_requisition() bar_requisition = self.traybar.get_child_requisition()
if bar_requisition[0] < allocation.width: if self.orientation == gtk.ORIENTATION_HORIZONTAL:
can_scroll = False can_scroll = bar_requisition[0] > allocation.width
else: else:
can_scroll = True can_scroll = bar_requisition[1] > allocation.height
if can_scroll != self._can_scroll: if can_scroll != self._can_scroll:
self._can_scroll = can_scroll self._can_scroll = can_scroll
self.notify('can-scroll') self.notify('can-scroll')
class _TrayScrollButton(gtk.Button): class _TrayScrollButton(gtk.Button):
def __init__(self, icon_name): def __init__(self, icon_name, scroll_direction):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._viewport = None
self._scroll_direction = scroll_direction
self.set_relief(gtk.RELIEF_NONE) self.set_relief(gtk.RELIEF_NONE)
self.set_size_request(style.GRID_CELL_SIZE, style.GRID_CELL_SIZE) self.set_size_request(style.GRID_CELL_SIZE, style.GRID_CELL_SIZE)
@ -84,34 +113,65 @@ class _TrayScrollButton(gtk.Button):
self.set_image(icon) self.set_image(icon)
icon.show() icon.show()
self.connect('clicked', self._clicked_cb)
def set_viewport(self, viewport):
self._viewport = viewport
self._viewport.connect('notify::can-scroll',
self._viewport_can_scroll_changed_cb)
def _viewport_can_scroll_changed_cb(self, viewport, pspec):
self.props.visible = self._viewport.props.can_scroll
def _clicked_cb(self, button):
self._viewport.scroll(self._scroll_direction)
viewport = property(fset=set_viewport)
class HTray(gtk.HBox): class HTray(gtk.HBox):
def __init__(self, **kwargs): def __init__(self, **kwargs):
gobject.GObject.__init__(self, **kwargs) gobject.GObject.__init__(self, **kwargs)
self._scroll_left = _TrayScrollButton('go-left') scroll_left = _TrayScrollButton('go-left', _PREVIOUS_PAGE)
self._scroll_left.connect('clicked', self._scroll_left_cb) self.pack_start(scroll_left, False)
self.pack_start(self._scroll_left, False)
self._viewport = _TrayViewport() self._viewport = _TrayViewport(gtk.ORIENTATION_HORIZONTAL)
self._viewport.connect('notify::can-scroll',
self._viewport_can_scroll_changed_cb)
self.pack_start(self._viewport) self.pack_start(self._viewport)
self._viewport.show() self._viewport.show()
self._scroll_right = _TrayScrollButton('go-right') scroll_right = _TrayScrollButton('go-right', _NEXT_PAGE)
self._scroll_right.connect('clicked', self._scroll_right_cb) self.pack_start(scroll_right, False)
self.pack_start(self._scroll_right, False)
def _viewport_can_scroll_changed_cb(self, viewport, pspec): scroll_left.viewport = self._viewport
if self._viewport.props.can_scroll: scroll_right.viewport = self._viewport
self._scroll_left.show()
self._scroll_right.show()
def _scroll_left_cb(self, button): def add_item(self, item, index=-1):
self._viewport.scroll_left() self._viewport.traybar.insert(item, index)
def _scroll_right_cb(self, button): def remove_item(self, item):
self._viewport.scroll_right() self._viewport.traybar.remove(item)
def get_item_index(self, item):
return self._viewport.traybar.get_item_index(item)
class VTray(gtk.VBox):
def __init__(self, **kwargs):
gobject.GObject.__init__(self, **kwargs)
# FIXME we need a go-up icon
scroll_left = _TrayScrollButton('go-left', _PREVIOUS_PAGE)
self.pack_start(scroll_left, False)
self._viewport = _TrayViewport(gtk.ORIENTATION_VERTICAL)
self.pack_start(self._viewport)
self._viewport.show()
# FIXME we need a go-down icon
scroll_right = _TrayScrollButton('go-right', _NEXT_PAGE)
self.pack_start(scroll_right, False)
scroll_left.viewport = self._viewport
scroll_right.viewport = self._viewport
def add_item(self, item, index=-1): def add_item(self, item, index=-1):
self._viewport.traybar.insert(item, index) self._viewport.traybar.insert(item, index)

View File

@ -22,16 +22,17 @@ Test the sugar.graphics.icon.Icon widget.
import gtk import gtk
from sugar.graphics.tray import HTray from sugar.graphics.tray import HTray
from sugar.graphics.tray import VTray
from sugar.graphics.tray import TrayButton from sugar.graphics.tray import TrayButton
import common import common
test = common.Test() test = common.Test()
box = gtk.VBox() vbox = gtk.VBox()
tray = HTray() tray = HTray()
box.pack_start(tray, False) vbox.pack_start(tray, False)
tray.show() tray.show()
theme_icons = gtk.icon_theme_get_default().list_icons() theme_icons = gtk.icon_theme_get_default().list_icons()
@ -42,7 +43,7 @@ for i in range(0, 100):
button.show() button.show()
tray = HTray() tray = HTray()
box.pack_start(tray, False) vbox.pack_start(tray, False)
tray.show() tray.show()
for i in range(0, 10): for i in range(0, 10):
@ -50,8 +51,31 @@ for i in range(0, 10):
tray.add_item(button) tray.add_item(button)
button.show() button.show()
test.pack_start(box) hbox = gtk.HBox()
box.show()
tray = VTray()
hbox.pack_start(tray, False)
tray.show()
for i in range(0, 100):
button = TrayButton(icon_name=theme_icons[i])
tray.add_item(button)
button.show()
tray = VTray()
hbox.pack_start(tray, False)
tray.show()
for i in range(0, 4):
button = TrayButton(icon_name=theme_icons[i])
tray.add_item(button)
button.show()
vbox.pack_start(hbox)
hbox.show()
test.pack_start(vbox)
vbox.show()
test.show() test.show()