#!/usr/bin/python # # byobu-config # Copyright (C) 2008 Canonical Ltd. # # Authors: Nick Barcet # Dustin Kirkland # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # If you change any strings, please generate localization information with: # ./debian/rules get-po import sys, os, os.path, time, string, commands, gettext, glob, snack from ConfigParser import SafeConfigParser from snack import * PKG="byobu" HOME=os.getenv("HOME") USER=os.getenv("USER") BYOBU_CONFIG_DIR=os.getenv("BYOBU_CONFIG_DIR", HOME+"/.byobu") BYOBU_BACKEND=os.getenv("BYOBU_BACKEND", "tmux") BYOBU_SOCKETDIR=os.getenv("SOCKETDIR", "/var/run/screen") BYOBU_PREFIX = os.getenv("BYOBU_PREFIX", "/usr") SHARE=BYOBU_PREFIX+'/share/'+PKG DOC=BYOBU_PREFIX+'/share/doc/'+PKG if not os.path.exists(SHARE): SHARE = BYOBU_CONFIG_DIR+"/"+SHARE if not os.path.exists(DOC): DOC = BYOBU_CONFIG_DIR+"/"+DOC DEF_ESC="A" RELOAD = "If you are using the default set of keybindings, press\n or to activate these changes.\n\nOtherwise, exit this session and start a new one." RELOAD_FLAG="%s/reload-required" % (BYOBU_CONFIG_DIR) RELOAD_CMD="%s -X at 0 source %s/profile" % (BYOBU_BACKEND, BYOBU_CONFIG_DIR) ESC = '' snack.hotkeys[ESC] = ord(ESC) snack.hotkeys[ord(ESC)] = ESC if commands.getstatusoutput('which gsed')[0] == 0: BYOBU_SED = "gsed" else: BYOBU_SED = "sed" gettext.bindtextdomain(PKG, SHARE+'/po') gettext.textdomain(PKG) _ = gettext.gettext def ioctl_GWINSZ(fd): #### TABULATION FUNCTIONS try: ### Discover terminal width import fcntl, termios, struct, os cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) except: return None return cr def reload_required(): try: if not os.path.exists(BYOBU_CONFIG_DIR): os.makedirs(BYOBU_CONFIG_DIR, 0755) f = open(RELOAD_FLAG,'w') f.close() commands.getoutput(RELOAD_CMD) except: True def terminal_size(): ### decide on *some* terminal size cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) # try open fds if not cr: # ...then ctty try: fd = os.open(os.ctermid(), os.O_RDONLY) cr = ioctl_GWINSZ(fd) os.close(fd) except: pass if not cr: # env vars or finally defaults try: cr = (env['LINES'], env['COLUMNS']) except: cr = (25, 80) return int(cr[1]-5), int(cr[0]-5) # reverse rows, cols def menu(snackScreen, size, isInstalled): if isInstalled: installtext=_("Byobu currently launches at login (toggle off)") else: installtext=_("Byobu currently does not launch at login (toggle on)") li = Listbox(height = 6, width = 60, returnExit = 1) li.append(_("Help -- Quick Start Guide"), 1) li.append(_("Toggle status notifications"), 2) li.append(_("Change escape sequence"), 3) li.append(installtext, 4) bb = ButtonBar(snackScreen, (("Exit", "exit", ESC),), compact=1) g = GridForm(snackScreen, _(" Byobu Configuration Menu"), 1, 2) g.add(li, 0, 0, padding=(4,2,4,2)) g.add(bb, 0, 1, padding=(1,1,0,0)) if bb.buttonPressed(g.runOnce()) == "exit": return 0 else: return li.current() def messagebox(snackScreen, width, height, title, text, scroll=0, \ buttons=((_("Okay"), "okay"),(_("Cancel"), "cancel", ESC)) ): t = Textbox(width, height, text, scroll=scroll ) bb = ButtonBar(snackScreen, buttons, compact = 1) g = GridForm(snackScreen, title, 1, 2) g.add(t, 0, 0, padding=(0,0,0,0)) g.add(bb, 0, 1, padding=(1,1,0,0)) return bb.buttonPressed(g.runOnce()) def help(snackScreen, size, config): f=file(DOC+'/help.'+BYOBU_BACKEND+'.txt') text=f.read() f.close() text=text.replace("", getesckey(), 1) text=text.replace("_VER_", commands.getoutput("byobu -v | head -n1 | " + BYOBU_SED + " 's/.* //'"), 1) t = Textbox(67, 16, text, scroll=1, wrap=1) bb = ButtonBar(snackScreen, ((_("Menu"), "menu", ESC),), compact = 1) g = GridForm(snackScreen, _("Byobu Help"), 2, 4) g.add(t, 1, 0) g.add(bb, 1, 1, padding=(1,1,0,0)) button = bb.buttonPressed(g.runOnce()) return 100 def readstatus(): status={} glo = {} loc = {} for f in [SHARE+'/status/status', BYOBU_CONFIG_DIR+'/status']: if os.path.exists(f): try: execfile(f, glo, loc) except: error("Invalid configuration [%s]" % f) if BYOBU_BACKEND == "tmux": items = "%s %s" % (loc["tmux_left"], loc["tmux_right"]) else: items = "%s %s %s %s" % (loc["screen_upper_left"], loc["screen_upper_right"], loc["screen_lower_left"], loc["screen_lower_right"]) for i in items.split(): if i.startswith("#"): i = i.replace("#", "") status[i] = "0" else: status[i] = "1" li=[] keys = status.keys() keys.sort() for i in keys: window=[int(status[i]), i] li.append(window) return li def genstatusstring(s, status): new = "" glo = {} loc = {} execfile(SHARE+'/status/status', glo, loc) for i in loc[s].split(): if i.startswith("#"): i = i.replace("#", "") if status[i] == 1: new += " " + i else: new += " #" + i return new def writestatus(items): status={} path = BYOBU_CONFIG_DIR+'/status' for i in items: status[i[1]] = i[0] # BYOBU_SED is hacky here, but effective if BYOBU_BACKEND == "tmux": for key in ["tmux_left", "tmux_right"]: val = genstatusstring(key, status) commands.getoutput("%s -i -e '/^%s=/d' %s" % (BYOBU_SED, key, path)) commands.getoutput("echo '%s=\"%s\"' >> %s" % (key, val, path)) else: for key in ["screen_upper_left", "screen_upper_right", "screen_lower_left", "screen_lower_right"]: val = genstatusstring(key, status) commands.getoutput("%s -i -e '/^%s=/d' %s" % (BYOBU_SED, key, path)) commands.getoutput("echo '%s=\"%s\"' >> %s" % (key, val, path)) def togglestatus(snackScreen, size): itemlist=readstatus() rl=Label("") r=CheckboxTree(12, scroll=1) count=0 for item in itemlist: if item[0] != -1: r.append(item[1],count,selected=item[0]) count=count+1 bb = ButtonBar(snackScreen, ((_("Apply"), "apply"), (_("Cancel"), "cancel", ESC)), compact = 1) g = GridForm(snackScreen, _("Toggle status notifications"), 2, 4 ) g.add(rl, 0, 0, anchorLeft=1, anchorTop=1, padding=(4,0,0,1)) g.add(r, 1, 0) g.add(bb, 1, 1, padding=(4,1,0,0)) if bb.buttonPressed(g.runOnce()) != "cancel": count=0 for item in itemlist: if item[0] != -1: item[0] = r.getEntryValue(count)[1] count=count+1 writestatus(itemlist) reload_required() return 100 def install(snackScreen, size, isInstalled): if isInstalled: out = commands.getoutput("byobu-launcher-uninstall") if out == "": out = _("Byobu will not be launched next time you login.") button = messagebox(snackScreen, 60, 2, _("Message"), out, buttons=((_("Menu"), ))) return 101 else: out = commands.getoutput("byobu-launcher-install") if out == "": out = _("Byobu will be launched automatically next time you login.") button = messagebox(snackScreen, 60, 2, "Message", out, buttons=((_("Menu"), ))) return 100 def appendtofile(p, s): f = open(p, 'a') try: f.write(s) except IOError: f.close() return f.close() return def getesckey(): path=BYOBU_CONFIG_DIR+'/keybindings' if not os.path.exists(path): return DEF_ESC line = commands.getoutput("grep ^escape "+path) if line == "": return DEF_ESC esc = line[line.find('^')+1] if esc == "`": esc = " " return esc def setesckey(key): path = BYOBU_CONFIG_DIR+'/keybindings' if key != "": if key == " ": key = "`" u = key[0].upper() l = key[0].lower() if os.path.exists(path): out = commands.getoutput(BYOBU_SED+" -i -e 's/^escape.*$//' "+path) appendtofile(path, "escape ^"+u+l+"\n") out = commands.getoutput(BYOBU_SED+" -i -e 's/^register.*$//' "+path) out = commands.getoutput("grep -sh '^register x' "+SHARE+"/keybindings/*keys") appendtofile(path, out+"\n") out = commands.getoutput(BYOBU_SED+" -i -e 's/\"^^/\"\^"+l+"/g' "+path) out = commands.getoutput(BYOBU_SED+" -i -e '/^$/d' "+path) def chgesc(snackScreen, size): esc=Entry(2, text=getesckey(), returnExit=1) escl=Label(_("Escape key: ctrl-")) bb = ButtonBar(snackScreen, ((_("Apply"), "apply"), (_("Cancel"), "cancel", ESC)), compact = 1) g = GridForm(snackScreen, _("Change escape sequence"), 2, 4 ) g.add(escl, 0, 0, anchorLeft=1, padding=(1,0,0,1)) g.add(esc, 1, 0, anchorLeft=1) g.add(bb, 1, 1) g.setTimer(100) loop=1 while loop: which=g.run() if which == "TIMER": val=esc.value() if len(val) > 1: esc.set(val[1]) # Ensure that escape sequence is not \ or / if val == '/' or val == '\\': esc.set(DEF_ESC) # Ensure that the escape sequence is not set to a number try: dummy = int(esc.value()) esc.set(DEF_ESC) except: # do nothing dummy = "foo" else: loop=0 snackScreen.popWindow() button = bb.buttonPressed(which) if button != "cancel": setesckey(esc.value()) reload_required() if button == "exit": return 0 return 100 def autolaunch(): if os.path.exists(BYOBU_CONFIG_DIR+"/disable-autolaunch"): return 0 if commands.getstatusoutput('grep -qs byobu-launch %s/.profile' % HOME)[0] == 0: return 1 if os.path.exists("/etc/profile.d/Z98-%s.sh" % PKG): return 1 return 0 def main(): """This is the main loop of our utility """ size = terminal_size() snackScreen = SnackScreen() snackScreen.drawRootText(1,0,_('Byobu Configuration Menu')) snackScreen.pushHelpLine(_(' between elements | selects | exits')) config = SafeConfigParser() isInstalled = autolaunch() tag = 100 while tag > 0 : tag = menu(snackScreen, size, isInstalled) if tag == 1: tag = help(snackScreen, size, config) elif tag == 2: tag = togglestatus(snackScreen, size) elif tag == 3: tag = chgesc(snackScreen, size) elif tag == 4: tag = install(snackScreen, size, isInstalled) isInstalled = autolaunch() snackScreen.finish() sys.exit(0) if __name__ == "__main__": main()