#!/usr/bin/python -Wall import dbus import dbus.mainloop.glib import gtk import gtk.glade import gobject import time import os import sys import subprocess from optparse import OptionParser GLADE_FILE = "/usr/share/debathena-kiosk/gdm-launch-kiosk.glade" LAUNCH_COMMAND = "/usr/lib/debathena-kiosk/launch-kiosk" SM_DBUS_NAME = "org.gnome.SessionManager" SM_DBUS_PATH = "/org/gnome/SessionManager" SM_DBUS_INTERFACE = "org.gnome.SessionManager" SM_CLIENT_DBUS_INTERFACE = "org.gnome.SessionManager.ClientPrivate" APP_ID = "debathena-kiosk" class Kiosk: def __init__(self): self.sessionEnding = False self.sessionBus = dbus.SessionBus() try: self.register_with_sm() self.init_sm_client() except: print "Warning: Cannot register with session manager." try: self.xml = gtk.glade.XML(GLADE_FILE) except: print "Failed to create Glade XML object." sys.exit(1) self.kioskWindow = self.xml.get_widget('KioskWindow') self.kioskDialog = self.xml.get_widget('KioskDialog') self.xml.signal_autoconnect(self) # Turn off all window decorations for the login screen. self.kioskWindow.set_decorated(False) self.kioskDialog.set_decorated(False) # Position the window near the bottom of the screen, in the center. self.kioskWindow.set_gravity(gtk.gdk.GRAVITY_SOUTH) width, height = self.kioskWindow.get_size() self.kioskWindow.move((gtk.gdk.screen_width() - width) / 2, gtk.gdk.screen_height() - height - 80) self.kioskWindow.show_all() def kioskButton_on_click(self, button): if not self.sessionEnding: self.kioskDialog.show() def kioskDialogResponseHandler(self, dialog, response_id): if response_id == 1 and not self.sessionEnding: self.launch() self.kioskDialog.hide() def launch(self): pid = os.fork() if pid == 0: # Start a new session. os.setsid(); # Fork another child to launch the command. pid = os.fork() if pid == 0: # Here in the second child, exec the command. try: os.execlp("sudo", "sudo", "-n", LAUNCH_COMMAND) except OSError, e: print "error: Could not run %s as root: %s" % (LAUNCH_COMMAND, e.strerror) os._exit(255) else: # The first child exits immediately. os._exit(0) else: # Here in the parent: wait for the first child to exit. (pid, status) = os.waitpid(pid, 0) if status != 0: print "error launching command, status %d" % status # Connect to the session manager, and register our client. def register_with_sm(self): proxy = self.sessionBus.get_object(SM_DBUS_NAME, SM_DBUS_PATH) sm = dbus.Interface(proxy, SM_DBUS_INTERFACE) autostart_id = os.getenv("DESKTOP_AUTOSTART_ID", default="") self.smClientId = sm.RegisterClient(APP_ID, autostart_id) # Set up to handle signals from the session manager. def init_sm_client(self): proxy = self.sessionBus.get_object(SM_DBUS_NAME, self.smClientId) self.smClient = dbus.Interface(proxy, SM_CLIENT_DBUS_INTERFACE) self.smClient.connect_to_signal("QueryEndSession", self.sm_on_QueryEndSession) self.smClient.connect_to_signal("EndSession", self.sm_on_EndSession) self.smClient.connect_to_signal("CancelEndSession", self.sm_on_CancelEndSession) self.smClient.connect_to_signal("Stop", self.sm_on_Stop) # Here on a QueryEndSession signal from the session manager. def sm_on_QueryEndSession(self, flags): self.sessionEnding = True # Response args: is_ok, reason. self.smClient.EndSessionResponse(True, "") # Here on an EndSession signal from the session manager. def sm_on_EndSession(self, flags): self.sessionEnding = True # Response args: is_ok, reason. self.smClient.EndSessionResponse(True, "") # Here on a CancelEndSession signal from the session manager. def sm_on_CancelEndSession(self): self.sessionEnding = False # Here on a Stop signal from the session manager. def sm_on_Stop(self): gtk.main_quit() def main(): if not os.access(GLADE_FILE, os.R_OK): print 'error: Unable to read glade file "' + GLADE_FILE + '"' sys.exit(1) dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) Kiosk() gtk.main() if __name__ == '__main__': main()