Replace start-in-Xephyr/start-replace with a new single "gnome-shell" script

The new script runs in "replace" mode if you pass --replace, or if there
isn't already a panel running, and in "Xephyr" mode otherwise.
This commit is contained in:
Dan Winship 2009-02-23 14:52:49 -05:00
parent 1fe32e30f5
commit 0763f5bc42
4 changed files with 256 additions and 260 deletions

View File

@ -1,136 +0,0 @@
from optparse import OptionParser
import os
import re
import subprocess
import sys
GLXINFO_RE = re.compile(r"^(\S.*):\s*\n((?:^\s+.*\n)*)", re.MULTILINE)
def _get_glx_extensions():
"""Return a tuple of server, client, and effective GLX extensions"""
glxinfo = subprocess.Popen(["glxinfo"], stdout=subprocess.PIPE)
glxinfo_output = glxinfo.communicate()[0]
glxinfo.wait()
glxinfo_map = {}
for m in GLXINFO_RE.finditer(glxinfo_output):
glxinfo_map[m.group(1)] = m.group(2)
server_glx_extensions = set(re.split("\s*,\s*", glxinfo_map['server glx extensions'].strip()))
client_glx_extensions = set(re.split("\s*,\s*", glxinfo_map['client glx extensions'].strip()))
glx_extensions = set(re.split("\s*,\s*", glxinfo_map['GLX extensions'].strip()))
return (server_glx_extensions, client_glx_extensions, glx_extensions)
class Launcher:
def __init__(self, use_tfp=True, accept_geometry=False):
self.use_tfp = use_tfp
# Figure out the path to the plugin when uninstalled
scripts_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
top_dir = os.path.dirname(scripts_dir)
self.plugin_dir = os.path.join(top_dir, "src")
self.js_dir = os.path.join(top_dir, "js")
self.data_dir = os.path.join(top_dir, "data")
parser = OptionParser()
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")
if accept_geometry:
parser.add_option("", "--geometry", metavar="GEOMETRY",
help="Specify screen geometry",
default="1024x768");
parser.add_option("-w", "--wide", action="store_true",
help="Use widescreen (1280x800)")
self.options, args = parser.parse_args()
if args:
parser.print_usage()
sys.exit(1)
if self.options.debug_command:
self.options.debug = True
self.debug_command = self.options.debug_command.split()
else:
self.debug_command = ["gdb", "--args"]
if accept_geometry and self.options.wide:
self.options.geometry = "1280x800"
def start_shell(self):
"""Starts gnome-shell. Returns a subprocess.Popen object"""
use_tfp = self.use_tfp
force_indirect = False
# Allow disabling usage of the EXT_texture_for_pixmap extension.
# FIXME: Move this to ClutterGlxPixmap like
# CLUTTER_PIXMAP_TEXTURE_RECTANGLE=disable.
if 'GNOME_SHELL_DISABLE_TFP' in os.environ and \
os.environ['GNOME_SHELL_DISABLE_TFP'] != '':
use_tfp = False
if use_tfp:
# Decide if we need to set LIBGL_ALWAYS_INDIRECT=1 to get the texture_from_pixmap
# extension; we take having the extension be supported on both the client and
# server but not in the list of effective extensions as a signal of needing
# to force indirect rendering.
#
# (The Xepyhr DRI support confuses this heuristic but we disable TFP in
# start-in-Xepyhr)
#
(server_glx_extensions, client_glx_extensions, glx_extensions) = _get_glx_extensions()
if ("GLX_EXT_texture_from_pixmap" in server_glx_extensions and
"GLX_EXT_texture_from_pixmap" in client_glx_extensions and
(not "GLX_EXT_texture_from_pixmap" in glx_extensions)):
force_indirect = True
# Now launch metacity-clutter with our plugin
env=dict(os.environ)
env.update({'GNOME_SHELL_JS' : self.js_dir,
'GNOME_SHELL_DATADIR' : self.data_dir,
'GI_TYPELIB_PATH' : self.plugin_dir,
'PATH' : os.environ.get('PATH', '') + ':' + self.plugin_dir,
'LD_LIBRARY_PATH' : os.environ.get('LD_LIBRARY_PATH', '') + ':' + self.plugin_dir,
'GNOME_DISABLE_CRASH_DIALOG' : '1'})
if force_indirect:
if self.options.verbose:
print "Forcing indirect GL"
# This is Mesa specific; the NVIDIA proprietary drivers drivers use
# __GL_FORCE_INDIRECT=1 instead. But we don't need to force indirect
# rendering for NVIDIA.
env['LIBGL_ALWAYS_INDIRECT'] = '1'
if not self.options.verbose:
# Unless verbose() is specified, only let gjs show errors and things that are
# explicitly logged via log() from javascript
env['GJS_DEBUG_TOPICS'] = 'JS ERROR;JS LOG'
if self.options.debug:
args = list(self.debug_command)
else:
args = []
plugin = os.path.join(self.plugin_dir, "libgnome-shell.la")
args.extend(['metacity', '--mutter-plugins=' + plugin, '--replace'])
if self.options.sync:
args.append('--sync')
return subprocess.Popen(args, env=env)
def is_verbose(self):
"""Returns whether the Launcher was started in verbose mode"""
return self.options.verbose
def get_geometry(self):
"""Returns the command-line specified geometry"""
return self.options.geometry

