4
# Copyright (C) 2008 Canonical Ltd.
6
# Authors: Nick Barcet <nick.barcet@ubuntu.com>
7
# Dustin Kirkland <kirkland@canonical.com>
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, version 3 of the License.
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU General Public License for more details.
18
# You should have received a copy of the GNU General Public License
19
# along with this program. If not, see <http://www.gnu.org/licenses/>.
21
# If you change any strings, please generate localization information with:
22
# ./debian/rules get-po
25
import sys, os, os.path, time, string, commands, gettext, glob, snack
26
from ConfigParser import SafeConfigParser
29
HOME=os.getenv("HOME")
30
USER=os.getenv("USER")
32
SHARE='/usr/share/'+PKG
33
DOC='/usr/share/doc/'+PKG
35
RELOAD = "If you are using the default set of keybindings, press\n<F5> or <ctrl-a-R> to activate these changes.\n\nOtherwise, exit this screen session and start a new one."
36
RELOAD_FLAG="/var/run/screen/S-"+USER+"/"+PKG+".reload-required"
37
RELOAD_CMD="screen -X at 0 source $HOME/."+PKG+"/profile"
39
snack.hotkeys[ESC] = ord(ESC)
40
snack.hotkeys[ord(ESC)] = ESC
42
gettext.bindtextdomain(PKG, SHARE+'/po')
43
gettext.textdomain(PKG)
46
# Command presets for windows creation
47
cmd=( ("System activity", "top", "top"),
48
("System log", "log", "watch -n 10 tail -n 5 /var/log/syslog /var/log/auth.log /var/log/dmesg"),
49
("Disk and ram usage", "mem", 'watch -n 30 "df -h; echo ""; free -mt"'))
52
def ioctl_GWINSZ(fd): #### TABULATION FUNCTIONS
53
try: ### Discover terminal width
54
import fcntl, termios, struct, os
55
cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
60
def reload_required():
61
f = open(RELOAD_FLAG,'w')
63
commands.getoutput(RELOAD_CMD)
65
def terminal_size(): ### decide on *some* terminal size
66
cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) # try open fds
67
if not cr: # ...then ctty
69
fd = os.open(os.ctermid(), os.O_RDONLY)
74
if not cr: # env vars or finally defaults
76
cr = (env['LINES'], env['COLUMNS'])
79
return int(cr[1]-5), int(cr[0]-5) # reverse rows, cols
81
def menu(screen, size, isInstalled):
83
installtext=_("Byobu currently launches at login (toggle off)")
85
installtext=_("Byobu currently does not launch at login (toggle on)")
88
li = Listbox(height = 8, width = 60, returnExit = 1)
89
li.append(_("Help"), 1)
90
li.append(_("Change Byobu's colors"), 2)
91
li.append(_("Toggle status notifications"), 3)
92
li.append(_("Change keybinding set"), 4)
93
li.append(_("Change escape sequence"), 5)
94
li.append(_("Create new windows"), 6)
95
li.append(_("Manage default windows"), 7)
96
li.append(installtext, 8)
97
bb = ButtonBar(screen, (("Exit", "exit", ESC),), compact=1)
99
g = GridForm(screen, _(" Byobu Configuration Menu"), 1, 2)
100
g.add(li, 0, 0, padding=(4,2,4,2))
101
g.add(bb, 0, 1, padding=(1,1,0,0))
103
if bb.buttonPressed(g.runOnce()) == "exit":
108
def messagebox(screen, width, height, title, text, \
110
buttons=((_("Okay"), "okay"),(_("Cancel"), "cancel", ESC)) ):
112
t = Textbox(width, height, text, scroll=scroll )
113
bb = ButtonBar(screen, buttons, compact = 1)
114
g = GridForm(screen, title, 1, 2)
115
g.add(t, 0, 0, padding=(0,0,0,0))
116
g.add(bb, 0, 1, padding=(1,1,0,0))
118
return bb.buttonPressed(g.runOnce())
120
def help(screen, size, config):
121
for fn in glob.glob(DOC+'*/help.txt'):
126
text=text.replace("<esckey>", getesckey(), 1)
128
t = Textbox(70, 14, text, scroll=0)
129
bb = ButtonBar(screen, ((_("Menu"), "menu", ESC),), compact = 1)
130
g = GridForm(screen, _("Byobu Help"), 1, 3)
131
g.add(t, 0, 0, padding=(0,0,0,0))
132
g.add(bb, 0, 2, padding=(1,1,0,0))
134
button = bb.buttonPressed(g.runOnce())
138
def profile(screen, size):
139
li = Listbox(height = 8, width = 60, scroll = 1, returnExit = 1)
141
for choice in commands.getoutput('byobu-select-profile -l').splitlines():
142
li.append(choice, choice)
144
bb = ButtonBar(screen, ((_("Apply"), "apply"), (_("Cancel"), "cancel", ESC)), compact = 1)
146
g = GridForm(screen, _("Which profile would you like to use?"), 1, 2)
147
g.add(li, 0, 0, padding=(4,2,4,2))
148
g.add(bb, 0, 1, padding=(1,1,0,0))
150
if bb.buttonPressed(g.runOnce()) != "cancel":
151
commands.getoutput('byobu-select-profile --set %s' % li.current())
155
def keybindings(screen, size):
156
li = Listbox(height = 6, width = 60, returnExit = 1)
157
for choice in commands.getoutput('ls '+SHARE+'/keybindings').splitlines():
158
if choice != "common" and choice != "none":
159
li.append(choice, choice)
160
li.append("none", "none")
161
bb = ButtonBar(screen, ((_("Apply"), "apply"), (_("Cancel"), "cancel", ESC)), compact = 1)
162
g = GridForm(screen, _("Which set of keybindings would you like to use?"), 1, 2)
163
g.add(li, 0, 0, padding=(4,2,4,2))
164
g.add(bb, 0, 1, padding=(1,1,0,0))
165
if bb.buttonPressed(g.runOnce()) != "cancel":
166
switch_keybindings(li.current())
170
def switch_keybindings(set):
171
commands.getoutput("sed -i -e 's:^source .*$:source "+SHARE+"/keybindings/"+set+":' "+HOME+"/."+PKG+"/keybindings")
173
def newwindow(screen, size):
174
title=Entry(8, text="bash", returnExit=1)
175
titlel=Label(_("Title: "))
176
command=Entry(20, text="/bin/bash", returnExit=1)
177
commandl=Label(_("Command: "))
179
rl=Label(_("Presets: "))
187
r=CheckboxTree(size, scroll=scroll)
190
r.append(cur[0], count)
193
cb=Checkbox(_("Add to default windows"))
195
bb = ButtonBar(screen, ((_("Apply"), "apply"), (_("Cancel"), "cancel", ESC)), compact = 1)
197
g = GridForm(screen, _("Create new window(s):"), 2, 5 )
198
g.add(titlel, 0, 0, anchorLeft=1,padding=(4,1,0,1))
199
g.add(title, 1, 0, anchorLeft=1)
200
g.add(commandl, 0, 1, anchorLeft=1, anchorTop=1,padding=(4,0,0,1))
201
g.add(command, 1, 1, anchorLeft=1)
202
g.add(rl, 0, 2, anchorLeft=1,padding=(4,0,0,1))
204
g.add(cb, 1, 3, padding=(4,1,0,1))
205
g.add(bb, 1, 4, padding=(4,1,0,0))
207
if bb.buttonPressed(g.runOnce()) != "cancel":
211
win='screen -t %s %s' % (cmd[s][1], cmd[s][2])
212
commands.getoutput(win)
216
win='screen -t %s %s' % (title.value(), command.value())
217
commands.getoutput(win)
223
def appendwindow(win):
224
f=open(HOME+'/.'+PKG+'/windows', 'a')
235
if not os.path.isfile(HOME+'/.'+PKG+'/windows'):
236
windowsfile=SHARE+'/windows/common'
237
elif os.path.getsize(HOME+'/.'+PKG+'/windows') == 0:
238
windowsfile=SHARE+'/windows/common'
240
windowsfile=HOME+'/.'+PKG+'/windows'
244
for line in f.readlines():
245
if line.startswith("# "):
248
elif line.startswith("#"):
249
# this is an inactive window
250
window=[0, line.lstrip("#")]
267
status["cpu_count"]=1
272
status["fan_speed"]=0
274
status["ip_address"]=0
275
status["load_average"]=1
278
status["mem_available"]=1
282
status["processes"]=0
283
status["reboot_required"]=1
289
status["updates_available"]=1
292
status["wifi_quality"]=0
293
if os.path.exists(HOME+'/.'+PKG+'/status'):
294
f=open(HOME+'/.'+PKG+'/status', 'r')
295
for line in f.readlines():
298
(key, val) = line.split("=", 2)
299
if status.has_key(key) and (val == "1" or val == "0"):
308
window=[int(status[i]), i]
312
def writestatus(items):
313
f=open(HOME+'/.'+PKG+'/status', 'w')
325
def togglestatus(screen, size):
326
itemlist=readstatus()
328
r=CheckboxTree(12, scroll=1)
330
for item in itemlist:
332
r.append(item[1],count,selected=item[0])
334
bb = ButtonBar(screen, ((_("Apply"), "apply"), (_("Cancel"), "cancel", ESC)), compact = 1)
335
g = GridForm(screen, _("Toggle status notifications:"), 2, 4 )
336
g.add(rl, 0, 0, anchorLeft=1, anchorTop=1, padding=(4,0,0,1))
338
g.add(bb, 1, 1, padding=(4,1,0,0))
339
if bb.buttonPressed(g.runOnce()) != "cancel":
341
for item in itemlist:
343
item[0] = r.getEntryValue(count)[1]
345
writestatus(itemlist)
349
def writewindows(winlist):
350
f=open(HOME+'/.'+PKG+'/windows', 'w')
364
def defaultwindows(screen, size):
365
winlist=readwindows()
367
rl=Label(_("Windows:"))
368
r=CheckboxTree(10, scroll=1)
372
r.append(win[1],count,selected=win[0])
375
bb = ButtonBar(screen, ((_("Apply"), "apply"), (_("Cancel"), "cancel", ESC)), compact = 1)
377
g = GridForm(screen, _("Select window(s) to create by default:"), 2, 4 )
378
g.add(rl, 0, 0, anchorLeft=1, anchorTop=1, padding=(4,0,0,1))
380
g.add(bb, 1, 1, padding=(4,1,0,0))
382
if bb.buttonPressed(g.runOnce()) != "cancel":
386
win[0] = r.getEntryValue(count)[1]
389
writewindows(winlist)
393
def install(screen, size, isInstalled):
395
out = commands.getoutput("bash /usr/share/"+PKG+"/byobu-launcher-install")
397
out = _("Byobu will be launched automatically next time you login.")
399
button = messagebox(screen, 60, 2, "Message", out, \
400
buttons=((_("Menu"), )))
403
out = commands.getoutput("bash /usr/share/"+PKG+"/byobu-launcher-uninstall")
405
out = _("Byobu will not be used next time you login.")
407
button = messagebox(screen, 60, 2, _("Message"), out, \
408
buttons=((_("Menu"), )))
411
def appendtofile(p, s):
423
path=HOME+'/.'+PKG+'/keybindings'
424
if not os.path.exists(path):
426
line = commands.getoutput("grep ^escape "+path)
429
return line[line.find('^')+1]
432
path = HOME+'/.'+PKG+'/keybindings'
436
if os.path.exists(path):
437
out = commands.getoutput("sed -i -e 's/^escape.*$//' "+path)
438
appendtofile(path, "escape ^"+u+l+"\n")
439
out = commands.getoutput("sed -i -e 's/^register.*$//' "+path)
440
out = commands.getoutput("grep -h ^register "+SHARE+"/keybindings/*keys")
441
appendtofile(path, out+"\n")
442
out = commands.getoutput("sed -i -e 's/\"\^a/\"\^"+l+"/g' "+path)
443
out = commands.getoutput("sed -i -e '/^$/d' "+path)
445
def chgesc(screen, size):
446
esc=Entry(2, text=getesckey(), returnExit=1)
447
escl=Label(_("Escape key: ctrl-"))
448
bb = ButtonBar(screen, ((_("Apply"), "apply"), (_("Cancel"), "cancel", ESC)), compact = 1)
450
g = GridForm(screen, _("Change escape sequence:"), 2, 4 )
451
g.add(escl, 0, 0, anchorLeft=1, padding=(1,0,0,1))
452
g.add(esc, 1, 0, anchorLeft=1)
462
# Ensure that the escape sequence is not set to a number
464
dummy = int(esc.value())
472
if bb.buttonPressed(which) != "cancel":
473
setesckey(esc.value())
480
"""This is the main loop of our utility
483
size = terminal_size()
484
screen = SnackScreen()
485
screen.drawRootText(1,0,_(' Byobu Configuration Menu'))
486
screen.pushHelpLine(_('<Tab>/<Alt-Tab> between elements | <Enter> selects | <Esc> exits'))
488
config = SafeConfigParser()
490
isInstalled = (commands.getoutput('grep byobu-launcher '+(HOME+'/.profile')) != "")
495
tag = menu(screen, size, isInstalled)
497
tag = help(screen, size, config)
499
tag = profile(screen, size)
501
tag = togglestatus(screen, size)
503
tag = keybindings(screen, size)
505
tag = chgesc(screen, size)
507
tag = newwindow(screen, size)
509
tag = defaultwindows(screen, size)
511
tag = install(screen, size, isInstalled)
512
isInstalled=(tag == 100)
518
if __name__ == "__main__": main()