#!/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)
        # Because the resize anchor in Natty is obscenely large
        self.kioskWindow.set_property('resizable', 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:
            if os.path.exists("/var/run/athena-nologin"):
                errDlg = gtk.MessageDialog(self.kioskWindow, 
                                           gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                                           gtk.MESSAGE_ERROR,
                                           gtk.BUTTONS_CLOSE,
                                           "This machine is currently taking an update and the kiosk browser can't be launched.  Please try again later.")
                errDlg.run()
                errDlg.destroy()
            else:
                self.kioskDialog.run()

    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()
