#!/usr/bin/python
# -*- coding: UTF-8 -*-
import os
import sys
import string
import gtk
import gobject
import gtk.glade
try:
import gnomecanvas
except:
import gnome.canvas as gnomecanvas
from gtk import RcStyle
from time import localtime, strftime
# make the path below a link to the theme you want
# example: sudo ln -s /usr/share/ldm/themes/Ubuntu /usr/share/ldm/themes/default
themedir = "/usr/share/ldm/themes/default"
class GTKGreeter:
def run(self):
self.ok = False
self.flag = 0
# set default gtk theme
try:
gtk.rc_parse ('/usr/lib/ltsp/greeters/gtkrc')
except:
gtk.rc_parse ('/usr/share/themes/Clearlooks/gtk-2.0/gtkrc')
# default settings for lang and session
self.language = ["Default", "None"]
self.session = ["Default", "None", "NOIP"]
# get glade widget tree
try:
self.wTree = gtk.glade.XML('/usr/lib/ltsp/greeters/greeter.glade')
except:
self.wTree = gtk.glade.XML('greeter.glade')
# care for look and feel
self.set_cursor()
self.theme_engine()
self.draw_login_window()
# configurable options
# self.draw_buttons() # session and lang, should be wrapped by a config option
self.draw_bottom_bar(False) # set to True if you want a clock
self.draw_shutdown_button()
self.win.show_all()
# the entry field has focus by default
self.entry.grab_focus()
gtk.main()
if self.ok == True:
print self.username
print self.password
#print self.session
#print self.language
return True
return False
def draw_login_window(self):
# get the username/password entry from the glade tree
self.entry = self.wTree.get_widget("entry")
self.entry.unparent()
self.entry.connect("activate", lambda w: self.switch_entry(self.flag))
self.sq_width=250
self.sq_height=80
self.sub_height=40
self.root.add(gnomecanvas.CanvasRect, x1 = -(self.sq_width/2)+self.diff,
y1 = +(self.sq_height), x2 = +(self.sq_width/2)+self.diff,
y2 = +(self.sq_height*2), fill_color = self.loginwin_color)
self.entrylabel = self.root.add(gnomecanvas.CanvasText,
markup = 'Username:',
fill_color = self.foreground_color, x = -33+self.diff, y = 100)
# entry with small frame
self.root.add(gnomecanvas.CanvasRect, x1 = -71+self.diff,
y1 = 114, x2 = 71+self.diff,
y2 = 138, fill_color = self.frame_color)
self.root.add(gnomecanvas.CanvasWidget, x = -70+self.diff, y = 115,
widget = self.entry,
width = 140, height = 22)
self.entry.hide()
def draw_buttons(self):
# get the buttons for lang and session selector from the glade tree
lang_butt = self.wTree.get_widget("lang_button")
lang_butt.unparent()
sess_butt = self.wTree.get_widget("sess_button")
sess_butt.unparent()
# define the button actions
sess_butt.connect("clicked", lambda w: self.select_session())
lang_butt.connect("clicked", lambda w: self.select_language())
# draw the lang and session selector
self.root.add(gnomecanvas.CanvasRect, x1 = -(self.sq_width/2)+self.diff,
y1 = +(self.sub_height)+125, x2 = +(self.sq_width/2)+self.diff,
y2 = +(self.sub_height*2)+125, fill_color = self.loginwin_color)
self.root.add(gnomecanvas.CanvasWidget, x = -(self.sq_width/2)+5+self.diff, y = +(self.sub_height)+130,
widget = lang_butt,
width = 110, height = 32)
self.root.add(gnomecanvas.CanvasWidget, x = -(self.sq_width/2)+135+self.diff, y = +(self.sub_height)+130,
widget = sess_butt,
width = 110, height = 32)
# get some additional glade entrys for session and lang selector
self.sess_box = self.wTree.get_widget("sess_vbox")
self.sess_box.unparent()
self.lang_box = self.wTree.get_widget("lang_vbox")
self.lang_box.unparent()
def draw_shutdown_button(self):
poweroff = gtk.Button('')
poweroff.connect("clicked", lambda w: self.shutdown())
try:
bg = gtk.gdk.pixbuf_new_from_file(themedir+'/shutdown.png')
img = gtk.Image()
img.set_from_pixbuf(bg)
poweroff.set_image(img)
poweroff.set_relief('GTK_RELIEF_NONE')
except:
poweroff.set_label('I/O')
self.root.add(gnomecanvas.CanvasWidget, x = -((self.width/2)-50), y = (self.height/2)+8,
widget = poweroff,
width = 46, height = 46)
def shutdown(self):
os.system('poweroff -fp')
def draw_bottom_bar(self, show_timer):
# draw the bottom bar, sysname and timer
sysname = os.uname()
timew = 0
timeh = 0
# get the labels from the glade tree
self.sysname = self.wTree.get_widget("host_label")
self.sysname.unparent()
self.timelabel = self.wTree.get_widget("time_label")
self.timelabel.unparent()
self.sysname.set_markup(''+str(sysname[1])+' //')
# show timer if wanted
if show_timer == True:
timew, timeh = self.timelabel.size_request()
self.timelabel.set_markup(strftime('%a %b %d, %H:%M', localtime()))
self.timer = self.root.add(gnomecanvas.CanvasWidget, x = ((self.orig_width/2)-timew), y = (self.height/2)+timeh,
widget = self.timelabel,
width = timew, height = timeh)
# refresh the clock all 30 sec
gobject.timeout_add(30000, lambda: self.update_time())
# get label sizes for drawing
namew, nameh = self.sysname.size_request()
self.root.add(gnomecanvas.CanvasRect, x1 = -(self.width/2),
y1 = (self.height/2)+10, x2 = self.width,
y2 = self.height, fill_color = self.foreground_color)
self.root.add(gnomecanvas.CanvasWidget, x = ((self.orig_width/2)-namew-timew-10), y = (self.height/2)+nameh,
widget = self.sysname,
width = namew, height = nameh)
def theme_engine(self):
# draw the window with canvas
canvas = self.wTree.get_widget("canvas")
self.win = self.wTree.get_widget("window")
self.root = canvas.root().add(gnomecanvas.CanvasGroup)
# get screensize
width, self.height = gtk.gdk.get_default_root_window().get_size()
self.orig_width = width
self.width = int(float(width+(width*0.04))) # lets overlap a bit :)
self.diff = (self.width-self.orig_width)/2 # to make sure the canvas
# has no grey border
# Theme Engine with sane fallback values
# for potentially broken themes
try:
# get the background pixmap and scale it to screenwidth
bg = gtk.gdk.pixbuf_new_from_file(themedir+'/background.png')
# read colors from theme file
colors = open(themedir+'/colors')
colorlist = colors.readlines()
# parse colorlist
for color in colorlist:
if string.find(color, "=") > 0 and not color.startswith('#'):
val = color.split(' ')[2].rstrip().strip('"')
if color.startswith('frame_color'):
self.frame_color = val
elif color.startswith('foreground'):
self.foreground_color = val
elif color.startswith('background'):
self.background_color = val
elif color.startswith('clockforeground'):
self.clockforeground_color = val
elif color.startswith('loginwin_color'):
self.loginwin_color = val
# put background color up
self.root.add(gnomecanvas.CanvasRect, x1 = -(self.width/2),
y1 = -(self.height/2), x2 = (self.width/2),
y2 = (self.height/2)+self.diff, fill_color = self.background_color)
# put the image on the canvas
self.root.add(gnomecanvas.CanvasPixbuf, pixbuf = bg,
x = -(bg.get_width()/2),
y = -(bg.get_height()/2+40), anchor = "nw")
except:
# fallback if no theme is available
self.frame_color = "#000000"
self.foreground_color = "#101010"
self.clockforeground_color = "#ffffff"
self.loginwin_color = "#606060"
self.root.add(gnomecanvas.CanvasRect, x1 = -(self.width/2),
y1 = -(self.height/2), x2 = (self.width/2),
y2 = (self.height/2)+self.diff, fill_color = "#303030")
self.root.add(gnomecanvas.CanvasText,
markup = 'No Theme Found !\n'+
' Make sure the theme directorys in /usr/share/ldm/themes exist.\n'+
' /usr/share/ldm/themes/default must be a symlink to the\n'+
' directory containing the default theme. Please contact your\n'+
' administrator to fix the ldm installation on the LTSP server.',
fill_color = "#606060", x = self.diff, y = -50)
# make sure the window sits correctly on the root
self.win.set_size_request((self.width), (self.height))
self.win.set_decorated(False)
def set_cursor(self):
# set cursor
self.rootwin = gtk.gdk.get_default_root_window()
self.rootwin.set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
def update_time(self):
# refresh the date/time string
self.timelabel.set_markup(strftime('%a %b %d, %H:%M', localtime()))
return True
def switch_entry(self, flag):
# switch between username and password entry, make sure neither of them is empty
# and exit after the password was entered.
if len(self.entry.get_text()) == 0:
return
self.entrylabel.destroy()
if flag > 0:
self.password = self.entry.get_text()
session = self.session[1]
language = self.language[1]
self.rootwin.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
self.ok = True
gtk.main_quit()
else:
self.username = self.entry.get_text()
self.entry.set_text('')
self.entrylabel = self.root.add(gnomecanvas.CanvasText,
markup = 'Password:',
fill_color = self.foreground_color, x = -33+self.diff, y = 100)
self.entry.set_visibility(False)
#self.entry.set_invisible_char('●'.e)
self.flag = 1
def select_session(self):
# session selector - sessions should be read from a config file i.e. /etc/ldm/sessions.conf
# a Session entry should define the visible name (for the selector) the session manager
# command that gets executed on the remote server and optionally a server ip (that gives
# us xdmcp functionallity for free) which falls back to the bootserver if not set.
# (indeed there needs to be a entry in known_hosts for a potential other server)
okbutton = self.wTree.get_widget("sess_ok_button")
okbutton.connect("clicked", lambda w: destroy_all())
try:
self.selwin.show()
self.sess_box.show()
except:
self.selwin = self.root.add(gnomecanvas.CanvasWidget, x = -(100), y = 40,
widget = self.sess_box,
width = 250, height = 200)
self.selwin.show()
listview = self.wTree.get_widget("sess_treeview")
liststore = gtk.ListStore(str, str, str)
listview.set_model(liststore)
text = gtk.CellRendererText()
text1 = gtk.CellRendererText()
text2 = gtk.CellRendererText()
treeselection = listview.get_selection()
treeselection.set_mode(gtk.SELECTION_SINGLE)
column = gtk.TreeViewColumn("Sessions available")
column.pack_start(text, False)
column.pack_start(text1, False)
column.pack_start(text2, False)
column.set_attributes(text, markup=1)
listview.append_column(column)
liststore.append([self.session[1], self.session[0], self.session[2]])
# call populate function here to fill the list with:
# liststore.append(["Visible name", "session command to be executed", "server ip"])
self.sess_box.show()
listview.grab_focus()
def destroy_all():
try:
list,paths = treeselection.get_selected_rows()[0], treeselection.get_selected_rows()[1:]
name = list[paths[0][0]][1].split('\n')
command = list[paths[0][0]][0].split('\n')
host = list[paths[0][0]][2].split('\n')
self.session = [name, command, host]
self.sess_box.hide()
self.entry.grab_focus()
except:
return
def select_language(self):
# the selection of available languages must be server dependent, we should have a file that lists
# available languages for every session, what this selector shows should directly depend on the selection
# made in the session selector above
okbutton = self.wTree.get_widget("lang_ok_button")
okbutton.connect("clicked", lambda w: destroy_all())
try:
self.langwin.show()
self.lang_box.show()
except:
self.langwin = self.root.add(gnomecanvas.CanvasWidget, x = -(100), y = -80,
widget = self.lang_box,
width = 250, height = 400)
self.langwin.show()
listview = self.wTree.get_widget("lang_treeview")
liststore = gtk.ListStore(str, str)
listview.set_model(liststore)
text = gtk.CellRendererText()
text1 = gtk.CellRendererText()
treeselection = listview.get_selection()
treeselection.set_mode(gtk.SELECTION_SINGLE)
column = gtk.TreeViewColumn("Languages available")
column.pack_start(text, False)
column.pack_start(text1, False)
column.set_attributes(text, markup=1)
listview.append_column(column)
liststore.append([self.language[1], self.language[0]])
self.populate_langlist(liststore)
self.lang_box.show()
listview.grab_focus()
def destroy_all():
try:
list,paths = treeselection.get_selected_rows()[0], treeselection.get_selected_rows()[1:]
name = list[paths[0][0]][1].split('\n')
language = list[paths[0][0]][0].split('\n')
self.language = [name, language]
self.lang_box.hide()
self.entry.grab_focus()
except:
return
def populate_langlist(self, liststore):
try:
languages = open('/etc/locale.alias')
langlist = languages.readlines()
for language in langlist:
if not language.startswith('#'):
if string.find(language, "\t"):
lang = language.split('\t')
else:
lang = language.split(' ')
if len(lang) < 2:
tmp = lang[0].split(' ')
lang = tmp
if len(lang[0]) > 1:
try:
if lang[0].find("_") == -1:
nat, encoding = lang[-1].rstrip().split('.')
if encoding.startswith('ISO'):
encoding = nat
else:
encoding = nat+'.'+encoding
# add a check for langs supported by the selected session
liststore.append([encoding, lang[0].capitalize().encode()])
except:
# do nothing
failed_langs = []
failed_langs.append(lang[0])
except:
return
if not GTKGreeter().run():
sys.exit(1)