Merge lp:~kylehuff/awn-extras/0.4-bandwidth-monitor into lp:~awn-extras/awn-extras/extras-trunk-rewrite-and-random-breakage

Proposed by Kyle L. Huff
Status: Merged
Approved by: Mark Lee
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~kylehuff/awn-extras/0.4-bandwidth-monitor
Merge into: lp:~awn-extras/awn-extras/extras-trunk-rewrite-and-random-breakage
Diff against target: 1546 lines (+1481/-0)
10 files modified
applets/Makefile.am (+1/-0)
applets/maintained/bandwidth-monitor/CHANGELOG (+126/-0)
applets/maintained/bandwidth-monitor/Makefile.am (+16/-0)
applets/maintained/bandwidth-monitor/TODO (+19/-0)
applets/maintained/bandwidth-monitor/awn-applet-bandwidth-monitor.schema-ini (+40/-0)
applets/maintained/bandwidth-monitor/awn-bwm.py (+688/-0)
applets/maintained/bandwidth-monitor/bandwidth-monitor.desktop.in.in (+11/-0)
applets/maintained/bandwidth-monitor/bandwidth-monitor.ui (+300/-0)
applets/maintained/bandwidth-monitor/bwmprefs.py (+278/-0)
configure.ac (+2/-0)
To merge this branch: bzr merge lp:~kylehuff/awn-extras/0.4-bandwidth-monitor
Reviewer Review Type Date Requested Status
Mark Lee Approve
Michal Hruby (community) Approve
Review via email: mp+16747@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Mark Lee (malept) wrote :

> +Version=0.3.9.2

That's not what the Version key is for. Please see <http://standards.freedesktop.org/desktop-entry-spec/1.0/ar01s05.html>.

review: Needs Fixing (desktop file)
Revision history for this message
Michal Hruby (mhr3) wrote :

After looking over the repaint() method I see that the applet doesn't properly support side orientations, which is very bad, I know that you display text on the icon and it's pretty hard to deal with this when using side orientations, but the options I see are:
1) rotate the whole icon 90 degrees and display the text vertically
2) use smaller text size when using side orientation, so there's no need to have the icon wider than width of the panel
3) display only the graph when using side orient and don't show the overlay

review: Needs Fixing (orientation-support)
Revision history for this message
Mark Lee (malept) wrote :

> + i = 0
[...]
> + for device_pref in prefs:
> + dpv = device_pref.split("|")
> + if dpv[0] == model[path][0]:
> + ''' If the current column is 1 or 2, it is a checkbox,
> + so transpose from bool to int '''
> + dpv[col_number] = parameter
> + prefs[i] = "%s|%s|%s|%s|%s" % (dpv[0], dpv[1], dpv[2], dpv[3], dpv[4])
> + i += 1

Because I'm a pedant, this could be rewritten as follows:

for i, device_pref in enumerate(prefs):
    dpv = device_pref.split('|')
    if dpv[0] == model[path][0]:
        ''' If the current column is 1 or 2, it is a checkbox,
        so transpose from bool to int '''
        dpv[col_number] = parameter
        prefs[i] = '|'.join(dpv)

Revision history for this message
Mark Lee (malept) wrote :

+ gobject.timeout_add(1000, self.update_net_stats)

You should use gobject.timeout_add_seconds when possible. See <http://live.gnome.org/GnomeGoals/UseTimeoutAddSeconds>.

An example of backwards-compatible usage in Python is available in the digital-clock applet: <http://bazaar.launchpad.net/~awn-extras/awn-extras/extras-trunk-rewrite-and-random-breakage/annotate/1406/src/digitalClock/digitalClock.py#L42>.

review: Needs Fixing (saving-the-world)
1861. By Kyle L. Huff <kylehuff@slaveduo>

bandwidth monitor applet -
    removed edits to un-related Makefile

1862. By Kyle L. Huff <kylehuff@slaveduo>

bandwidth monitor applet -
    Removed LICENSE file - provided by AWN
    Fixed desktop file version
    Removed "Encoding" from desktop file
    Improved logic for setting device preference values per Mark Lee's suggestion
    Added timeout_add_seconds wrapper function
    Adjusted width calculation if orientation is vertical

Revision history for this message
Kyle L. Huff (kylehuff) wrote :

I have committed fixes for the review items above;

- Desktop file has been corrected
- Correct repaint to account for vertical orientations
- Improvements to the device preference parsing committed
- Changed instances of timeout_add that have a whole-number timeout greater than or equal to 1 to use tmeout_add_seconds

1863. By Kyle L. Huff <kylehuff@slaveduo>

bandwidth monitor applet -
    Change version string to use awn.extras.__version__
    Shortened orientation logic 'if' statement
    Changed email address

1864. By Kyle L. Huff <kylehuff@slaveduo>

bandwidth monitor applet -
    Minor syntax changes
    More vertical orientation fixes (font size)

1865. By Kyle L. Huff <kylehuff@slaveduo>

bandwidth monitor applet -
    Changed loading default settings from applet.settings.load() to applet.settings.load_preferences()

Revision history for this message
Michal Hruby (mhr3) wrote :

Overlay font-size on side orients is fine now, but it doesn't change to the original size when it's switched back to top/bottom orient.

review: Needs Fixing (orientation-support)
1866. By Kyle L. Huff <kylehuff@slaveduo>

bandwidth monitor applet -
   Removed settings.load/load_preferences
   Fix for applet/font-sizing when changing orientation

Revision history for this message
Kyle L. Huff (kylehuff) wrote :

> Overlay font-size on side orients is fine now, but it doesn't change to the
> original size when it's switched back to top/bottom orient.

This should be fixed in r1866

1867. By Kyle L. Huff <kylehuff@slaveduo>

bandwidth monitor applet -
    Changed instantiation of color objects to use gtk.gdk.color_parse instead of gtk.gdk.Color('#XXX') for older systems
    Changed handling of default preferences/unassigned keys

Revision history for this message
Michal Hruby (mhr3) wrote :

No more blocking problems from my side, though I did notice that on my system the redrawing doesn't feel smooth, it's like it updates every second, but from time to time it completely skips a frame. Anyone else seeing this?

review: Approve
1868. By Kyle L. Huff <kylehuff@slaveduo>

bandwidth monitor applet -
    PEP8 cleanup of all lines > 80 chars
    Rename of classes/variables for space/consistency
    Change of timer values for consistent drawing.
    Removed some unused modules.
    Removed 'blank.png' - initial icon is now created with gtk.gdk.pixbuf_new_from_xpm_data()

1869. By Kyle L. Huff <kylehuff@slaveduo>

bandwidth monitor applet -
    Removed reference to blank.png from Makefile.am

Revision history for this message
Mark Lee (malept) wrote :

Here's some things that I noted in my last round of reviewing the merge request:
* what are the valid values for ``DEFAULT/unit``? Presumably (currently) deals with bits vs. bytes? This should probably be documented in the description.
* is ``DEFAULT/draw_threshold`` dependent upon ``DEFAULT/unit``?
* I don't remember if you had problems with desktopagnostic.Color, but you can use that in place of #abcdef|0.5 config values
* something to think about post-merge, pre-0.4.0: i18n (gettext) / l10n support
* bwmprefs.py doesn't need the shebang (``#!``) line
* update your copyright statements to 2010 :)

review: Needs Fixing (minor)
Revision history for this message
Mark Lee (malept) wrote :

> Here's some things that I noted in my last round of reviewing the merge
> request:
> * what are the valid values for ``DEFAULT/unit``? Presumably (currently) deals
> with bits vs. bytes? This should probably be documented in the description.
> * is ``DEFAULT/draw_threshold`` dependent upon ``DEFAULT/unit``?
> * I don't remember if you had problems with desktopagnostic.Color, but you can
> use that in place of #abcdef|0.5 config values
> * something to think about post-merge, pre-0.4.0: i18n (gettext) / l10n
> support
> * bwmprefs.py doesn't need the shebang (``#!``) line
> * update your copyright statements to 2010 :)

I've handled everything except the desktopagnostic.Color point in my branch:
lp:~awn-extras/awn-extras/0.4-bwm-minor-fixes

I've also fixed a typo and a small error in the build system.

Please review and merge into your branch :)

Revision history for this message
Mark Lee (malept) wrote :

