#!/usr/bin/python2
##############################################################################
# Mount or unmount a removeable device
# Author: Chris Rouch
# Date: 13/10/2003
# Changelog:
#
# Copyright (c) Chris Rouch 2003
#
# 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; either version 2 of the License, or
# (at your option) any later version.
#
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# or see http://www.gnu.org/licenses/gpl.txt
##############################################################################
import gtk
import os
import getopt
import sys
import re
import pango
import commands
######################################################################
# constants
MOD1_MASK = 1 << 3
SHIFT_MASK = 1 << 0
CONTROL_MASK = 1 << 2
TITLESIZE = 24000
LABELSIZE = 18000
######################################################################
class ButtonBox:
def gettip(self,drive):
"""get the tip for the state of this drive"""
if self.state[drive]:
tip=drive + ' mounted'
else:
tip=drive + ' not mounted'
return tip
def getstate(self,drive):
"""get the state of this drive"""
mounted=commands.getoutput('mount')
for x in mounted.split('\n'):
if re.search(drive,x):
return 1
return 0
def togglestate(self,drive):
"""toggle the state of this drive"""
if self.state[drive]:
res=commands.getoutput("umount " + drive)
else:
res=commands.getoutput("mount " + drive)
if res:
self.complain(res)
def complain(self,res):
"""display a dialog with the output received"""
dialog = gtk.Dialog("Output from mount command",self.window)
label = gtk.Label(res)
label.set_use_markup(gtk.TRUE)
tstr='' + res + ''
label.set_markup(tstr)
dialog.vbox.pack_start(label, gtk.TRUE, gtk.TRUE, 0)
label.show()
button = gtk.Button(None,gtk.STOCK_OK);
button.connect("button_press_event", self.popdown,dialog)
dialog.action_area.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
button.show()
dialog.show()
def geticon(self,drive):
"""get the icon for the state of this drive"""
if self.state[drive]:
icon=self.micons[drive]
else:
icon=self.uicons[drive]
if re.match("\$HOME",icon):
icon=re.sub("\$HOME",os.environ["HOME"],icon)
return icon
def action(self, widget, event,drive):
"""toggle the drive state and update the icon"""
if event.button == 1:
# left button
self.togglestate(drive)
self.update(drive)
def update(self,drive):
"""update the state and then the icon for this drive"""
self.state[drive]=self.getstate(drive)
tip=self.gettip(drive)
button=self.buttons[drive]
image=button.get_child();
ifile=self.geticon(drive);
image.set_from_file(ifile)
image.show()
self.tooltips.set_tip(button, tip,"")
def updateall(self):
"""update the state and then the icon for all drives"""
drives=self.state.keys()
for drive in drives:
self.update(drive)
return gtk.TRUE
def popdown(self, widget, event,w):
"""popdown the dialog"""
if event.button == 1:
# left button
w.destroy()
def keypress(self, widget, event,*args):
"""check for keypresses, exit on ctrl-q"""
key = event.keyval
if event.state & CONTROL_MASK:
if chr(key) == 'q':
gtk.main_quit()
def addtitle(self,table,title,width):
"""add a title to the top of the table"""
label = gtk.Label(title);
font_desc = pango.FontDescription('Serif')
label.modify_font(font_desc)
label.set_name('mytitle')
label.set_use_markup(gtk.TRUE)
tstr='' + title + ''
label.set_markup(tstr)
table.attach(label, 0, width, 0, 1,xpadding=0,ypadding=0)
def addbutton(self,table,x,y,drive,icon,tip):
"""add a button to the table at x,y"""
button = gtk.Button();
button.set_name('mybutton')
self.buttons[drive]=button
image = gtk.Image()
image.set_from_file(icon)
image.set_padding(0,0)
button.add(image);
button.connect("button_press_event", self.action,drive)
button.set_relief(gtk.RELIEF_NONE)
self.tooltips.set_tip(button, tip,"")
table.attach(button, x, x+1, y, y+1,xpadding=0,ypadding=0)
def __init__(self,blist,rows=1,cols=1,title=None,name=None):
"""Create a button box according to the supplied blist"""
self.state={};
self.micons={};
self.uicons={};
self.buttons={};
# Create a new window
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_name("buttonbox")
self.window.connect("key_press_event", self.keypress)
# create tooltips object
self.tooltips = gtk.Tooltips()
# Create a table
table = gtk.Table(rows, cols, gtk.FALSE)
table.set_col_spacings(0)
table.set_row_spacings(0)
# Put the table in the main window
self.window.add(table)
# Set the window title
x=0
y=0
if title:
self.window.set_title(title)
self.addtitle(table,title,cols)
y=y+1
elif name:
self.window.set_title(name)
# add the buttons
for tuple in blist:
drive=tuple[0].strip()
self.uicons[drive]=tuple[1].strip()
self.micons[drive]=tuple[2].strip()
self.state[drive]=self.getstate(drive)
icon=self.geticon(drive)
tip=self.gettip(drive)
self.addbutton(table,x,y,drive,icon,tip);
x=x+1
if x>= cols:
x=0
y=y+1
self.window.show_all()
msecs=secs *1000;
timeout_handler_id = gtk.timeout_add(msecs, self.updateall)
######################################################################
def ReadArgs(file):
"""parse a file for a list of drives and icons
format is
drive,unmounted icon,mounted icon
$HOME is understood, otherwise use full path
"""
options=[]
try:
f=open(file)
except:
print file, " not found"
return
for line in f.xreadlines():
line=line.rstrip()
if line:
options.append(re.split(",",line))
return options
def main():
gtk.main()
return 0
if __name__ == "__main__":
file=''
rows=-1
cols=-1
title=''
name=''
secs=60
options=[]
opts,args = getopt.getopt(sys.argv[1:],'d:f:t:n:r:c:s:hv')
for opt in opts:
if opt[0] == '-f':
file=opt[1]
elif opt[0] == '-h':
rows=1
elif opt[0] == '-v':
cols=1
elif opt[0] == '-n':
name=opt[1]
elif opt[0] == '-t':
title=opt[1]
elif opt[0] == '-d':
dir=opt[1]
elif opt[0] == '-r':
rows=opt[1]
elif opt[0] == '-c':
cols=opt[1]
elif opt[0] == '-s':
secs=opt[1]
if file:
options=ReadArgs(file)
else:
for arg in args:
buttons.append(re.split(",",arg))
if options:
count=len(options)
if rows <= 0:
if cols <=0:
# default horizontal strip
rows=1
cols=count
else:
rows=int(count)/int(cols)
if int(count)%int(cols) > 0:
rows+=1
else:
cols=int(count)/int(rows)
if int(count)%int(rows) > 0:
cols+=1
cols=int(cols)
rows=int(rows)
ButtonBox(options,rows,cols,title,name)
main()
# only get here if we quit
# no options