View File

@ -1,63 +0,0 @@
#!/usr/bin/python
import os
import random
import shutil
import signal
import subprocess
import sys
import tempfile
import time
from launcher import Launcher
# GL_EXT_texture_from_pixmap doesn't work in Xepyhr
launcher = Launcher(use_tfp=False, accept_geometry=True)
# Temporary directory to hold our X credentials
tmpdir = tempfile.mkdtemp("", "gnome-shell.")
try:
display = ":" + str(random.randint(10, 99))
xauth_file = os.path.join(tmpdir, "database")
# Create a random 128-byte key and format it as hex
f = open("/dev/urandom", "r")
key = f.read(16)
f.close()
hexkey = "".join(("%02x" % ord(byte) for byte in key))
# Store that in an xauthority file as the key for connecting to our Xephyr
retcode = subprocess.call(["xauth",
"-f", xauth_file,
"add", display, "MIT-MAGIC-COOKIE-1", hexkey])
if retcode != 0:
raise RuntimeError("xauth failed")
# Launch Xephyr
xephyr = subprocess.Popen(["Xephyr", display,
"-auth", xauth_file,
"-screen", launcher.get_geometry(),
"-host-cursor"])
os.environ['DISPLAY'] = display
os.environ['XAUTHORITY'] = xauth_file
# Wait for server to get going: LAME
time.sleep(1)
# Start some windows in our session. Specify explicit geometries
# so we don't end up with the title bars underneath the panel
subprocess.Popen(["xterm", "-geometry", "+30+30"])
subprocess.Popen(["xlogo", "-geometry", "-0-0"])
subprocess.Popen(["xeyes", "-geometry", "-0+30"])
# Now launch metacity-clutter with our plugin
shell = launcher.start_shell()
# Wait for Xephyr to exit
try:
retcode = xephyr.wait()
except KeyboardInterrupt, e:
os.kill(xephyr.pid, signal.SIGKILL)
finally:
shutil.rmtree(tmpdir)

View File

@ -1,61 +0,0 @@
#!/usr/bin/python
import os
import subprocess
import signal
from launcher import Launcher
launcher = Launcher()
def find_cmd (cmd_list):
"""
Takes a list of command candidates and returns the first one that exists.
Raises a system exit if none of the commands exist.
"""
for cmd in cmd_list:
if os.path.exists(cmd):
return cmd
raise SystemExit("None of the commands %s exist" % cmd_list)
try:
# Kill gnome-panel in a way that it won't autorespawn
pidof_cmd = find_cmd(["/sbin/pidof", "/bin/pidof", "/usr/bin/pidof"])
pidof = subprocess.Popen([pidof_cmd, "gnome-panel"], stdout=subprocess.PIPE)
pids = pidof.communicate()[0].split()
pidof.wait()
devnull = open("/dev/null", "w")
for pid in pids:
if launcher.is_verbose():
print "Terminating panel process %s" % pid
subprocess.call(["gdb", "-batch-silent",
"-ex", "call panel_session_do_not_restart()",
"-ex", "call exit(0)",
"-p", pid], stdout=devnull, stderr=devnull)
devnull.close()
if launcher.is_verbose():
print "Starting shell"
shell = launcher.start_shell()
# Wait for shell to exit
try:
if launcher.is_verbose():
print "Waiting for shell to exit"
shell.wait()
if launcher.is_verbose():
print "Shell is dead"
except KeyboardInterrupt, e:
os.kill(shell.pid, signal.SIGKILL)
shell.wait()
if launcher.is_verbose():
print "Shell killed"
finally:
# Restart gnome-panel and window manager
if launcher.is_verbose():
print "Restarting Metacity and Gnome Panel"
subprocess.Popen(["/usr/bin/metacity"])
subprocess.Popen(["/usr/bin/gnome-panel"])