In order to speed up the "Merge 0.4 into trunk" task, I'm approving this merge (specifically, of my modified branch of awn-bwm) and adding Kyle to awn-extras so that he can potentially fix any of the bugs I introduced in my branch, in addition to the usual maintainership responsibilities :)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'applets/Makefile.am'
--- applets/Makefile.am 2009-11-15 21:40:13 +0000
+++ applets/Makefile.am 2010-01-16 19:06:14 +0000
@@ -52,6 +52,7 @@
52SUBDIRS = \52SUBDIRS = \
53 maintained/animal-farm \53 maintained/animal-farm \
54 maintained/awnterm \54 maintained/awnterm \
55 maintained/bandwidth-monitor \
55 maintained/battery \56 maintained/battery \
56 maintained/cairo-clock \57 maintained/cairo-clock \
57 maintained/comics \58 maintained/comics \
5859
=== added directory 'applets/maintained/bandwidth-monitor'
=== added file 'applets/maintained/bandwidth-monitor/CHANGELOG'
--- applets/maintained/bandwidth-monitor/CHANGELOG 1970-01-01 00:00:00 +0000
+++ applets/maintained/bandwidth-monitor/CHANGELOG 2010-01-16 19:06:14 +0000
@@ -0,0 +1,126 @@
101/05/2010:
2 PEP8 cleanup of all lines > 80 chars
3 Rename of classes/variables for space/consistency
4 Change of timer values for consistent drawing.
5 Removed some unused modules.
6 Removed 'blank.png' - initial icon is now created with gtk.gdk.pixbuf_new_from_xpm_data()
7
801/03/2010:
9 Removed settings.load/load_preferences
10 Fix for applet/font-sizing when changing orientation
11 Changed instantiation of color objects to use gtk.gdk.color_parse instead of gtk.gdk.Color('#XXX') for older systems
12 Changed handling of default preferences/unassigned keys
13
14
1501/02/2010:
16 Fixed bug which caused the unit of measure checkbutton to become out of sync with the gconf value
17 Changed default interface to '', was wlan0 for some reason..
18 PEP8 verified - mostly complaint, a few lines are "too long"
19 Replaced icon
20 Removed LICENSE file - provided by AWN
21 Fixed desktop file version
22 Removed "Encoding" from desktop file
23 Improved logic for setting device preference values per Mark Lee's suggestion
24 Added timeout_add_seconds wrapper function
25 Adjusted width calculation if orientation is vertical
26 Change version string to use awn.extras.__version__
27 Changed email address
28
2912/20/2009:
30 Change logic to graph calculation which corrects the following rendering issues -
31 Graph lines drawing outside of border/frame
32 Graph normalised top-value was rendering off-screen when applet size smaller than 35
33 Graph normalised top-value was rendering very low on the graph when applet size greater than 60
34 Changed scaling of initial icon - it was rendering too large and centered text was displayed with an odd alignment to the dock
35 Fixed some issues with default values
36 Changed short-name to 'bandwidth-monitor' to match schema file
37 Corrected path to UI file
38 Fixed division by zero error
39 Addedd bandwidth-monitor.ui and bwmprefs.py to Makefile.am
40
4112/19/2009:
42 Added preferences to control -
43 Enable/Disable drawing of the background
44 Enable/Disable drawing of the border
45 Select color/opacity of background
46 Select color/opacity of border
47 Options to control the text representation of throughput
48 Display Upload/Download text
49 Display Sum text only
50 Do not display text - only draw the graph.
51 Enable/Disable drawing the zero value in the graph (if true, draw a line at the bottom of the graph for zero value)
52
5312/18/2009:
54 Cleaned up code to make it run faster or use less resources
55 Removed everything related to the status of interfaces (Not required, may add later)
56 Removed everything related to IP Addresses for interfaces (Not required, may add later)
57
5812/16/2009:
59 Added call to applet.errors.general if read access to /proc/net/dev fails.
60 Made changes to TODO file
61 Change parser logic for to handle interfaces with less than 11 columns of output in 'netstat -iea'
62
6312/14/2009:
64 Created preferences dialog to manage options -
65 An option to select the unit Bytes/bits
66 A spinbutton entry for setting the minimum threshold
67 A "Devices" pref-pane which allows selection of interfaces into virtual interfaces
68 A color picker for upload and download colors for use in the line-graph.
69 Fixed division by zero that would occur in some scenarios.
70
7112/10/2009:
72 Added virtual interfaces for SUM and MULTI
73 The Sum Interface is a virtual interface which displays the sum throughput of all interfaces that are selected for "Sum"
74 The Multi Interface is a virtual interface which displays each individual throughput of the interfaces that are selected for "Multi", each with the colors defined for the interface.
75 Added logic to parse and use preferences that are planned
76
7711/29/2009:
78 Changed table generation function to be less verbose
79 Fixed regular expression for gathering IP/Netmask
80 Changed IP/Netmask tooltip logic
81 Changed command for device stats gathering to include administratively down-interfaces
82
8311/28/2009:
84 pep8 verified main program file
85 Added a few non-parsed comments to the source file
86
8711/28/2009:
88 Changed initial ratio value to 1 to prevent the graphs from ignoring data transfers below 3200 bytes
89 Changed the graph scaling to display the line graph almost center of the graph window below 6400 bytes
90 Added items to the TODO list
91
9211/27/2009:
93 Filter out the wmaster0 interface.
94 Applied patch from onox:
95 Renamed some classes
96 Removed functions for things abstracted by AWN
97 Cleaned up some of the syntax
98 Cleaned up some naming conventions
99 Created a new branch repository (previous was setup wrong): lp:~kylehuff/awn-extras/0.4-bandwidth-monitor
100
10111/27/2009:
102 Applied patch from mhr3 which included -
103 Changes to applet short-name
104 Changes to Makefile.am
105 Fixed spelling of "CHANGLOG" to "CHANGELOG"
106 Renamed awn-bwm.schema-ini to awn-applet-bwm.schema-ini
107 Changed the application of the cairo surface to use applet.set_icon_context()
108 Fixed bug which caused rendering the scale of the upload speed off-screen
109 Removed references to some obsolete functions/methods/properties
110
11111/25/2009:
112 Eliminated usage of 'ifconfig' command - moved everything to netstat
113 Bumped to version v0.3.9.2
114 Created launchpad branch - lp:~kylehuff/awn-extras/awn-bwm
115
11611/24/2009:
117 Converted text to OverlayText()
118 Cleaned up some functions
119 Bumped version to v0.3.9.1
120
12111/23/2009:
122 Implemented API v0.4
123 Changed from v0.3.2.8 to v0.3.9.0
124
12504/18/2006:
126 Original release - 0.1
0127
=== added file 'applets/maintained/bandwidth-monitor/Makefile.am'
--- applets/maintained/bandwidth-monitor/Makefile.am 1970-01-01 00:00:00 +0000
+++ applets/maintained/bandwidth-monitor/Makefile.am 2010-01-16 19:06:14 +0000
@@ -0,0 +1,16 @@
1APPLET_NAME = bandwidth-monitor
2APPLET_MAIN_FILE = awn-bwm.py
3include $(top_srcdir)/Makefile.python-applet
4include $(top_srcdir)/Makefile.schemas
5
6dist_applet_DATA = \
7 CHANGELOG \
8 bwmprefs.py \
9 bandwidth-monitor.ui \
10 $(NULL)
11
12bwm_iconsdir = $(applet_datadir)/images
13dist_bwm_icons_DATA = \
14 images/icon.png \
15 $(NULL)
16
017
=== added file 'applets/maintained/bandwidth-monitor/TODO'
--- applets/maintained/bandwidth-monitor/TODO 1970-01-01 00:00:00 +0000
+++ applets/maintained/bandwidth-monitor/TODO 2010-01-16 19:06:14 +0000
@@ -0,0 +1,19 @@
1TODO:
2
3--- Things that need to happen ---
4None Left...
5
6--- Things I would like ---
7Add preference control for applying effect to text (new default = True, always apply)
8Auto select interface (maybe based on default route)
9Add toggle for enable/disable auto-scaling (so 100Mbps would draw the line at the top of the meter)
10
11--- Completed TODO's ---
12Create preference dialog for selecting the color of the line-graphs, as well as the background
13 Done
14Ability to select multiple (or all) devices for a sum throughput -
15 Done (also created 'multi' interface)
16Add preference for specifying minimum threshold for charting data
17 Done
18
19
020
=== added file 'applets/maintained/bandwidth-monitor/awn-applet-bandwidth-monitor.schema-ini'
--- applets/maintained/bandwidth-monitor/awn-applet-bandwidth-monitor.schema-ini 1970-01-01 00:00:00 +0000
+++ applets/maintained/bandwidth-monitor/awn-applet-bandwidth-monitor.schema-ini 2010-01-16 19:06:14 +0000
@@ -0,0 +1,40 @@
1[DEFAULT/unit]
2type = integer
3default = 0
4description = The display unit for transfer speed
5[DEFAULT/interface]
6type = string
7default =
8description = The interface currently selected
9[DEFAULT/draw_threshold]
10type = float
11default = 0.0
12description = Minimum threshold to draw meter
13[DEFAULT/device_display_parameters]
14type = list-string
15default = ;
16description = Display parameters for interfaces
17[DEFAULT/background]
18type = boolean
19default = true
20description = Draw the applet background
21[DEFAULT/background_color]
22type = string
23default = #000000|0.5
24description = Color to draw the background
25[DEFAULT/border]
26type = boolean
27default = false
28description = Draw the applet border
29[DEFAULT/border_color]
30type = string
31default = #000000|1.0
32description = Color to draw the border
33[DEFAULT/label_control]
34type = integer
35default = 2
36description = Throughput label control - 0 = no label, 1 = Sum, 2 = Upload/Download
37[DEFAULT/graph_zero]
38type = integer
39default = 0
40description = If enabled this will draw a line at the bottom of the graph even if the value is 0. If unchecked, values below 1 are not drawn
041
=== added file 'applets/maintained/bandwidth-monitor/awn-bwm.py'
--- applets/maintained/bandwidth-monitor/awn-bwm.py 1970-01-01 00:00:00 +0000
+++ applets/maintained/bandwidth-monitor/awn-bwm.py 2010-01-16 19:06:14 +0000
@@ -0,0 +1,688 @@
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3"""
4bandwidth-monitor - Network bandwidth monitor.
5Copyright (c) 2006-2009 Kyle L. Huff (awn-bwm@curetheitch.com)
6url: <http://www.curetheitch.com/projects/awn-bwm/>
7Email: awn-bwm@curetheitch.com
8
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/gpl.txt>.
21"""
22
23from time import time
24import os
25import re
26import sys
27
28
29import gtk
30import awn
31
32from awn.extras import awnlib, __version__
33import gobject
34import cairo
35import bwmprefs
36
37APPLET_NAME = "Bandwidth Monitor"
38APPLET_VERSION = "0.3.9.3"
39APPLET_COPYRIGHT = "© 2006-2009 CURE|THE|ITCH"
40APPLET_AUTHORS = ["Kyle L. Huff <awn-bwm@curetheitch.com>"]
41APPLET_DESCRIPTION = "Network Bandwidth monitor"
42APPLET_WEBSITE = "http://www.curetheitch.com/projects/awn-bwm/"
43APPLET_PATH = os.path.dirname(sys.argv[0])
44APPLET_ICON = APPLET_PATH + "/images/icon.png"
45UI_FILE = os.path.join(os.path.dirname(__file__), "bandwidth-monitor.ui")
46
47
48class Netstat:
49
50 def __init__(self, parent, unit):
51 self.parent = parent
52 self.ifaces = {}
53 self.ifaces["Sum Interface"] = {"collection_time": 0,
54 "status": "V",
55 "prbytes": 0,
56 "ptbytes": 0,
57 "index": 1,
58 "rx_history": [0, 0],
59 "tx_history": [0, 0],
60 "rx_bytes": 0,
61 "tx_bytes": 0,
62 "rx_sum": 0,
63 "tx_sum": 0,
64 "rxtx_sum": 0,
65 "rabytes": 0,
66 "tabytes": 0,
67 'sum_include': False,
68 'multi_include': False,
69 'upload_color': "#ff0000",
70 'download_color': "#ffff00"}
71 self.ifaces["Multi Interface"] = {"collection_time": 0,
72 "status": "V",
73 "prbytes": 0,
74 "ptbytes": 0,
75 "index": 1,
76 "rx_history": [0, 0],
77 "tx_history": [0, 0],
78 "rx_bytes": 0,
79 "tx_bytes": 0,
80 "rx_sum": 0,
81 "tx_sum": 0,
82 "rxtx_sum": 0,
83 "rabytes": 0,
84 "tabytes": 0,
85 'sum_include': False,
86 'multi_include': False}
87 self.regenerate = False
88 self.update_net_stats()
89 gobject.timeout_add(800, self.update_net_stats)
90
91 def timeout_add_seconds(self, seconds, callback):
92 if hasattr(gobject, 'timeout_add_seconds'):
93 return gobject.timeout_add_seconds(seconds, callback)
94 else:
95 return gobject.timeout_add(seconds * 1000, callback)
96
97 def update_net_stats(self):
98 ifcfg_str = os.popen("netstat -eia").read()
99 if ifcfg_str:
100 ifcfg_str = ifcfg_str.split("\n\n")
101 stat_str = "n"
102 devices = []
103 ''' Reset the Sum Interface records to zero '''
104 self.ifaces["Sum Interface"]["rx_sum"] = 0
105 self.ifaces["Sum Interface"]["tx_sum"] = 0
106 self.ifaces["Sum Interface"]["rx_bytes"] = 0
107 self.ifaces["Sum Interface"]["tx_bytes"] = 0
108 sum_rx_history = 0.0
109 sum_tx_history = 0.0
110 ''' Reset the Multi Interface records to zero '''
111 self.ifaces["Multi Interface"]["rx_sum"] = 0
112 self.ifaces["Multi Interface"]["tx_sum"] = 0
113 self.ifaces["Multi Interface"]["rx_bytes"] = 0
114 self.ifaces["Multi Interface"]["tx_bytes"] = 0
115 multi_rx_history = 0.0
116 multi_tx_history = 0.0
117 if ifcfg_str and stat_str:
118 for device_group in ifcfg_str:
119 device_lines = device_group.split("\n")
120 if "Kernel" in device_lines[0]:
121 device_lines = device_lines[1:]
122 iface = re.split('[\W]+',
123 device_lines[0].strip().replace(":", "_"))[0]
124 if len(device_lines) > 2:
125 try:
126 rx_bytes = float(re.search(r'RX bytes:(\d+)\D',
127 device_group).group(1))
128 tx_bytes = float(re.search(r'TX bytes:(\d+)\D',
129 device_group).group(1))
130 except:
131 rx_bytes = 0
132 tx_bytes = 0
133 if not iface in self.ifaces:
134 ddps = "device_display_parameters"
135 prefs = self.parent.applet.settings[ddps]
136 sum_include = True
137 multi_include = True
138 for device_pref in prefs:
139 dpv = device_pref.split("|")
140 if dpv[0] == iface:
141 sum_include = str(dpv[1])[0].upper() == 'T'
142 multi_include = str(dpv[2])[0].upper() == 'T'
143 self.ifaces[iface] = {"collection_time": time(),
144 "status": None,
145 "prbytes": rx_bytes,
146 "ptbytes": tx_bytes,
147 "index": 1,
148 "rx_history": [0, 0],
149 "tx_history": [0, 0],
150 "sum_include": sum_include,
151 'multi_include': multi_include,
152 'upload_color': \
153 self.parent.prefs.get_color(iface, "upload"),
154 'download_color': \
155 self.parent.prefs.get_color(iface, "download")}
156 collection = (
157 time() - self.ifaces[iface]["collection_time"])
158 rbytes = ((rx_bytes - self.ifaces[iface]["prbytes"])
159 * self.parent.unit) / collection
160 tbytes = ((tx_bytes - self.ifaces[iface]["ptbytes"])
161 * self.parent.unit) / collection
162 rabytes = (rx_bytes - self.ifaces[iface]["prbytes"]) \
163 / collection
164 tabytes = (tx_bytes - self.ifaces[iface]["ptbytes"]) \
165 / collection
166 self.ifaces[iface]["rabytes"] = rabytes
167 self.ifaces[iface]["tabytes"] = tabytes
168 rxtx_sum = rx_bytes + tx_bytes
169 if self.ifaces[iface]['sum_include']:
170 self.ifaces["Sum Interface"]["rx_sum"] += rx_bytes
171 self.ifaces["Sum Interface"]["tx_sum"] += tx_bytes
172 self.ifaces["Sum Interface"]["rx_bytes"] += rbytes
173 self.ifaces["Sum Interface"]["tx_bytes"] += tbytes
174 sum_rx_history += rabytes
175 sum_tx_history += tabytes
176 if self.ifaces[iface]['multi_include']:
177 self.ifaces["Multi Interface"]["rx_sum"] += rx_bytes
178 self.ifaces["Multi Interface"]["tx_sum"] += tx_bytes
179 self.ifaces["Multi Interface"]["rx_bytes"] += rbytes
180 self.ifaces["Multi Interface"]["tx_bytes"] += tbytes
181 multi_rx_history += rabytes
182 multi_tx_history += tabytes
183 ifstatus = "BRMU"
184 self.ifaces[iface]["rx_bytes"] = rbytes
185 self.ifaces[iface]["tx_bytes"] = tbytes
186 self.ifaces[iface]["prbytes"] = rx_bytes
187 self.ifaces[iface]["ptbytes"] = tx_bytes
188 self.ifaces[iface]["rx_sum"] = rx_bytes
189 self.ifaces[iface]["tx_sum"] = tx_bytes
190 self.ifaces[iface]["rxtx_sum"] = rxtx_sum
191 self.ifaces[iface]["status"] = ifstatus
192 self.ifaces[iface]["collection_time"] = time()
193 offset = self.parent.meter_scale - 1 \
194 if self.parent.border else self.parent.meter_scale
195 self.ifaces[iface]["rx_history"] = \
196 self.ifaces[iface]["rx_history"][0 - offset:]
197 self.ifaces[iface]["rx_history"].append(
198 self.ifaces[iface]["rabytes"])
199 self.ifaces[iface]["tx_history"] = \
200 self.ifaces[iface]["tx_history"][0 - offset:]
201 self.ifaces[iface]["tx_history"].append(
202 self.ifaces[iface]["tabytes"])
203 devices.append(iface)
204 self.ifaces["Sum Interface"]["rx_history"] = \
205 self.ifaces["Sum Interface"]["rx_history"][0 - offset:]
206 self.ifaces["Sum Interface"]["rx_history"].append(sum_rx_history)
207 self.ifaces["Sum Interface"]["tx_history"] = \
208 self.ifaces["Sum Interface"]["tx_history"][0 - offset:]
209 self.ifaces["Sum Interface"]["tx_history"].append(sum_tx_history)
210 for dev in self.ifaces.keys():
211 if not dev in devices and not "Sum Interface" in dev \
212 and not "Multi Interface" in dev:
213 ''' The device does not exist, remove it.
214 del dictionary[key] is faster than dictionary.pop(key) '''
215 del self.ifaces[dev]
216 self.regenerate = True
217 return True
218
219
220class AppletBandwidthMonitor:
221
222 def __init__(self, applet):
223 ''' Test if user has access to /proc/net/dev '''
224 if not os.access('/proc/net/dev', os.R_OK):
225 applet.errors.general(('Unable to caclulate statistics',
226 'Statistics calculation requires read access to /proc/net/dev'))
227 applet.errors.set_error_icon_and_click_to_restart()
228 return None
229 self.applet = applet
230 self.UI_FILE = UI_FILE
231 applet.tooltip.set("Bandwidth Monitor")
232 self.meter_scale = 25
233 icon = gtk.gdk.pixbuf_new_from_xpm_data(["1 1 1 1",
234 " c #000",
235 " "])
236 height = self.applet.get_size() * 1.5
237 if height != icon.get_height():
238 icon = icon.scale_simple(int(height), \
239 int(height / 1.5), gtk.gdk.INTERP_BILINEAR)
240 self.applet.set_icon_pixbuf(icon)
241 self.dialog = applet.dialog.new("main")
242 self.vbox = gtk.VBox()
243 self.dialog.add(self.vbox)
244 button = gtk.Button("Change Unit")
245 self.dialog.add(button)
246 defaults = {'unit': 8,
247 'interface': '',
248 'draw_threshold': 0.0,
249 'device_display_parameters': [],
250 'background': True,
251 'background_color': "#000000|0.5",
252 'border': False,
253 'border_color': "#000000|1.0",
254 'label_control': 2,
255 'graph_zero': 0}
256 for key, value in defaults.items():
257 if not key in self.applet.settings:
258 self.applet.settings[key] = value
259 self.iface = self.applet.settings['interface']
260 self.unit = self.applet.settings['unit']
261 self.label_control = self.applet.settings["label_control"]
262 self.background = self.applet.settings['background']
263 self.background_color = self.applet.settings['background_color']
264 self.border = self.applet.settings['border']
265 self.border_color = self.applet.settings['border_color']
266 self.graph_zero = self.applet.settings['graph_zero']
267 if not self.unit:
268 self.change_unit(defaults['unit'])
269 if self.applet.settings['draw_threshold'] == 0.0:
270 self.ratio = 1
271 else:
272 ratio = self.applet.settings['draw_threshold']
273 self.ratio = ratio * 1024 if self.unit == 1 else ratio * 1024 / 8
274 self.prefs = bwmprefs.Preferences(self.applet, self)
275 self.netstats = Netstat(self, self.unit)
276 applet.tooltip.connect_becomes_visible(self.enter_notify)
277 self.table = self.generate_table()
278 self.vbox.add(self.table)
279 self.upload_ot = awn.OverlayText()
280 self.download_ot = awn.OverlayText()
281 self.sum_ot = awn.OverlayText()
282 self.upload_ot.props.gravity = gtk.gdk.GRAVITY_NORTH
283 self.download_ot.props.gravity = gtk.gdk.GRAVITY_SOUTH
284 self.sum_ot.props.gravity = gtk.gdk.GRAVITY_NORTH
285 applet.add_overlay(self.upload_ot)
286 applet.add_overlay(self.download_ot)
287 applet.add_overlay(self.sum_ot)
288 self.default_font_size = self.upload_ot.props.font_sizing
289 self.upload_ot.props.y_override = 4
290 self.download_ot.props.y_override = 18
291 self.sum_ot.props.y_override = 11
292 self.upload_ot.props.apply_effects = True
293 self.download_ot.props.apply_effects = True
294 self.sum_ot.props.apply_effects = True
295 self.upload_ot.props.text = "Scanning"
296 self.download_ot.props.text = "Devices"
297 self.prefs.setup()
298 ''' connect the left-click dialog button "Change Unit" to
299 the call_change_unit function, which does not call
300 self.change_unit directly, instead it toggles the "active"
301 property of the checkbutton so everything that needs to
302 happen, happens. '''
303 button.connect("clicked", self.call_change_unit)
304 gobject.timeout_add(100, self.first_paint)
305 gobject.timeout_add(800, self.subsequent_paint)
306
307 def change_draw_ratio(self, widget):
308 ratio = widget.get_value()
309 self.ratio = ratio * 1024 if self.unit == 1 else ratio * 1024 / 8
310 self.applet.settings["draw_threshold"] = ratio
311
312 def call_change_unit(self, *args):
313 if self.unit == 8:
314 self.prefs.uomCheckbutton.set_property('active', True)
315 else:
316 self.prefs.uomCheckbutton.set_property('active', False)
317
318 def change_unit(self, widget=None, scaleThresholdSBtn=None, label=None):
319 self.unit = 8 if self.unit == 1 else 1
320 ''' normalize and update the label, and normalize the spinbutton '''
321 if label:
322 if self.unit == 1:
323 label.set_text("KBps")
324 scaleThresholdSBtn.set_value(
325 self.applet.settings["draw_threshold"] / 8)
326 else:
327 label.set_text("Kbps")
328 scaleThresholdSBtn.set_value(
329 self.applet.settings["draw_threshold"] * 8)
330 self.applet.settings["unit"] = self.unit
331
332 def change_iface(self, widget, iface):
333 if widget.get_active():
334 ''' Changed to interface %s" % iface '''
335 self.iface = iface
336 self.applet.settings["interface"] = iface
337
338 def generate_table(self):
339 table = gtk.Table(100, 100, False)
340 col_iter = 0
341 row_iter = 2
342 for i in [0, 1, 2, 3, 4, 5, 6]:
343 table.set_col_spacing(i, 20)
344 table.attach(gtk.Label(""),
345 0, 1, 0, 1,
346 xoptions=gtk.EXPAND | gtk.FILL,
347 yoptions=gtk.EXPAND | gtk.FILL,
348 xpadding=0, ypadding=0)
349 table.attach(gtk.Label("Interface"),
350 1, 2, 0, 1,
351 xoptions=gtk.EXPAND | gtk.FILL,
352 yoptions=gtk.EXPAND | gtk.FILL,
353 xpadding=0, ypadding=0)
354 table.attach(gtk.Label("Sent"),
355 2, 3, 0, 1,
356 xoptions=gtk.EXPAND | gtk.FILL,
357 yoptions=gtk.EXPAND | gtk.FILL,
358 xpadding=0, ypadding=0)
359 table.attach(gtk.Label("Received"),
360 3, 4, 0, 1,
361 xoptions=gtk.EXPAND | gtk.FILL,
362 yoptions=gtk.EXPAND | gtk.FILL,
363 xpadding=0, ypadding=0)
364 table.attach(gtk.Label("Sending"),
365 4, 5, 0, 1,
366 xoptions=gtk.EXPAND | gtk.FILL,
367 yoptions=gtk.EXPAND | gtk.FILL,
368 xpadding=0, ypadding=0)
369 table.attach(gtk.Label("Receiving"),
370 5, 6, 0, 1,
371 xoptions=gtk.EXPAND | gtk.FILL,
372 yoptions=gtk.EXPAND | gtk.FILL,
373 xpadding=0, ypadding=0)
374 radio = None
375 for iface in sorted(self.netstats.ifaces):
376 widget = gtk.Label()
377 widget.toggle = gtk.RadioButton(group=radio)
378 radio = widget.toggle
379 if iface == self.iface:
380 widget.toggle.set_active(True)
381 widget.toggle.connect("clicked", self.change_iface, iface)
382 widget.name_label = gtk.Label(str(iface))
383 widget.sent_label = gtk.Label(str(
384 readable_speed(self.netstats.ifaces[iface]["tx_sum"],
385 self.unit, False).strip()))
386 widget.received_label = gtk.Label(str(
387 readable_speed(self.netstats.ifaces[iface]["rx_sum"],
388 self.unit, False).strip()))
389 widget.tx_speed_label = gtk.Label(str(
390 readable_speed(self.netstats.ifaces[iface]["tx_bytes"]
391 * self.unit, self.unit).strip()))
392 widget.rx_speed_label = gtk.Label(str(
393 readable_speed(self.netstats.ifaces[iface]["rx_bytes"]
394 * self.unit, self.unit).strip()))
395 self.netstats.ifaces[iface]["widget"] = widget
396 for widget_object in [widget.toggle,
397 widget.name_label,
398 widget.sent_label,
399 widget.received_label,
400 widget.tx_speed_label,
401 widget.rx_speed_label]:
402 table.attach(widget_object,
403 col_iter, col_iter + 1,
404 row_iter, row_iter + 1,
405 xoptions=gtk.EXPAND | gtk.FILL,
406 yoptions=gtk.EXPAND | gtk.FILL,
407 xpadding=0, ypadding=0)
408 col_iter += 1
409 row_iter += 1
410 col_iter = 0
411 return table
412
413 def enter_notify(self):
414 if not self.applet.dialog.is_visible("main"):
415 if not self.iface in self.netstats.ifaces:
416 self.applet.set_tooltip_text(
417 "Please select a valid Network Device")
418 else:
419 self.applet.set_tooltip_text(
420 "Total Sent: %s - Total Received: %s (All Interfaces)" % (
421 readable_speed(
422 self.netstats.ifaces[self.iface]["tx_sum"]
423 * self.unit, self.unit, False),
424 readable_speed(
425 self.netstats.ifaces[self.iface]["rx_sum"]
426 * self.unit, self.unit, False)))
427
428 def first_paint(self):
429 self.repaint()
430 return False
431
432 def subsequent_paint(self):
433 self.repaint()
434 return True
435
436 def draw_background(self, ct, x0, y0, x1, y1, radius):
437 ct.move_to(x0, y0 + radius)
438 ct.curve_to(x0, y0, x0, y0, x0 + radius, y0)
439 ct.line_to(x1 - radius, y0)
440 ct.curve_to(x1, y0, x1, y0, x1, y0 + radius)
441 ct.line_to(x1, y1 - radius)
442 ct.curve_to(x1, y1, x1, y1, x1 - radius, y1)
443 ct.line_to(x0 + radius, y1)
444 ct.curve_to(x0, y1, x0, y1, x0, y1 - radius)
445 ct.close_path()
446
447 def draw_meter(self, ct, width, height, iface, multi=False):
448 ratio = self.ratio
449 ct.set_line_width(2)
450 ''' Create temporary lists to store the values of the transmit
451 and receive history, which will be then placed into the
452 _total_hist and sorted by size to set the proper
453 scale/ratio for the line heights '''
454 _rx_hist = [1]
455 _tx_hist = [1]
456 _total_hist = [1]
457 if not multi:
458 if iface in self.netstats.ifaces \
459 and len(self.netstats.ifaces[iface]["rx_history"]):
460 _rx_hist = self.netstats.ifaces[iface]["rx_history"]
461 if iface in self.netstats.ifaces \
462 and len(self.netstats.ifaces[iface]["tx_history"]):
463 _tx_hist = self.netstats.ifaces[iface]["tx_history"]
464 _total_hist.extend(_rx_hist)
465 _total_hist.extend(_tx_hist)
466 else:
467 for device in self.netstats.ifaces:
468 if self.netstats.ifaces[device]['multi_include']:
469 _total_hist.extend(
470 self.netstats.ifaces[device]["rx_history"])
471 if self.netstats.ifaces[iface]['multi_include']:
472 _total_hist.extend(
473 self.netstats.ifaces[device]["tx_history"])
474 _total_hist.sort()
475 ''' ratio variable controls the minimum threshold for data -
476 i.e. 32000 would not draw graphs for data transfers below
477 3200 bytes - the initial value of ratio if set to the link
478 speed will prevent the graph from scaling. If using the
479 Multi Interface, the ratio will adjust based on the
480 highest throughput metric. '''
481 max_val = _total_hist[-1]
482 ratio = max_val / 28 if max_val > self.ratio else self.ratio
483 ''' Change the color of the upload line to configured/default '''
484 if iface:
485 color = gtk.gdk.color_parse(
486 self.netstats.ifaces[iface]['upload_color'])
487 ct.set_source_rgba(color.red / 65535.0,
488 color.green / 65535.0,
489 color.blue / 65535.0, 1.0)
490 else:
491 ct.set_source_rgba(0.1, 0.1, 0.1, 0.5)
492 ''' Set the initial position and iter to 0 '''
493 x_pos = 2 if self.border else 0
494 cnt = 0
495 ''' If a transmit history exists, draw it '''
496 if iface in self.netstats.ifaces \
497 and len(self.netstats.ifaces[iface]["tx_history"]):
498 for value in self.netstats.ifaces[iface]["tx_history"]:
499 x_pos_end = (x_pos - width) + 2 if self.border \
500 and x_pos > width else 0
501 ct.line_to(x_pos - x_pos_end, self.chart_coords(value, ratio))
502 ct.move_to(x_pos, self.chart_coords(value, ratio))
503 x_pos += width / self.meter_scale
504 cnt += 1
505 ct.close_path()
506 ct.stroke()
507 ''' Change the color of the download line to configured/default '''
508 if iface:
509 color = gtk.gdk.color_parse(
510 self.netstats.ifaces[iface]['download_color'])
511 ct.set_source_rgba(color.red / 65535.0,
512 color.green / 65535.0,
513 color.blue / 65535.0, 1.0)
514 else:
515 ct.set_source_rgba(0.1, 0.1, 0.1, 0.5)
516 ''' Reset the position and iter to 0 '''
517 x_pos = 2 if self.border else 0
518 cnt = 0
519 ''' If a receive history exists, draw it '''
520 if iface in self.netstats.ifaces \
521 and len(self.netstats.ifaces[iface]["rx_history"]):
522 for value in self.netstats.ifaces[iface]["rx_history"]:
523 x_pos_end = (x_pos - width) + 2 if self.border \
524 and x_pos > width else 0
525 ct.line_to(x_pos - x_pos_end, self.chart_coords(value, ratio))
526 ct.move_to(x_pos, self.chart_coords(value, ratio))
527 x_pos += width / self.meter_scale
528 cnt += 1
529 ct.close_path()
530 ct.stroke()
531
532 def chart_coords(self, value, ratio=1):
533 ratio = 1 if ratio < 1 else ratio
534 pos = float(self.applet.get_size()) / 58
535 bottom = 2.0 if self.border else 0
536 return (self.applet.get_size() - pos \
537 * (value / int(ratio))) + self.graph_zero - bottom
538
539 def repaint(self):
540 orientation = self.applet.get_pos_type()
541 if orientation in (gtk.POS_LEFT, gtk.POS_RIGHT):
542 width = self.applet.get_size()
543 self.upload_ot.props.font_sizing = 9
544 self.download_ot.props.font_sizing = 9
545 self.sum_ot.props.font_sizing = 9
546 else:
547 width = self.applet.get_size() * 1.5
548 self.upload_ot.props.font_sizing = self.default_font_size
549 self.download_ot.props.font_sizing = self.default_font_size
550 self.sum_ot.props.font_sizing = self.default_font_size
551 cs = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width),
552 self.applet.get_size())
553 ct = cairo.Context(cs)
554 ct.set_source_surface(cs)
555 ct.set_line_width(2)
556 if self.background:
557 bgColor, alpha = \
558 self.applet.settings["background_color"].split("|")
559 bgColor = gtk.gdk.color_parse(bgColor)
560 ct.set_source_rgba(bgColor.red / 65535.0,
561 bgColor.green / 65535.0,
562 bgColor.blue / 65535.0,
563 float(alpha))
564 self.draw_background(ct, 0, 0, width, self.applet.get_size(), 10)
565 ct.fill()
566 if self.iface == "Multi Interface":
567 tmp_history = [1]
568 for iface in self.netstats.ifaces:
569 if self.netstats.ifaces[iface]['multi_include']:
570 tmp_history.extend(
571 self.netstats.ifaces[iface]["rx_history"])
572 tmp_history.extend(
573 self.netstats.ifaces[iface]["tx_history"])
574 tmp_history.sort()
575 max_val = tmp_history[-1]
576 self.ratio = max_val / 28 if max_val > self.ratio else 1
577 for iface in self.netstats.ifaces:
578 if self.netstats.ifaces[iface]['multi_include']:
579 self.draw_meter(ct, width, self.applet.get_size(),
580 iface, True)
581 else:
582 self.draw_meter(ct, width, self.applet.get_size(), self.iface)
583 if self.iface in self.netstats.ifaces:
584 if self.label_control:
585 if self.label_control == 2:
586 self.sum_ot.props.text = ""
587 self.download_ot.props.text = \
588 readable_speed(
589 self.netstats.ifaces[self.iface]["rx_bytes"],
590 self.unit).strip()
591 self.upload_ot.props.text = \
592 readable_speed(
593 self.netstats.ifaces[self.iface]["tx_bytes"],
594 self.unit).strip()
595 else:
596 self.upload_ot.props.text = ""
597 self.download_ot.props.text = ""
598 self.sum_ot.props.text = \
599 readable_speed(
600 self.netstats.ifaces[self.iface]["rx_bytes"] \
601 + self.netstats.ifaces[self.iface]["tx_bytes"],
602 self.unit).strip()
603 else:
604 self.upload_ot.props.text = ""
605 self.download_ot.props.text = ""
606 self.sum_ot.props.text = ""
607 self.title_text = readable_speed(
608 self.netstats.ifaces[self.iface]["tx_bytes"], self.unit)
609 else:
610 self.upload_ot.props.text = "No"
611 self.download_ot.props.text = "Device"
612 self.title_text = "Please select a valid device"
613 if self.border:
614 line_width = 2
615 ct.set_line_width(line_width)
616 borderColor, alpha = \
617 self.applet.settings["border_color"].split("|")
618 borderColor = gtk.gdk.color_parse(borderColor)
619 ct.set_source_rgba(borderColor.red / 65535.0,
620 borderColor.green / 65535.0,
621 borderColor.blue / 65535.0,
622 float(alpha))
623 self.draw_background(ct,
624 line_width / 2,
625 line_width / 2,
626 width - line_width / 2,
627 self.applet.get_size() - line_width / 2, 4)
628 ct.stroke()
629 self.applet.set_icon_context(ct)
630 if self.applet.dialog.is_visible("main"):
631 for iface in self.netstats.ifaces:
632 if not "widget" in self.netstats.ifaces[iface] \
633 or self.netstats.regenerate == True:
634 self.netstats.regenerate = False
635 self.vbox.remove(self.table)
636 self.table = self.generate_table()
637 self.vbox.add(self.table)
638 self.vbox.show_all()
639 self.netstats.ifaces[iface]["widget"].rx_speed_label.set_text(
640 str(readable_speed(self.netstats.ifaces[iface]["rx_bytes"],
641 self.unit).strip()))
642 self.netstats.ifaces[iface]["widget"].tx_speed_label.set_text(
643 str(readable_speed(self.netstats.ifaces[iface]["tx_bytes"],
644 self.unit).strip()))
645 self.netstats.ifaces[iface]["widget"].sent_label.set_text(
646 str(readable_speed(self.netstats.ifaces[iface]["tx_sum"] \
647 * self.unit, self.unit, False).strip()))
648 self.netstats.ifaces[iface]["widget"].received_label.set_text(
649 str(readable_speed(self.netstats.ifaces[iface]["rx_sum"] \
650 * self.unit, self.unit, False).strip()))
651 return True
652
653
654def readable_speed(speed, unit, seconds=True):
655 ''' readable_speed(speed) -> string
656 speed is in bytes per second
657 returns a readable version of the speed given '''
658 speed = 0 if speed is None or speed < 0 else speed
659 units = ["B ", "KB", "MB", "GB", "TB"] if unit == 1 \
660 else ["b ", "Kb", "Mb", "Gb", "Tb"]
661 if seconds:
662 temp_units = []
663 for u in units:
664 temp_units.append("%sps" % u.strip())
665 units = temp_units
666 step = 1L
667 for u in units:
668 if step > 1:
669 s = "%4.2f " % (float(speed) / step)
670 if len(s) <= 5:
671 return s + u
672 s = "%4.2f " % (float(speed) / step)
673 if len(s) <= 5:
674 return s + u
675 if speed / step < 1024:
676 return "%4.1d " % (speed / step) + u
677 step = step * 1024L
678 return "%4.1d " % (speed / (step / 1024)) + units[-1]
679
680if __name__ == "__main__":
681 awnlib.init_start(AppletBandwidthMonitor, {"name": APPLET_NAME,
682 "short": "bandwidth-monitor",
683 "version": __version__,
684 "description": APPLET_DESCRIPTION,
685 "logo": APPLET_ICON,
686 "author": "Kyle L. Huff",
687 "copyright-year": "2009",
688 "authors": APPLET_AUTHORS})
0689
=== added file 'applets/maintained/bandwidth-monitor/bandwidth-monitor.desktop.in.in'
--- applets/maintained/bandwidth-monitor/bandwidth-monitor.desktop.in.in 1970-01-01 00:00:00 +0000
+++ applets/maintained/bandwidth-monitor/bandwidth-monitor.desktop.in.in 2010-01-16 19:06:14 +0000
@@ -0,0 +1,11 @@
1[Desktop Entry]
2Version=1.0
3Name=Bandwidth Monitor
4Type=Application
5X-AWN-Type=Applet
6X-AWN-AppletType=Python
7Comment=A Network Bandwidth monitor for AWN
8X-AWN-AppletExec=bandwidth-monitor/awn-bwm.py
9Exec=awn-applet -p %k
10Icon=bandwidth-monitor/images/icon
11X-AWN-AppletCategory=Utility
012
=== added file 'applets/maintained/bandwidth-monitor/bandwidth-monitor.ui'
--- applets/maintained/bandwidth-monitor/bandwidth-monitor.ui 1970-01-01 00:00:00 +0000
+++ applets/maintained/bandwidth-monitor/bandwidth-monitor.ui 2010-01-16 19:06:14 +0000
@@ -0,0 +1,300 @@
1<?xml version="1.0"?>
2<interface>
3 <!-- interface-requires gtk+ 2.12 -->
4 <!-- interface-naming-policy toplevel-contextual -->
5 <object class="GtkAdjustment" id="adjustment-scale-threshold">
6 <property name="upper">100000</property>
7 <property name="step_increment">0.01</property>
8 <property name="page_increment">100</property>
9 </object>
10 <object class="GtkWindow" id="general-preferences">
11 <child>
12 <object class="GtkNotebook" id="dialog-notebook">
13 <property name="width_request">500</property>
14 <property name="visible">True</property>
15 <property name="can_focus">True</property>
16 <child>
17 <object class="GtkFrame" id="frame3">
18 <property name="visible">True</property>
19 <property name="label_xalign">0</property>
20 <property name="shadow_type">none</property>
21 <child>
22 <object class="GtkAlignment" id="alignment3">
23 <property name="visible">True</property>
24 <property name="top_padding">6</property>
25 <property name="bottom_padding">6</property>
26 <property name="left_padding">12</property>
27 <property name="right_padding">12</property>
28 <child>
29 <object class="GtkVBox" id="vbox3">
30 <property name="visible">True</property>
31 <property name="orientation">vertical</property>
32 <property name="spacing">6</property>
33 <child>
34 <object class="GtkCheckButton" id="uomCheckbutton">
35 <property name="label" translatable="yes">Display MBps/KBps (bytes) instead of Mbps/Kbps (bits)</property>
36 <property name="visible">True</property>
37 <property name="can_focus">True</property>
38 <property name="receives_default">False</property>
39 <property name="tooltip_text" translatable="yes">If this is checked, the common display unit will be Bytes</property>
40 <property name="use_underline">True</property>
41 <property name="draw_indicator">True</property>
42 </object>
43 <packing>
44 <property name="expand">False</property>
45 <property name="padding">6</property>
46 <property name="position">0</property>
47 </packing>
48 </child>
49 <child>
50 <object class="GtkHBox" id="bgHbox">
51 <property name="visible">True</property>
52 <child>
53 <object class="GtkCheckButton" id="bgCheckbutton">
54 <property name="label" translatable="yes">Draw Background</property>
55 <property name="width_request">200</property>
56 <property name="visible">True</property>
57 <property name="can_focus">True</property>
58 <property name="receives_default">False</property>
59 <property name="tooltip_text" translatable="yes">If this is checked the applet background will use the selected color. If unchecked, background will be transparent</property>
60 <property name="active">True</property>
61 <property name="draw_indicator">True</property>
62 </object>
63 <packing>
64 <property name="position">0</property>
65 </packing>
66 </child>
67 <child>
68 <object class="GtkColorButton" id="bgColorbutton">
69 <property name="visible">True</property>
70 <property name="can_focus">True</property>
71 <property name="receives_default">True</property>
72 <property name="events">GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK</property>
73 <property name="tooltip_text" translatable="yes">Background Color</property>
74 <property name="use_alpha">True</property>
75 <property name="title" translatable="yes">Background Color</property>
76 <property name="color">#000000000000</property>
77 <property name="alpha">32767</property>
78 </object>
79 <packing>
80 <property name="padding">10</property>
81 <property name="position">1</property>
82 </packing>
83 </child>
84 </object>
85 <packing>
86 <property name="position">1</property>
87 </packing>
88 </child>
89 <child>
90 <object class="GtkHBox" id="borderHbox">
91 <property name="visible">True</property>
92 <child>
93 <object class="GtkCheckButton" id="borderCheckbutton">
94 <property name="label" translatable="yes">Draw Border</property>
95 <property name="width_request">200</property>
96 <property name="visible">True</property>
97 <property name="can_focus">True</property>
98 <property name="receives_default">False</property>
99 <property name="tooltip_text" translatable="yes">If this is checked the applet border will use the selected color. If unchecked, border will be transparent</property>
100 <property name="draw_indicator">True</property>
101 </object>
102 <packing>
103 <property name="position">0</property>
104 </packing>
105 </child>
106 <child>
107 <object class="GtkColorButton" id="borderColorbutton">
108 <property name="visible">True</property>
109 <property name="can_focus">True</property>
110 <property name="receives_default">True</property>
111 <property name="tooltip_text" translatable="yes">Border Color</property>
112 <property name="use_alpha">True</property>
113 <property name="title" translatable="yes">Border Color</property>
114 <property name="color">#000000000000</property>
115 </object>
116 <packing>
117 <property name="padding">10</property>
118 <property name="position">1</property>
119 </packing>
120 </child>
121 </object>
122 <packing>
123 <property name="position">2</property>
124 </packing>
125 </child>
126 <child>
127 <object class="GtkHBox" id="hbox1">
128 <property name="visible">True</property>
129 <child>
130 <object class="GtkRadioButton" id="labelBothRadiobutton">
131 <property name="label" translatable="yes">Display Speed Text</property>
132 <property name="visible">True</property>
133 <property name="can_focus">True</property>
134 <property name="receives_default">False</property>
135 <property name="tooltip_text" translatable="yes">Display upload and download text representation of speed</property>
136 <property name="draw_indicator">True</property>
137 </object>
138 <packing>
139 <property name="position">0</property>
140 </packing>
141 </child>
142 <child>
143 <object class="GtkRadioButton" id="labelSumRadiobutton">
144 <property name="label" translatable="yes">Sum</property>
145 <property name="visible">True</property>
146 <property name="can_focus">True</property>
147 <property name="receives_default">False</property>
148 <property name="tooltip_text" translatable="yes">Display the sum of upload and download</property>
149 <property name="draw_indicator">True</property>
150 <property name="group">labelBothRadiobutton</property>
151 </object>
152 <packing>
153 <property name="position">1</property>
154 </packing>
155 </child>
156 <child>
157 <object class="GtkRadioButton" id="labelNoneRadiobutton">
158 <property name="label" translatable="yes">Graph Only</property>
159 <property name="visible">True</property>
160 <property name="can_focus">True</property>
161 <property name="receives_default">False</property>
162 <property name="tooltip_text" translatable="yes">Do not display the speed as text, only draw the graph</property>
163 <property name="draw_indicator">True</property>
164 <property name="group">labelBothRadiobutton</property>
165 </object>
166 <packing>
167 <property name="position">2</property>
168 </packing>
169 </child>
170 </object>
171 <packing>
172 <property name="position">3</property>
173 </packing>
174 </child>
175 <child>
176 <object class="GtkCheckButton" id="graphZerotoggle">
177 <property name="label" translatable="yes">Draw 0 bps in graphs</property>
178 <property name="visible">True</property>
179 <property name="can_focus">True</property>
180 <property name="receives_default">False</property>
181 <property name="tooltip_text" translatable="yes">If enabled, this will draw a line at the bottom of the graph even if the value is 0. If unchecked, values below 1 are not drawn in the graph.</property>
182 <property name="active">True</property>
183 <property name="draw_indicator">True</property>
184 </object>
185 <packing>
186 <property name="position">4</property>
187 </packing>
188 </child>
189 <child>
190 <object class="GtkHBox" id="hbox6">
191 <property name="visible">True</property>
192 <property name="tooltip_text" translatable="yes">Sets the minimum threshold for scaling to not show large spikes for small amounts of traffic. e.g.: Setting to 32.0 KBps will cause the graph to only draw if throughput exceeds 32.0 KBps</property>
193 <property name="spacing">12</property>
194 <child>
195 <object class="GtkLabel" id="label-scale-threshold">
196 <property name="visible">True</property>
197 <property name="xalign">0</property>
198 <property name="label" translatable="yes">Minimum Scaling threshold</property>
199 <property name="use_underline">True</property>
200 <property name="mnemonic_widget">scaleThresholdSBtn</property>
201 </object>
202 <packing>
203 <property name="expand">False</property>
204 <property name="position">0</property>
205 </packing>
206 </child>
207 <child>
208 <object class="GtkHBox" id="hbox3">
209 <property name="visible">True</property>
210 <property name="spacing">6</property>
211 <child>
212 <object class="GtkSpinButton" id="scaleThresholdSBtn">
213 <property name="visible">True</property>
214 <property name="can_focus">True</property>
215 <property name="invisible_char">&#x25CF;</property>
216 <property name="caps_lock_warning">False</property>
217 <property name="adjustment">adjustment-scale-threshold</property>
218 <property name="digits">2</property>
219 <property name="numeric">True</property>
220 </object>
221 <packing>
222 <property name="position">0</property>
223 </packing>
224 </child>
225 <child>
226 <object class="GtkLabel" id="label-scaleThreshold">
227 <property name="visible">True</property>
228 <property name="label" translatable="yes">KBps</property>
229 </object>
230 <packing>
231 <property name="position">1</property>
232 </packing>
233 </child>
234 </object>
235 <packing>
236 <property name="position">1</property>
237 </packing>
238 </child>
239 </object>
240 <packing>
241 <property name="padding">6</property>
242 <property name="position">5</property>
243 </packing>
244 </child>
245 </object>
246 </child>
247 </object>
248 </child>
249 <child type="label">
250 <object class="GtkLabel" id="label-display">
251 <property name="visible">True</property>
252 <property name="label" translatable="yes">&lt;b&gt;Display&lt;/b&gt;</property>
253 <property name="use_markup">True</property>
254 </object>
255 </child>
256 </object>
257 </child>
258 <child type="tab">
259 <object class="GtkLabel" id="label-general">
260 <property name="visible">True</property>
261 <property name="label" translatable="yes">General</property>
262 </object>
263 <packing>
264 <property name="tab_fill">False</property>
265 </packing>
266 </child>
267 <child>
268 <object class="GtkAlignment" id="alignment1">
269 <property name="height_request">150</property>
270 <property name="visible">True</property>
271 <child>
272 <object class="GtkScrolledWindow" id="scrolledwindow1">
273 <property name="visible">True</property>
274 <property name="can_focus">True</property>
275 <property name="hscrollbar_policy">automatic</property>
276 <property name="vscrollbar_policy">automatic</property>
277 <child>
278 <placeholder/>
279 </child>
280 </object>
281 </child>
282 </object>
283 <packing>
284 <property name="position">1</property>
285 </packing>
286 </child>
287 <child type="tab">
288 <object class="GtkLabel" id="label-devices">
289 <property name="visible">True</property>
290 <property name="label" translatable="yes">Devices</property>
291 </object>
292 <packing>
293 <property name="position">1</property>
294 <property name="tab_fill">False</property>
295 </packing>
296 </child>
297 </object>
298 </child>
299 </object>
300</interface>
0301
=== added file 'applets/maintained/bandwidth-monitor/bwmprefs.py'
--- applets/maintained/bandwidth-monitor/bwmprefs.py 1970-01-01 00:00:00 +0000
+++ applets/maintained/bandwidth-monitor/bwmprefs.py 2010-01-16 19:06:14 +0000
@@ -0,0 +1,278 @@
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3"""
4bandwidth-monitor - Network bandwidth monitor.
5Copyright (c) 2006-2009 Kyle L. Huff (kyle.huff@curetheitch.com)
6url: <http://www.curetheitch.com/projects/awn-bwm/>
7Email: awn-bwm@curetheitch.com
8
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/gpl.txt>.
21"""
22
23import gtk
24import gobject
25
26
27class Preferences:
28
29 def __init__(self, applet, parent):
30 self.applet = applet
31 self.parent = parent
32
33 def setup(self):
34 prefs_ui = gtk.Builder()
35 prefs_ui.add_from_file(self.parent.UI_FILE)
36 preferences_vbox = self.applet.dialog.new("preferences").vbox
37 cell_box = self.create_treeview()
38 store = cell_box.liststore
39 scaleThresholdSBtn = prefs_ui.get_object("scaleThresholdSBtn")
40 thresholdLabel = prefs_ui.get_object("label-scaleThreshold")
41 scaleThresholdSBtn.set_value(
42 float(self.applet.settings["draw_threshold"]))
43 scaleThresholdSBtn.connect(
44 'value-changed', self.parent.change_draw_ratio)
45 uomCheckbutton = prefs_ui.get_object('uomCheckbutton')
46 self.uomCheckbutton = uomCheckbutton
47 if self.parent.unit == 1:
48 uomCheckbutton.set_property('active', True)
49 thresholdLabel.set_text("KBps")
50 else:
51 thresholdLabel.set_text("Kbps")
52 uomCheckbutton.connect('toggled',
53 self.parent.change_unit, scaleThresholdSBtn, thresholdLabel)
54 graphZerotoggle = prefs_ui.get_object('graphZerotoggle')
55 graphZerotoggle_value = True if not self.parent.graph_zero else False
56 graphZerotoggle.set_property('active', graphZerotoggle_value)
57 graphZerotoggle.connect('toggled', self.graphZeroToggle_cb)
58 bgCheckbutton = prefs_ui.get_object('bgCheckbutton')
59 bgCheckbutton.set_active(self.applet.settings["background"])
60 bgCheckbutton.connect('toggled', self.bgCheckbutton_cb)
61 bgColorbutton = prefs_ui.get_object('bgColorbutton')
62 bgColor, bgAlpha = self.applet.settings["background_color"].split("|")
63 bgColorbutton.set_color(gtk.gdk.color_parse(bgColor))
64 bgColorbutton.set_alpha(int(float(bgAlpha) * 65535.0))
65 bgColorbutton.connect('color-set',
66 self.backgroundColorbutton_color_set_cb)
67 borderCheckbutton = prefs_ui.get_object('borderCheckbutton')
68 borderCheckbutton.set_active(self.applet.settings["border"])
69 borderCheckbutton.connect('toggled', self.borderCheckbutton_cb)
70 borderColorbutton = prefs_ui.get_object('borderColorbutton')
71 borderColor, borderAlpha = \
72 self.applet.settings["border_color"].split("|")
73 borderColorbutton.set_color(gtk.gdk.color_parse(borderColor))
74 borderColorbutton.set_alpha(int(float(borderAlpha) * 65535.0))
75 borderColorbutton.connect('color-set',
76 self.borderColorbutton_color_set_cb)
77 labelNoneRadiobutton = prefs_ui.get_object('labelNoneRadiobutton')
78 labelSumRadiobutton = prefs_ui.get_object('labelSumRadiobutton')
79 labelBothRadiobutton = prefs_ui.get_object('labelBothRadiobutton')
80 if self.parent.label_control == 0:
81 labelNoneRadiobutton.set_active(True)
82 elif self.parent.label_control == 1:
83 labelSumRadiobutton.set_active(True)
84 else:
85 labelBothRadiobutton.set_active(True)
86 labelNoneRadiobutton.connect('toggled', self.labelRadio_cb, 0)
87 labelSumRadiobutton.connect('toggled', self.labelRadio_cb, 1)
88 labelBothRadiobutton.connect('toggled', self.labelRadio_cb, 2)
89 for iface in sorted(self.parent.netstats.ifaces):
90 if not "Multi Interface" in iface \
91 and not "Sum Interface" in iface:
92 if self.parent.netstats.ifaces[iface]['sum_include'] == True:
93 sum_include = 1
94 else:
95 sum_include = 0
96 if self.parent.netstats.ifaces[iface]['multi_include'] == True:
97 muti_include = 1
98 else:
99 muti_include = 0
100 current_iter = store.append([iface, sum_include,
101 muti_include, '', '', '#ff0000', '#ffff00'])
102 prefs_ui.get_object("scrolledwindow1").add_with_viewport(cell_box)
103 prefs_ui.get_object("dialog-notebook").reparent(preferences_vbox)
104
105 def graphZeroToggle_cb(self, widget):
106 self.parent.graph_zero = 0 if widget.get_active() else 1
107 self.applet.settings['graph_zero'] = self.parent.graph_zero
108
109 def labelRadio_cb(self, widget, setting):
110 if widget.get_active():
111 self.applet.settings["label_control"] = setting
112 self.parent.label_control = setting
113
114 def create_treeview(self):
115 cell_box = gtk.HBox()
116 liststore = gtk.ListStore(str, gobject.TYPE_BOOLEAN,
117 gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN,
118 gobject.TYPE_BOOLEAN, str, str)
119 treeview = gtk.TreeView(liststore)
120 treeview.set_property("rules-hint", True)
121 treeview.set_enable_search(True)
122 treeview.position = 0
123 rows = gtk.VBox(False, 3)
124 self.liststore = liststore
125 listcols = gtk.HBox(False, 0)
126 prows = gtk.VBox(False, 0)
127 rows.pack_start(listcols, True, True, 0)
128 listcols.pack_start(treeview)
129 listcols.pack_start(prows, False, False, 0)
130 selection = treeview.get_selection()
131 selection.connect('changed', self.on_selection_changed)
132 ''' Device '''
133 device_renderer = gtk.CellRendererText()
134 device_column = gtk.TreeViewColumn("Device", device_renderer)
135 device_column.set_property('expand', True)
136 device_column.add_attribute(device_renderer, "text", 0)
137 ''' Sum '''
138 sum_renderer = gtk.CellRendererToggle()
139 sum_column = gtk.TreeViewColumn("Sum", sum_renderer)
140 sum_column.add_attribute(sum_renderer, 'active', 1)
141 sum_renderer.set_property('activatable', True)
142 sum_renderer.connect('toggled', self.toggle_cb, liststore, 1, "sum")
143 ''' Multi '''
144 multi_renderer = gtk.CellRendererToggle()
145 multi_column = gtk.TreeViewColumn("Mutli", multi_renderer)
146 multi_column.add_attribute(multi_renderer, 'active', 2)
147 multi_renderer.set_property('activatable', True)
148 multi_renderer.connect('toggled', self.toggle_cb,
149 liststore, 2, "multi")
150 ''' Upload '''
151 uploadColor_renderer = gtk.CellRendererToggle()
152 uploadColor_renderer.set_property('indicator-size', 0.1)
153 uploadColor_column = gtk.TreeViewColumn("Upload Color",
154 uploadColor_renderer, cell_background=5)
155 uploadColor_column.add_attribute(uploadColor_renderer, 'active', 3)
156 uploadColor_column.set_cell_data_func(uploadColor_renderer,
157 self.devlist_cell_func)
158 uploadColor_renderer.set_property('activatable', True)
159 uploadColor_renderer.connect('toggled', self.color_cb,
160 liststore, 3, "upload")
161 ''' Download '''
162 downloadColor_renderer = gtk.CellRendererToggle()
163 downloadColor_renderer.set_property('indicator-size', 0.1)
164 downloadColor_column = gtk.TreeViewColumn("Download Color",
165 downloadColor_renderer, cell_background=6)
166 downloadColor_column.add_attribute(downloadColor_renderer, 'active', 4)
167 downloadColor_column.set_cell_data_func(downloadColor_renderer,
168 self.devlist_cell_func)
169 downloadColor_renderer.set_property('activatable', True)
170 downloadColor_renderer.connect('toggled', self.color_cb,
171 liststore, 4, "download")
172 ''' Apply the before defined cells '''
173 cell_box.liststore = liststore
174 treeview.append_column(device_column)
175 treeview.append_column(sum_column)
176 treeview.append_column(multi_column)
177 treeview.append_column(uploadColor_column)
178 treeview.append_column(downloadColor_column)
179 cell_box.listcols = listcols
180 cell_box.add(rows)
181 return cell_box
182
183 def on_selection_changed(self, selection):
184 ''' If a row is selected; deselect it.. always..
185 There is currently no need to have the row selected,
186 and the highlight of the row makes it difficult to see
187 the colors selected depending on your GTK theme.. '''
188 model, paths = selection.get_selected_rows()
189 if paths:
190 selection.unselect_path(model[paths[0]].path)
191
192 def devlist_cell_func(self, column, cell, model, iter):
193 ''' Changes the cell color to match the preferece or selected value '''
194 device = self.liststore.get_value(iter, 0)
195 column_title = column.get_title().lower().split(" ")[0]
196 cell.set_property("cell-background",
197 self.get_color(device, column_title))
198
199 def bgCheckbutton_cb(self, widget):
200 self.applet.settings['background'] = widget.get_active()
201 self.parent.background = widget.get_active()
202
203 def borderCheckbutton_cb(self, widget):
204 self.applet.settings['border'] = widget.get_active()
205 self.parent.border = widget.get_active()
206
207 def backgroundColorbutton_color_set_cb(self, widget):
208 color = widget.get_color()
209 alpha = float("%2.1f" % (widget.get_alpha() / 65535.0))
210 self.applet.settings["background_color"] = "%s|%s" % (color, alpha)
211 self.parent.background_color = "%s|%s" % (color, alpha)
212
213 def borderColorbutton_color_set_cb(self, widget):
214 color = widget.get_color()
215 alpha = float("%2.1f" % (widget.get_alpha() / 65535.0))
216 self.applet.settings["border_color"] = "%s|%s" \
217 % (color.to_string(), alpha)
218 self.parent.border_color = "%s|%s" % (color, alpha)
219
220 def get_color(self, device, column_name):
221 if column_name == "upload":
222 i = 3
223 color = "#ff0000"
224 else:
225 i = 4
226 color = "#ffff00"
227 prefs = self.applet.settings["device_display_parameters"]
228 for device_pref in prefs:
229 device_pref_values = device_pref.split("|")
230 if device_pref_values[0] == device:
231 if "#" in device_pref_values[i]:
232 color = device_pref_values[i]
233 return color
234
235 def color_cb(self, widget, path, model, col_number, name):
236 if col_number == 3:
237 prop = "Upload"
238 else:
239 prop = "Download"
240 colorseldlg = gtk.ColorSelectionDialog(
241 "%s %s Color" % (model[path][0], prop))
242 colorseldlg.colorsel.set_current_color(
243 gtk.gdk.color_parse(self.get_color(model[path][0], prop.lower())))
244 response = colorseldlg.run()
245 if response == gtk.RESPONSE_OK:
246 self.color_choice = colorseldlg.colorsel.get_current_color()
247 self.parent.netstats.ifaces[model[path][0]]['%s_color' \
248 % prop.lower()] = self.color_choice.to_string()
249 prefs = self.applet.settings["device_display_parameters"]
250 if not prefs:
251 prefs = ["%s|True|True|None|None" % (model[path][0])]
252 if not model[path][0] in prefs.__str__():
253 prefs.append("%s|True|True|None|None" % (model[path][0]))
254 for i, device_pref in enumerate(prefs):
255 dpv = device_pref.split('|')
256 if dpv[0] == model[path][0]:
257 dpv[col_number] = self.color_choice.to_string()
258 prefs[i] = '|'.join(dpv)
259 model[path][col_number + 2] = self.color_choice.to_string()
260 self.applet.settings["device_display_parameters"] = prefs
261 colorseldlg.hide()
262
263 def toggle_cb(self, widget, path, model, col_number, name):
264 model[path][col_number] = not model[path][col_number]
265 parameter = model[path][col_number]
266 self.parent.netstats.ifaces[model[path][0]]['%s_include' % name] \
267 = parameter
268 prefs = self.applet.settings["device_display_parameters"]
269 if not prefs:
270 prefs = ["%s|True|True|None|None" % (model[path][0])]
271 if not model[path][0] in prefs.__str__():
272 prefs.append("%s|True|True|None|None" % (model[path][0]))
273 for i, device_pref in enumerate(prefs):
274 dpv = device_pref.split('|')
275 if dpv[0] == model[path][0]:
276 dpv[col_number] = str(parameter)
277 prefs[i] = '|'.join(dpv)
278 self.applet.settings["device_display_parameters"] = prefs
0279
=== added directory 'applets/maintained/bandwidth-monitor/images'
=== added file 'applets/maintained/bandwidth-monitor/images/icon.png'
1Binary files applets/maintained/bandwidth-monitor/images/icon.png 1970-01-01 00:00:00 +0000 and applets/maintained/bandwidth-monitor/images/icon.png 2010-01-16 19:06:14 +0000 differ280Binary files applets/maintained/bandwidth-monitor/images/icon.png 1970-01-01 00:00:00 +0000 and applets/maintained/bandwidth-monitor/images/icon.png 2010-01-16 19:06:14 +0000 differ
=== modified file 'configure.ac'
--- configure.ac 2009-12-29 23:15:57 +0000
+++ configure.ac 2010-01-16 19:06:14 +0000
@@ -316,6 +316,8 @@
316applets/maintained/animal-farm/Makefile316applets/maintained/animal-farm/Makefile
317applets/maintained/awnterm/Makefile317applets/maintained/awnterm/Makefile
318applets/maintained/awnterm/awnterm.desktop.in318applets/maintained/awnterm/awnterm.desktop.in
319applets/maintained/bandwidth-monitor/Makefile
320applets/maintained/bandwidth-monitor/bandwidth-monitor.desktop.in
319applets/maintained/battery/Makefile321applets/maintained/battery/Makefile
320applets/maintained/cairo-clock/Makefile322applets/maintained/cairo-clock/Makefile
321applets/maintained/cairo-menu/Makefile323applets/maintained/cairo-menu/Makefile

Subscribers

People subscribed via source and target branches