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