#!/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)