256
src/gnome-shell Executable file
View File

@ -0,0 +1,256 @@
#!/usr/bin/python
import atexit
import optparse
import os
import random
import re
import shutil
import signal
import subprocess
import sys
import tempfile
import time
def find_cmd (cmd_list):
"""
Takes a list of command candidates and returns the first one that exists.
Raises a system exit if none of the commands exist.
"""
for cmd in cmd_list:
if os.path.exists(cmd):
return cmd
raise SystemExit("None of the commands %s exist" % cmd_list)
def pidof(command):
pidof_cmd = find_cmd(["/sbin/pidof", "/bin/pidof", "/usr/bin/pidof"])
pidof = subprocess.Popen([pidof_cmd, command], stdout=subprocess.PIPE)
pids = pidof.communicate()[0].split()
pidof.wait()
# pidof doesn't have a "current user only" option, so we may have
# gotten the pids of other users' processes. Fix that.
for pid in pids:
try:
os.kill(int(pid), 0)
return pid
except Exception, e:
pass
return None
def kill_gnome_panel(pid):
if options.verbose:
print "Terminating panel process %s" % pid
devnull = open("/dev/null", "w")
subprocess.call(["gdb", "-batch-silent",
"-ex", "call panel_session_do_not_restart()",
"-ex", "call exit(0)",
"-p", pid], stdout=devnull, stderr=devnull)
devnull.close()
def start_xephyr():
tmpdir = tempfile.mkdtemp("", "gnome-shell.")
atexit.register(shutil.rmtree, tmpdir)
display = ":" + str(random.randint(10, 99))
xauth_file = os.path.join(tmpdir, "database")
# Create a random 128-bit key and format it as hex
f = open("/dev/urandom", "r")
key = f.read(16)
f.close()
hexkey = "".join(("%02x" % ord(byte) for byte in key))
# Store that in an xauthority file as the key for connecting to our Xephyr
retcode = subprocess.call(["xauth",
"-f", xauth_file,
"add", display, "MIT-MAGIC-COOKIE-1", hexkey])
if retcode != 0:
raise RuntimeError("xauth failed")
# Launch Xephyr
xephyr = subprocess.Popen(["Xephyr", display,
"-auth", xauth_file,
"-screen", options.geometry,
"-host-cursor"])
os.environ['DISPLAY'] = display
os.environ['XAUTHORITY'] = xauth_file
# Wait for server to get going: LAME
time.sleep(1)
# Start some windows in our session.
subprocess.Popen(["xterm", "-geometry", "+30+30"])
subprocess.Popen(["xlogo", "-geometry", "-0-0"])
subprocess.Popen(["xeyes", "-geometry", "-0+30"])
return xephyr;
GLXINFO_RE = re.compile(r"^(\S.*):\s*\n((?:^\s+.*\n)*)", re.MULTILINE)
def _get_glx_extensions():
"""Return a tuple of server, client, and effective GLX extensions"""
glxinfo = subprocess.Popen(["glxinfo"], stdout=subprocess.PIPE)
glxinfo_output = glxinfo.communicate()[0]
glxinfo.wait()
glxinfo_map = {}
for m in GLXINFO_RE.finditer(glxinfo_output):
glxinfo_map[m.group(1)] = m.group(2)
server_glx_extensions = set(re.split("\s*,\s*", glxinfo_map['server glx extensions'].strip()))
client_glx_extensions = set(re.split("\s*,\s*", glxinfo_map['client glx extensions'].strip()))
glx_extensions = set(re.split("\s*,\s*", glxinfo_map['GLX extensions'].strip()))
return (server_glx_extensions, client_glx_extensions, glx_extensions)
def start_shell():
# Figure out the path to the plugin when uninstalled
src_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
top_dir = os.path.dirname(src_dir)
plugin_dir = os.path.join(top_dir, "src")
js_dir = os.path.join(top_dir, "js")
data_dir = os.path.join(top_dir, "data")
force_indirect = False
if use_tfp:
# Decide if we need to set LIBGL_ALWAYS_INDIRECT=1 to get the
# texture_from_pixmap extension; we take having the extension
# be supported on both the client and server but not in the
# list of effective extensions as a signal of needing to force
# indirect rendering.
#
# Note that this check would give the wrong answer for Xephyr,
# but since we force !use_tfp there anyway, it doesn't matter.
(server_glx_extensions, client_glx_extensions, glx_extensions) = _get_glx_extensions()
if ("GLX_EXT_texture_from_pixmap" in server_glx_extensions and
"GLX_EXT_texture_from_pixmap" in client_glx_extensions and
(not "GLX_EXT_texture_from_pixmap" in glx_extensions)):
if options.verbose:
print "Forcing indirect GL"
force_indirect = True
# Now launch metacity-clutter with our plugin
env = dict(os.environ)
env.update({'GNOME_SHELL_JS' : js_dir,
'GNOME_SHELL_DATADIR' : data_dir,
'GI_TYPELIB_PATH' : plugin_dir,
'PATH' : os.environ.get('PATH', '') + ':' + plugin_dir,
'LD_LIBRARY_PATH' : os.environ.get('LD_LIBRARY_PATH', '') + ':' + plugin_dir,
'GNOME_DISABLE_CRASH_DIALOG' : '1'})
if force_indirect:
if options.verbose:
# This is Mesa specific; the NVIDIA proprietary drivers
# drivers use __GL_FORCE_INDIRECT=1 instead. But we don't
# need to force indirect rendering for NVIDIA.
env['LIBGL_ALWAYS_INDIRECT'] = '1'
if not options.verbose:
# Unless verbose() is specified, only let gjs show errors and
# things that are explicitly logged via log() from javascript
env['GJS_DEBUG_TOPICS'] = 'JS ERROR;JS LOG'
if options.debug:
debug_command = options.debug_command.split()
args = list(debug_command)
else:
args = []
plugin = os.path.join(plugin_dir, "libgnome-shell.la")
args.extend(['metacity', '--mutter-plugins=' + plugin, '--replace'])
if options.sync:
args.append('--sync')
return subprocess.Popen(args, env=env)
# 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("", "--geometry", metavar="GEOMETRY",
help="Specify Xephyr screen geometry",
default="1024x768");
parser.add_option("-w", "--wide", action="store_true",
help="Use widescreen (1280x800) with Xephyr")
options, args = parser.parse_args()
if args:
parser.print_usage()
sys.exit(1)
if options.debug_command:
options.debug = True
elif options.debug:
options.debug_command = "gdb --args"
if options.wide:
options.geometry = "1280x800"
metacity_pid = pidof("metacity")
gnome_panel_pid = pidof("gnome-panel")
# Run in Xephyr if gnome-panel is already running and the user didn't
# specify --replace. Otherwise, run fullscreen
if options.replace:
run_in_xephyr = False
else:
run_in_xephyr = (metacity_pid != None or gnome_panel_pid != None)
# Figure out whether or not to use GL_EXT_texture_from_pixmap. By default
# we use it iff we aren't running Xephyr, but we allow the user to
# explicitly disable it.
# FIXME: Move this to ClutterGlxPixmap like
# CLUTTER_PIXMAP_TEXTURE_RECTANGLE=disable.
if 'GNOME_SHELL_DISABLE_TFP' in os.environ and \
os.environ['GNOME_SHELL_DISABLE_TFP'] != '':
use_tfp = False
else:
# tfp does not work correctly in Xephyr
use_tfp = not run_in_xephyr
if options.verbose:
print "Starting shell"
try:
if run_in_xephyr:
shell = start_xephyr()
start_shell()
else:
kill_gnome_panel(gnome_panel_pid)
shell = start_shell()
# Wait for shell to exit
if options.verbose:
print "Waiting for shell to exit"
shell.wait()
if options.verbose:
print "Shell is dead"
except KeyboardInterrupt, e:
os.kill(shell.pid, signal.SIGKILL)
shell.wait()
if options.verbose:
print "Shell killed"
finally:
if metacity_pid or gnome_panel_pid:
# Restart gnome-panel and window manager
if options.verbose:
print "Restarting Metacity and Gnome Panel"
if metacity_pid:
subprocess.Popen(["/usr/bin/metacity"])
if gnome_panel_pid:
subprocess.Popen(["/usr/bin/gnome-panel"])