Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/services/nm
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2006-10-30 03:42:51 (GMT)
committer Dan Williams <dcbw@redhat.com>2006-10-30 03:42:51 (GMT)
commit72832e01743c9676442e2a46cfa79dbc56aba3a7 (patch)
treec6c17ec8f7458d9a9730b66fc1cf6ef882f23bca /services/nm
parent4bf76960a0982b2facb007847c163e9a32b0ee9f (diff)
Convert to an ugly Hippo menu
Diffstat (limited to 'services/nm')
-rw-r--r--services/nm/Makefile.am3
-rw-r--r--services/nm/bubble.py85
-rw-r--r--services/nm/nmclient.py148
3 files changed, 191 insertions, 45 deletions
diff --git a/services/nm/Makefile.am b/services/nm/Makefile.am
index 6dc19ec..7f6dce8 100644
--- a/services/nm/Makefile.am
+++ b/services/nm/Makefile.am
@@ -2,7 +2,8 @@ sugardir = $(pkgdatadir)/services/nm
sugar_PYTHON = \
__init__.py \
nmclient.py \
- nminfo.py
+ nminfo.py \
+ bubble.py
bin_SCRIPTS = sugar-nm-applet
diff --git a/services/nm/bubble.py b/services/nm/bubble.py
new file mode 100644
index 0000000..ca900db
--- /dev/null
+++ b/services/nm/bubble.py
@@ -0,0 +1,85 @@
+# Copyright (C) 2006, Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+import math
+
+import gobject
+import gtk
+import hippo
+
+class Bubble(hippo.CanvasBox, hippo.CanvasItem):
+ __gtype_name__ = 'NetworkBubble'
+
+ __gproperties__ = {
+ 'color' : (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'percent' : (object, None, None,
+ gobject.PARAM_READWRITE),
+ }
+
+ def __init__(self, **kwargs):
+ self._color = None
+ self._percent = 0
+ self._radius = 8
+
+ hippo.CanvasBox.__init__(self, **kwargs)
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'color':
+ self._color = value
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'percent':
+ self._percent = value
+ self.emit_paint_needed(0, 0, -1, -1)
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'color':
+ return self._color
+ elif pspec.name == 'percent':
+ return self._percent
+
+ def _string_to_rgb(self, color_string):
+ col = gtk.gdk.color_parse(color_string)
+ return (col.red / 65535.0, col.green / 65535.0, col.blue / 65535.0)
+
+ def do_paint_below_children(self, cr, damaged_box):
+ [width, height] = self.get_allocation()
+
+ line_width = 3.0
+ x = line_width
+ y = line_width
+ width -= line_width * 2
+ height -= line_width * 2
+
+ cr.move_to(x + self._radius, y);
+ cr.arc(x + width - self._radius, y + self._radius,
+ self._radius, math.pi * 1.5, math.pi * 2);
+ cr.arc(x + width - self._radius, x + height - self._radius,
+ self._radius, 0, math.pi * 0.5);
+ cr.arc(x + self._radius, y + height - self._radius,
+ self._radius, math.pi * 0.5, math.pi);
+ cr.arc(x + self._radius, y + self._radius, self._radius,
+ math.pi, math.pi * 1.5);
+
+ color = self._string_to_rgb(self._color.get_fill_color())
+ cr.set_source_rgb(*color)
+ cr.fill_preserve();
+
+ color = self._string_to_rgb(self._color.get_stroke_color())
+ cr.set_source_rgb(*color)
+ cr.set_line_width(line_width)
+ cr.stroke();
diff --git a/services/nm/nmclient.py b/services/nm/nmclient.py
index 8097d57..fcc5638 100644
--- a/services/nm/nmclient.py
+++ b/services/nm/nmclient.py
@@ -22,9 +22,15 @@ import dbus.decorators
import gobject
import gtk
import logging
-from sugar.graphics.menu import Menu
-from gettext import gettext as _
import os
+from gettext import gettext as _
+
+import hippo
+from sugar.graphics.menu import Menu
+from sugar.graphics import style
+from sugar.graphics.iconcolor import IconColor
+from sugar.graphics.timeline import Timeline
+from bubble import Bubble
import nminfo
@@ -106,18 +112,13 @@ class Network(gobject.GObject):
return self._valid
def add_to_menu(self, menu):
- item = gtk.CheckMenuItem()
strength = self._strength
if strength > 100:
strength = 100
elif strength < 0:
strength = 0
- label_str = "%s (%d%%)" % (self._ssid, strength)
- label = gtk.Label(label_str)
- label.set_alignment(0.0, 0.5)
- item.add(label)
- item.show_all()
- menu.add(item)
+ item = NetworkMenuItem(text=self._ssid, percent=strength)
+ menu.add_item(item)
class Device(gobject.GObject):
@@ -188,14 +189,8 @@ class Device(gobject.GObject):
del self._networks[net_op]
def _add_to_menu_wired(self, menu):
- item = gtk.CheckMenuItem()
- label = gtk.Label(_("Wired Network"))
- label.set_alignment(0.0, 0.5);
- item.add(label)
- if self._caps & NM_DEVICE_CAP_CARRIER_DETECT:
- item.set_sensitive(self._link)
- item.show_all()
- menu.add(item)
+ item = NetworkMenuItem(_("Wired Network"))
+ menu.add_item(item)
def _add_to_menu_wireless(self, menu):
for net in self._networks.values():
@@ -270,22 +265,42 @@ class Device(gobject.GObject):
def set_carrier(self, on):
self._link = on
-class ActivityMenu(Menu):
- def __init__(self, activity_host):
- Menu.__init__(self, activity_host.get_title())
- if not activity_host.get_shared():
- self._add_mesh_action()
+class NetworkMenuItem(Bubble):
+ def __init__(self, text, percent=0):
+ color = IconColor("#646464,#646464")
+ Bubble.__init__(self, color=color, percent=percent)
+
+ text_item = hippo.CanvasText(text=text)
+ style.apply_stylesheet(text_item, 'menu.Text')
+ self.append(text_item)
+
+
+class NetworkMenu(gtk.Window):
+ __gsignals__ = {
+ 'action': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([int])),
+ }
+
+ def __init__(self):
+ gtk.Window.__init__(self, gtk.WINDOW_POPUP)
+
+ canvas = hippo.Canvas()
+ self.add(canvas)
+ canvas.show()
+
+ self._root = hippo.CanvasBox()
+ style.apply_stylesheet(self._root, 'menu')
+ canvas.set_root(self._root)
- self._add_close_action()
+ def add_separator(self):
+ separator = hippo.CanvasBox()
+ style.apply_stylesheet(separator, 'menu.Separator')
+ self._root.append(separator)
- def _add_mesh_action(self):
- icon = CanvasIcon(icon_name='stock-share-mesh')
- self.add_action(icon, ActivityMenu.ACTION_SHARE)
+ def add_item(self, item):
+ self._root.append(item)
- def _add_close_action(self):
- icon = CanvasIcon(icon_name='stock-close')
- self.add_action(icon, ActivityMenu.ACTION_CLOSE)
NM_STATE_UNKNOWN = 0
@@ -304,7 +319,6 @@ ICON_WIRELESS_81_100 = "stock-net-wireless-81-100"
class NMClientApp:
def __init__(self):
- self.menu = None
self.nminfo = None
self._nm_present = False
self._nm_state = NM_STATE_UNKNOWN
@@ -313,6 +327,13 @@ class NMClientApp:
self._active_device = None
self._devices = {}
+ self._menu = None
+ self._hover_menu = False
+ self._timeline = Timeline(self)
+ self._timeline.add_tag('popup', 6, 6)
+ self._timeline.add_tag('before_popdown', 7, 7)
+ self._timeline.add_tag('popdown', 8, 8)
+
self._icons = {}
self._cur_icon = None
@@ -400,24 +421,61 @@ class NMClientApp:
def _setup_trayicon(self):
pixbuf = self._get_icon()
self._trayicon = gtk.status_icon_new_from_pixbuf(pixbuf)
- self._trayicon.connect("popup_menu", self._popup)
- self._trayicon.connect("activate", self._popup)
+ self._trayicon.connect("popup_menu", self._status_icon_clicked)
+ self._trayicon.connect("activate", self._status_icon_clicked)
self._schedule_icon_update()
- def _popup(self, status, button=0, time=None):
- def menu_pos(menu):
- return gtk.status_icon_position_menu(menu, self._trayicon)
+ def _status_icon_clicked(self, button=0, time=None):
+ self._timeline.play(None, 'popup')
+
+ def _get_menu_position(self, menu, item):
+ (screen, rect, orientation) = item.get_geometry()
+ [item_x, item_y, item_w, item_h] = rect
+ [menu_w, menu_h] = menu.size_request()
+
+ x = item_x + item_w - menu_w
+ y = item_y + item_h
+
+ x = min(x, screen.get_width() - menu_w)
+ x = max(0, x)
- if time is None:
- time = gtk.get_current_event_time()
- if self.menu:
- del self.menu
- self.menu = self._construct_new_menu()
- self.menu.popup(None, None, menu_pos, button, time)
- self.menu.show_all()
+ y = min(y, screen.get_height() - menu_h)
+ y = max(0, y)
+
+ return (x, y)
+
+ def do_popup(self, current, n_frames):
+ if self._menu:
+ self._popdown()
+ return
- def _construct_new_menu(self):
- menu = gtk.Menu()
+ self._menu = self._create_menu()
+ self._menu.connect('enter-notify-event',
+ self._menu_enter_notify_event_cb)
+ self._menu.connect('leave-notify-event',
+ self._menu_leave_notify_event_cb)
+ (x, y) = self._get_menu_position(self._menu, self._trayicon)
+ self._menu.move(x, y)
+ self._menu.show_all()
+
+ def do_popdown(self, current, frame):
+ if self._menu:
+ self._menu.destroy()
+ self._menu = None
+
+ def _popdown(self):
+ self._timeline.play('popdown', 'popdown')
+
+ def _menu_enter_notify_event_cb(self, widget, event):
+ self._hover_menu = True
+ self._timeline.play('popup', 'popup')
+
+ def _menu_leave_notify_event_cb(self, widget, event):
+ self._hover_menu = False
+ self._popdown()
+
+ def _create_menu(self):
+ menu = NetworkMenu()
# Wired devices first
for dev in self._devices.values():
@@ -427,6 +485,8 @@ class NMClientApp:
continue
dev.add_to_menu(menu)
+ menu.add_separator()
+
# Wireless devices second
for dev in self._devices.values():
if not dev.is_valid():