#!@PYTHON@
# -*- mode: Python; indent-tabs-mode: nil; -*-

import optparse
import os
import re
import signal
import subprocess
import sys
import termios

def show_version(option, opt_str, value, parser):
    print "GNOME Shell @VERSION@"
    sys.exit()

def get_running_session_environs():
    wanted_environment = ['DBUS_SESSION_BUS_ADDRESS', 'DISPLAY', 'XDG_DATA_DIRS',
                          'XAUTHORITY', 'XDG_SESSION_COOKIE', 'ORBIT_SOCKETDIR',
                          'SESSION_MANAGER']
    num_re = re.compile('^[0-9]+$')
    myuid = os.getuid()
    if not os.path.isdir('/proc'):
        return {}
    for filename in os.listdir('/proc'):
        if not num_re.match(filename):
            continue
        piddir = '/proc/' + filename
        try:
            stat = os.stat(piddir)
        except OSError, e:
            continue
        if not stat.st_uid == myuid:
            continue
        try:
            f = open(piddir + "/cmdline")
            command = f.read()
            f.close()
        except IOError, e:
            continue
        # /proc/cmdline is separated and terminated by NULs
        command = command.split("\x00")[0]
        command = os.path.basename(command)
        if command != 'gnome-session':
            continue
        try:
            f = open(os.path.join(piddir, 'environ'))
        except OSError, e:
            continue
        environ_data = f.read()
        f.close()
        # There's a trailing null at the last one, so remove the
        # empty string
        environs = environ_data.split('\0')[:-1]
        # Rumor has it the presence of just FOO (instead of FOO=bar)
        # represents a deleted environment variable
        environs = filter(lambda x: '=' in x, environs)
        # Turn it into a dictionary
        environs = dict(map(lambda x: x.split('=', 1), environs))
        result = {}
        for key in wanted_environment:
            if key in environs:
                result[key] = environs[key]
        return result

def start_shell():
    self_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
    running_from_source_tree = os.path.exists(os.path.join(self_dir, 'gnome-shell-jhbuild.in'))

    # Set up environment
    env = dict(os.environ)
    if running_from_source_tree:
        top_dir = os.path.dirname(self_dir)

        typelib_dir = os.path.join(top_dir, "src")
        if 'GI_TYPELIB_PATH' in os.environ:
            typelib_dir += ':%s' % (os.environ['GI_TYPELIB_PATH'],)

        env.update({'GNOME_SHELL_JS'       : os.path.join(top_dir, "js"),
                    'GNOME_SHELL_BINDIR'   : self_dir,
                    'GI_TYPELIB_PATH'      : typelib_dir,
                    'GNOME_SHELL_DATADIR'  : os.path.join(top_dir, "data"),
                    'GSETTINGS_SCHEMA_DIR' : os.path.join(top_dir, "data") })

    args = []
    if options.debug:
        debug_command = options.debug_command.split()
        if running_from_source_tree:
            args += [os.path.join(top_dir, 'libtool'), '--mode=execute']
        args += debug_command

    args.append(os.path.join(self_dir, 'gnome-shell-real'))
    if options.replace:
        args.append('--replace')
    if options.sync:
        args.append('--sync')
    return subprocess.Popen(args, env=env)

def run_shell():
    if options.debug:
        # Record initial terminal state so we can reset it to that
        # later, in case we kill gdb at a bad time
        termattrs = termios.tcgetattr(0);

    normal_exit = False

    if options.verbose:
        print "Starting shell"

    shell = None
    try:
        shell = start_shell()

        # Wait for shell to exit
        if options.verbose:
            print "Waiting for shell to exit"
        shell.wait()

    except KeyboardInterrupt, e:
        try:
            os.kill(shell.pid, signal.SIGKILL)
        except:
            pass
        shell.wait()
    finally:
        if shell is None:
            print "Failed to start shell"
        elif shell.returncode == 0:
            normal_exit = True
            if options.verbose:
                print "Shell exited normally"
        elif shell.returncode < 0:
            # Python has no mapping for strsignal; not worth using
            # ctypes for this.
            print "Shell killed with signal %d" % - shell.returncode
        else:
            # Normal reason here would be losing connection the X server
            if options.verbose:
                print "Shell exited with return code %d" % shell.returncode

        if options.debug:
            termios.tcsetattr(0, termios.TCSANOW, termattrs);

    return normal_exit

# Main program

parser = optparse.OptionParser()
parser.add_option("-r", "--replace", action="store_true",
                  help="Replace the running metacity/gnome-panel")
parser.add_option("-g", "--debug", action="store_true",
                  help="Run under a debugger")
parser.add_option("", "--debug-command", metavar="COMMAND",
                  help="Command to use for debugging (defaults to 'gdb --args')")
parser.add_option("-v", "--verbose", action="store_true")
parser.add_option("", "--sync", action="store_true")
parser.add_option("", "--version", action="callback", callback=show_version,
                  help="Display version and exit")

options, args = parser.parse_args()

if args:
    parser.print_usage()
    sys.exit(1)

# Handle ssh logins
if 'DISPLAY' not in os.environ:
    running_env = get_running_session_environs()
    os.environ.update(running_env)

if options.debug_command:
    options.debug = True
elif options.debug:
    options.debug_command = "gdb --args"

normal_exit = run_shell()
if normal_exit:
    sys.exit(0)
else:
    sys.exit(1)
