1 xinit
在说明 startx 之前,我想我们应该先了解一下 xinit 。因为 startx 就是通过调用 xinit 启动 X 的。
1.1 功能
当我们安装了 Ubuntu 后,默认就已经安装了 xinit ,它位于 /usr/bin 下。 xinit 是一个二进制文件,并非是一个脚本。它的主要功能是启动一个 X 服务器,同时启动一个基于 X 的应用程序。
1.2 用法
xinit 的用法为: xinit [[client] options ] [-- [server] [display] options] 。
其中 client 用于指定一个基于 X 的应用程序,client 后面的 options 是传给这个应用程序的参数, server 是用于指定启动哪个 X 服务器,一般为 /usr/bin/X 或/usr/bin/Xorg , display 用于指定 display number ,一般为 0 ,表示第一个 display , option 为传给 server 的参数。
如果不指定 client , xinit 会查找 HOME ( 环境变量 ) 目录下的 .xinitrc 文件,如果存在这个文件, xinit 直接调用 execvp函数执行该文件。如果这个文件不存在,那么 client 及其 options 为: xterm -geometry +1+1 -n login -display :0 。
如果不指定 server , xinit 会查找 HOME( 环境变量 ) 目录下的 .xserverrc 文件,如果存在这个文件, xinit 直接调用execvp 函数执行该文件。如果这个文件不存在,那么 server 及其 display 为: X :0 。如果系统目录中不存在 X 命令,那么我们需要在系统目录下建立一个名为 X 的链接,使其指向真正的 X server 命令( Ubuntu 下为 Xorg )。
1.3 例子
下面是几个关于 xinit 应用的例子:
1) xinit /usr/bin/xclock -- /usr/bin/X :0
该例子将启动 X server , 同时将会启动 xclock 。请注意指定 client 或 server 时,需要用绝对路径,否则 xinit 将因无法区别是传给 xterm 或 server 的参数还是指定的 client 或 server 而直接当成是参数处理。
2) 在 HOME 下新建 .xinitrc 文件,并加入以下几行:
xsetroot -solid gray &
xclock -g 50x50-0+0 -bw 0 &
xterm -g 80x24+0+0 &
xterm -g 80x24+0-0 &
twm
当 xinit 启动时,它会先启动 X server ,然后启动一个 clock ,两个 xterm ,最后启动窗口管理器 twm 。
请注意:
最后一个命令不能后台运行,否则所有命令都后台运行的话 xinit 就会返回退出,同样的,除最后一个命令外都必须后台运行,否则后面的命令将只有在该命令退出后才能运行。
1.4 分析
看到这里,眼尖的人或许早以看出 xinit 的功能完全可以由脚本来实现,例如要启动 X Server 和一个 xterm ,就像 xinit 默认启动的那样,只需要在新建一个脚本或在 rc.local 中加入:
X&
export DISPLAY=:0.0
xterm
这个实现完全正确,然而却并没有完全实现 xinit 所具有的功能, xinit 所有的一项功能就是当最后一个启动的 client (如上面第二个例子中的 twm 窗口管理器)退出后, X 服务器也会退出。而我们的脚本实现中当我们退出 xterm 后并不会退出 X server 。
2 startx 脚本
用过 linux 的人基本上都知道 linux 下有个命令叫做 startx , 那么它到底是怎么实现的呢 ?
2.1 功能
当我们在终端下想启动图形界面时,我们都会通过输入 startx 来实现,该命令可以启动一个 X server ,而且可以启动一个漂亮的图形界面( Ubuntu 下,我装的是 gnome )。
2.2 用法
Startx 的用法和 xinit 的基本一样 : startx [ [ client ] options ... ] [ -- [ server ] options ... ] 。为什么呢?这是因为 startx其实就是一个脚本,它启动 X server 就是通过调用 xinit 命令实现的, startx 的参数将全部传给 xinit 。因此,这些参数的意义和 xinit 的参数是一样的。
2.3 例子
下面是两个关于 startx 命令的简单例子:
1) startx -- -depth 16
该例子主要是以 16 位色启动 X 服务器。
2) startx -- -dpi 100
该例子主要是以 100 的 dpi 启动 X 服务器。
2.4 分析
下面我们来分析一下 startx 脚本。 startx 脚本位于 /usr/bin 下,直接用 vim 打开我们可以看到它的具体实现如下:
#!/bin/bash # 注意:该脚本用的是 bash shell 解析的
# $Xorg: startx.cpp,v 1.3 2000/08/17 19:54:29 cpqbld Exp $
# This is just a sample implementation of a slightly less primitive
# interface than xinit. It looks for user .xinitrc and .xserverrc
# files, then system xinitrc and xserverrc files, else lets xinit choose
# its default. The system xinitrc should probably do things like check
# for .Xresources files and merge them in, startup up a window manager,
# and pop a clock and serveral xterms.
# Site administrators are STRONGLY urged to write nicer versions.
# $XFree86: xc/programs/xinit/startx.cpp,v 3.16tsi Exp $
# 下面主要是对一些变量进行赋值。
userclientrc=$HOME/.xinitrc
sysclientrc=/etc/X11/xinit/xinitrc
userserverrc=$HOME/.xserverrc
sysserverrc=/etc/X11/xinit/xserverrc
defaultclient=xterm
defaultserver=/usr/bin/X
defaultclientargs=""
defaultserverargs=""
clientargs=""
serverargs=""
# 下面的语句主要是说:如果 $HOME/.xinitrc 文件存在,并且不是一个目录,那么就将 defaultclientargs 赋值为$HOME/.xinitrc ,否则,如果 /etc/X11/xinit/xinitrc 存在并且不是一个目录,就将 defaultclientargs 赋值为/etc/X11/xinit/xinitrc 。
if [ -f $userclientrc ]; then
defaultclientargs=$userclientrc
elif [ -f $sysclientrc ]; then
defaultclientargs=$sysclientrc
fi
# 下面的语句主要是说:如果 $HOME/.xserverrc 文件存在,并且不是一个目录,那么就将 defaultclientargs 赋值为$HOME/.xserverrc ,否则,如果 /etc/X11/xinit/xserverrc 存在并且不是一个目录,就将 defaultclientargs 赋值为/etc/X11/xinit/xserverrc 。
if [ -f $userserverrc ]; then
defaultserverargs=$userserverrc
elif [ -f $sysserverrc ]; then
defaultserverargs=$sysserverrc
fi
# 将 whoseargs 变量赋值为字符串“ client ”,表示当前解析的指定 client 的参数。
whoseargs="client"
# 当 startx 的一个参数不为空时就进入 while 循环。
while [ x"$1" != x ]; do
case "$1" in
# '' required to prevent cpp from treating "/*" as a C comment.
/''*|/./''*)
if [ "$whoseargs" = "client" ]; then
if [ x"$clientargs" = x ]; then
client="$1" # 解析出了用户指定的 Client 程序
else
clientargs="$clientargs $1" # 解析出了 Client 的参数
fi
else
if [ x"$serverargs" = x ]; then
server="$1" # 解析出了用户指定的 X Server 程序
else
serverargs="$serverargs $1" # 解析出了 X Server 的参数
fi
fi
;;
--) # 遇到“ - - ”就解析 server
whoseargs="server"
;;
*)
if [ "$whoseargs" = "client" ]; then
clientargs="$clientargs $1"
else
# display must be the FIRST server argument
if [ x"$serverargs" = x ] && /
expr "$1" : ':[0-9][0-9]*$' > /dev/null 2>&1; then
display="$1" # 解析出 display
else
serverargs="$serverargs $1"
fi
fi
;;
esac #case 语句结束
shift # 将参数列表左移一位,即解析下个参数 .
done
# process client arguments
if [ x"$client" = x ]; then # 如果 client 变量为空,即用户没有指定 client 。
# if no client arguments either, use rc file instead
if [ x"$clientargs" = x ]; then # 如果用户没有指定 client 参数 就将 client 设为前面设定的默认的 rc 文件(为$HOME/.xinitrc ,或 /etc/X11/xinit/xinitrc )
client="$defaultclientargs"
else
client=$defaultclient # 如果用户指定了 client 参数,就将 client 设定为 xterm
fi
fi
# process server arguments
if [ x"$server" = x ]; then # 如果 server 变量为空,即用户没有指定 server 。
# if no server arguments or display either, use rc file instead
if [ x"$serverargs" = x -a x"$display" = x ]; then # 如果 serverargs 为空,并且 display 为空,就将 server 设为前面设定的默认的 rc 文件(为 $HOME/. xserverrc ,或 /etc/X11/xinit/ xserverrc )
server="$defaultserverargs"
else
server=$defaultserver # 如果用户指定了 serverargs 或 display ,就将 server 设定为 /usr/bin/X
fi
fi
if [ x"$XAUTHORITY" = x ]; then # 如果环境变量 XAUTHORITY 为空,就设定为 $HOME/.Xauthority
XAUTHORITY=$HOME/.Xauthority
export XAUTHORITY
fi
removelist=
# set up default Xauth info for this machine
# check for GNU hostname
if hostname --version > /dev/null 2>&1; then # 如果 hostname 命令存在
if [ -z "`hostname --version 2>&1 | grep GNU`" ]; then # 如果 hostname –version 中不包含 GNU 就将 hostname 变量设定为命令 hostname –f 返回的字符串。
hostname=`hostname -f`
fi
fi
if [ -z "$hostname" ]; then # 如果 hostname 长度为 0, 就将 hostname 变量设定为命令 hostname 返回的字符串。
hostname=`hostname`
fi
authdisplay=${display:-:0}
mcookie=`/usr/bin/mcookie`
dummy=0
# create a file with auth information for the server. ':0' is a dummy.
xserverauthfile=`mktemp -p /tmp serverauth.XXXXXXXXXX`
trap "rm -f $xserverauthfile" HUP INT QUIT ILL TRAP KILL BUS TERM
xauth -q -f $xserverauthfile << EOF
add :$dummy . $mcookie
EOF
serverargs=${serverargs}" -auth "${xserverauthfile}
# now add the same credentials to the client authority file
# if '$displayname' already exists do not overwrite it as another
# server man need it. Add them to the '$xserverauthfile' instead.
for displayname in $authdisplay $hostname$authdisplay; do
authcookie=`xauth list "$displayname" /
| sed -n "s/.*$displayname[[:space:]*].*[[:space:]*]//p"` 2>/dev/null;
if [ "z${authcookie}" = "z" ] ; then
xauth -q << EOF
add $displayname . $mcookie
EOF
removelist="$displayname $removelist"
else
dummy=$(($dummy+1));
xauth -q -f $xserverauthfile << EOF
add :$dummy . $authcookie
EOF
fi
done
echo "client=$client,clientargs=$clientargs,server= $server, display= $display, serverargs=$serverargs"
# 下面的语句通过 xinit 启动 X server 和 Clients 。
xinit $client $clientargs -- $server $display $serverargs
if [ x"$removelist" != x ]; then
xauth remove $removelist
fi
if [ x"$xserverauthfile" != x ]; then
rm -f $xserverauthfile
fi
if command -v deallocvt > /dev/null 2>&1; then
deallocvt # 释放所有未使用的虚拟终端的核心内存和数据结构
fi
2.5 总结
由以上对 startx 脚本的分析,我们可以知道: startx 将会先解析用户的参数,如果该用户指定了该参数(即解析结果不为空),那么 startx 就会以该参数来启动 xinit ,否则就会解析(与其说是解析,还不如说是执行) $HOME 目录下的 rc 文件,如果该文件不存在,就会解析系统目录下( /etc/X11/xinit/ )的 rc 文件,如果这个文件也不存在,那 startx 就将以默认的 client ( xterm )和 server ( /usr/bin/X )为参数来启动 xinit 。
3 startx 默认启动过程
通过以上对 startx 脚本的分析,我们知道了 startx 的基本的启动流程,但是到目前为止,我们还不知道仅仅在终端输入startx 是怎么样启动 gnome 那漂亮的桌面的,下面我们来看一下其启动过程。
3.1 startx 的几种启动方式
由对 startx 脚本的分析,我们可以知道 startx 主要有三种启动方式:
a) 、一种是自己指定要启动的 client 和 server , 例如: startx /usr/bin/xclock -- /usr/bin/X :0 ;
b )、一种是通过在 $HOME 下新建 .xinitrc 文件来指定要启动的多个 client 和 .xserverrc 来指定要启动的 server (注意:这两个文件本来是不存在的);
c )、还有一种是直接输入 startx 而不指定参数,这也就是我们启动 gnome 桌面的方法。这里
我们主要介绍最后一种启动方法。
在 c 这种启动方法中,我们可以知道, startx 脚本会先去看系统目录( /etc/X11/xinit/ )下的 rc 文件是否存在,如果不存在就会用默认的 xterm 和 /usr/bin/X 来启动 xinit 。显然, startx 启动的不是 xterm ,而是 gnome 桌面,因此 gnome的启动是通过系统文件 /etc/X11/xinit/xinitrc 来指定的。
而 /etc/X11/xinit/xinitrc 文件的内容如下所示:
#!/bin/bash # 注意 : 该脚本用的是 bash shell 解析的
# $Xorg: xinitrc.cpp,v 1.3 2000/08/17 19:54:30 cpqbld Exp $
# /etc/X11/xinit/xinitrc
# global xinitrc file, used by all X sessions started by xinit (startx)
# invoke global X session script
. /etc/X11/Xsession # 在当前这个 shell 环境中执行 Xsession 脚本
因此, gnome 的启动应该在 Xsession 里。
而 X Server 的启动则是通过系统文件 /etc/X11/xinit/xserverrc 来指定的 , 这个文件的内容为 :
#!/bin/sh # 注意:该脚本用的是 Bourne shell 解析的
# $Id: xserverrc 189 2005-06-11 00:04:27Z branden $
exec /usr/bin/X11/X -nolisten tcp
3.2 Xsession
下面是 Xsession 脚本的内容 :
#!/bin/sh # 注意:该脚本用的是 Bourne shell 解析的
# /etc/X11/Xsession
# global Xsession file -- used by display managers and xinit (startx)
# $Id: Xsession 967 2005-12-27 07:20:55Z dnusinow $
set –e # 打开 errexit 选项,该选项表示:如果下面有命令返回的状态非 0 ,则退出程序。
PROGNAME=Xsession
# 下面四个是信息输出函数,可以不管
message () {
# pretty-print messages of arbitrary length; use xmessage if it
# is available and $DISPLAY is set
MESSAGE="$PROGNAME: $*"
echo "$MESSAGE" | fold -s -w ${COLUMNS:-80} >&2
if [ -n "$DISPLAY" ] && which xmessage > /dev/null 2>&1; then
echo "$MESSAGE" | fold -s -w ${COLUMNS:-80} | xmessage -center -file -
fi
}
message_nonl () {
# pretty-print messages of arbitrary length (no trailing newline); use
# xmessage if it is available and $DISPLAY is set
MESSAGE="$PROGNAME: $*"
echo -n "$MESSAGE" | fold -s -w ${COLUMNS:-80} >&2;
if [ -n "$DISPLAY" ] && which xmessage > /dev/null 2>&1; then
echo -n "$MESSAGE" | fold -s -w ${COLUMNS:-80} | xmessage -center -file -
fi
}
errormsg () {
# exit script with error
message "$*"
exit 1
}
internal_errormsg () {
# exit script with error; essentially a "THIS SHOULD NEVER HAPPEN" message
# One big call to message() for the sake of xmessage; if we had two then
# the user would have dismissed the error we want reported before seeing the
# request to report it.
errormsg "$*" /
"Please report the installed version of the /"x11-common/"" /
"package and the complete text of this error message to" /
"<debian-x@lists.debian.org>."
}
# initialize variables for use by all session scripts
OPTIONFILE=/etc/X11/Xsession.options
SYSRESOURCES=/etc/X11/Xresources
USRRESOURCES=$HOME/.Xresources
SYSSESSIONDIR=/etc/X11/Xsession.d
USERXSESSION=$HOME/.xsession
USERXSESSIONRC=$HOME/.xsessionrc
ALTUSERXSESSION=$HOME/.Xsession
ERRFILE=$HOME/.xsession-errors
# attempt to create an error file; abort if we cannot
if (umask 077 && touch "$ERRFILE") 2> /dev/null && [ -w "$ERRFILE" ] &&
[ ! -L "$ERRFILE" ]; then
chmod 600 "$ERRFILE"
elif ERRFILE=$(tempfile 2> /dev/null); then
if ! ln -sf "$ERRFILE" "${TMPDIR:=/tmp}/xsession-$USER"; then
message "warning: unable to symlink /"$TMPDIR/xsession-$USER/" to" /
"/"$ERRFILE/"; look for session log/errors in" /
"/"$TMPDIR/xsession-$USER/"."
fi
else
errormsg "unable to create X session log/error file; aborting."
fi
# truncate ERRFILE if it is too big to avoid disk usage DoS
if [ "`stat -c%s /"$ERRFILE/"`" -gt 500000 ]; then
T=`mktemp -p "$HOME"`
tail -c 500000 "$ERRFILE" > "$T" && mv -f "$T" "$ERRFILE" || rm -f "$T"
fi
exec >>"$ERRFILE" 2>&1
echo "$PROGNAME: X session started for $LOGNAME at $(date)"
# sanity check; is our session script directory present?
# 如果 /etc/X11/Xsession.d 不存在或不是一个目录则打印错误信息并退出。
if [ ! -d "$SYSSESSIONDIR" ]; then
errormsg "no /"$SYSSESSIONDIR/" directory found; aborting."
fi
# Attempt to create a file of non-zero length in /tmp; a full filesystem can
# cause mysterious X session failures. We do not use touch, :, or test -w
# because they won't actually create a file with contents. We also let standard
# error from tempfile and echo go to the error file to aid the user in
# determining what went wrong.
WRITE_TEST=$(tempfile)
if ! echo "*" >>"$WRITE_TEST"; then
message "warning: unable to write to ${WRITE_TEST%/*}; X session may exit" /
"with an error"
fi
rm -f "$WRITE_TEST"
# use run-parts to source every file in the session directory; we source
# instead of executing so that the variables and functions defined above
# are available to the scripts, and so that they can pass variables to each
# other
# 将 /etc/X11/Xsession.d 目录中的所有文件都读出,并存入 SESSIONFILES 变量中。
SESSIONFILES=$(run-parts --list $SYSSESSIONDIR)
# 如果 SESSIONFILES 变量中的字符串不为空,即 /etc/X11/Xsession.d 中有文件存在
if [ -n "$SESSIONFILES" ]; then
set +e # 关闭 errexit 选项
for SESSIONFILE in $SESSIONFILES; do
. $SESSIONFILE # 在当前 shell 环境下执行该文件
done
set –e # 打卡 errexit 选项
fi
exit 0
从以上的对 Xsession 脚本文件的分析 , 可以看出 , Xsession 脚本仅仅是执行了 /etc/X11/Xsession.d 目录下的所有文件,在该目录下,文件包括:
20x11-common_process-args
30x11-common_xresources
40x11-common_xsessionrc
50x11-common_determine-startup
55gnome-session_gnomerc
60seahorse
60xdg-user-dirs-update
80im-switch
90-console-kit
90x11-common_ssh-agent
99x11-common_start
每个文件名都以数字开头,这主要是为了确保这些脚本的执行顺序, run-parts 会将数字小的排在前面,这样就能确保以上文件能按数字由小到大的顺序执行。
1 、 20x11-common_process-args
这个文件主要是处理传给 /etc/X11/xinit/ xinitrc 脚本文件的参数的。该参数个数只能为 0 或一个,否则将不进行任何处理。如果该参数是 failsafe ,则该脚本将执行 x-terminal-emulator ,否则就执行该参数。需要说明的是, x-terminal-emulator 是一个符号链接,指向 /etc/alternatives/x-terminal-emulator ,同时, /etc/alternatives/x-terminal-emulator 也是一个符号链接,它指向 /usr/bin/gnome-terminal.wrapper ,而 gnome-terminal.wrapper 则是一个 perl 脚本,它最终是调用了 gnome-terminal 。
2 、 30x11-common_xresources
该文件主要是调用 xrdb 来将 /etc/X11/Xresources 目录下及 $HOME/.Xresources 目录下的文件的内容来设置根窗口的屏幕 0 上 的 RESOURCE_MANAGER 属性的内容。
3 、 40x11-common_xsessionrc
该文件主要是判断 $HOME/.xsessionrc 文件是否存在,如果存在则执行该脚本文件。
4 、 50x11-common_determine-startup
该文件主要先查看配置文件 /etc/X11/Xsession.options 中是否允许使用用户的 xsession ,如果/etc/X11/Xsession.options 中存在 allow-user-xsession 字段,则查看 $HOME/.xsession 是否存在并有执行权限,如果是,则将 STARTUP 变量设置为该文件,如果没有执行权限就将 STARTUP 变量设置为“ sh 该 xsession 文件”。如果此时 STARTUP 变量仍然为空,则将其设置为 x-session-manager , x-window-manager 或 x-terminal-emulator 。注意:这个 STARTUP 将会在后面的脚本中被启动。
5 、 55gnome-session_gnomerc
该文件会先得到 STARTUP 的 basename ,如: STARTUP=/usr/bin/x-session-manager ,则其 basename 为 x-session-manager 。再判断该 basename 是否为 gnome-session ,或者为 x-session-manager 并且 x-session-manager是个符号链接,它指向 /usr/bin/gnome-session ,如果是则执行 $HOME/.gnomerc (如果该文件存在并且可读)。
6 、 60seahorse
将 STARTUP 重新赋值为“ /usr/bin/seahorse-agent $STARTUP ”,这个可能只是为安全考虑才这么做的,具体的我也不是很清楚,只是看了一下 seahorse-agent 的帮助,知道 seahorse 是一个 GNOME 的应用程序,它用于为用户的输入进行暂时的安全存储,而 seahorse-agent 则是 seahorse 的一个代理而已。
7 、 60xdg-user-dirs-update
用 xdg-user-dirs-update 自动生成 $HOME 下的文件夹,该命令主要是根据 /etc/xdg/user-dirs.defaults 文件的内容来为用户创建文件夹的。
8 、 80im-switch
该文件主要用于设置输入法。具体的请自己参考文件内容。
9 、 90-console-kit
如果环境变量 $XDG_SESSION_COOKIE 为空,并且 /usr/bin/ck-launch-session 可执行,则将 STARTUP 重新赋值为” /usr/bin/ck-launch-session $STARTUP” 。至于 ck-launch-session 的功能,我也不是很清楚,估计是和 session 有关。
10 、 90x11-common_ssh-agent
该文件主要先查看配置文件 /etc/X11/Xsession.options 中是否使用 ssh agent ,如果 /etc/X11/Xsession.options 中存在use-ssh-agent 字段,则判断 /usr/bin/ssh-agent 是否可执行,并且环境变量 $SSH_AUTH_SOCK 和$SSH2_AUTH_SOCK 是否都为空,如果是,这将 STARTUP 重新赋值为 ” /usr/bin/ssh-agent $STARTUP” 。
11 、 99x11-common_start
它仅仅是用 exec 启动 $STARTUP 。关于 exec ,在 Bourne shell 中,它与 fork 的区别就在于它执行一个新的脚本不需创建 sub-shell ,而它与 Source 和 Dot 的区别就在与在这条语句后面的语句将不会再被执行。此时,我们可以发现变量 $STARTUP 的值为:“ startup=/usr/bin/ssh-agent /usr/bin/ck-launch-session /usr/bin/seahorse-agent --execute x-session-manager ”, 因此,最终将会被执行的就是这么一条语句。而 x-session-manager 在 Ubuntu8.04 中仅仅是个符号链接,它最终指向的是 gnome-session 。
gnome-session 则是启动 GNOME 桌面环境的,这个程序一般被登入管理器 gdm 、 xdm 和脚本 startx 调用。(gnome-session 如何启动桌面,待研究)
4 startx 启动过程小结
综上所述, startx 的默认启动过程为: startx 调用并将系统文件 /etc/X11/xinit/xinitrc 和 /etc/X11/xinit/xserverrc 作为参数传给 xinit , xinit 就会先执行系统文件 /etc/X11/xinit/xserverrc 以启动 X Server ,然后执行 /etc/X11/xinit/xinitrc ,而xinitrc 则会执行脚本 /etc/X11/Xsession ,而 Xsession 则会按顺序调用执行 /etc/X11/Xsession.d 目录下的文件,从而最终调用了 gnome-session 这个用于启动 GNOME 桌面环境的程序。
Linux X Window System运行原理和启动过程
本文主要说明X Window System的基本运行原理,其启动过程,及常见的跨网络运行X Window System。
一) 基本运行原理
X Window System采用C/S结构,但和我们常见的C/S不同。常见的C/S结构中,称提供服务的一方为server,即服务器端(如HTTP服务,FTP服务等),使用服务的称为client,即客户端。但在X Window System中,client是执行程式的一方,在上面执行各种X程式,而server则是负责显示client运行程式的窗口的一方。
X Window System的组成能够分为X server,X client,X protocol三部分。X server主要控制输入输出,维护字体,颜色等相关资源。他接受输入设备的输入信息并传递给X client,X client将这些信息处理后所返回的信息,也由X server负责输出到输出设备(即我们所见的显示器)上。X server传递给X client的信息称为Event,主要是键盘鼠标输入和窗口状态的信息。X client传递给X server的信息则称为Request,主要是需要X server建立窗口,更改窗口大小位置或在窗口上绘图输出文字等。X client主要是完成应用程式计算处理的部分,并不接受用户的输入信息,输入信息都是输入给X server,然后由X server以Event的形式传递给X client(这里感觉类似Windows的消息机制,系统接收到用户的输入信息,然后以消息的形式传递给窗口,再由窗口的消息处理过程处理)。X client对收到的Event进行相应的处理后,假如需要输出到屏幕上或更改画面的外观等,则发出Request给X server,由X server负责显示。
常见的情况是X server和X client都在同一台电脑上运行,但他们也可分别位于网络上不同的电脑上。在X Window System中,X client是和硬件无关的,他并不关心您使用的是什么显卡什么显示器什么键盘鼠标,这些只和X server相关。我们平常安装完XFree86后运行xf86config或xf86cfg进行的配置实际上只是和X server有关,能够说就是配置X server吧,不配置照样能够运行X client程式(如:xeyes -display xserver:0就能够在xserver这台机器上的0号屏幕(屏幕编号displaynumber为0)上显示那对大眼睛了)。
X protocol就是X server于X client之间通信的协议了。X protocol支持现在常用的网络通信协议。我只能测试TCP/IP,能够看到X server侦听在tcp 6000端口上。那X protocol就是位于运输层以上了,应该属于应用层吧?。
总结下运行过程吧:
(1) 用户通过鼠标键盘对X server下达操作命令
(2) X server利用Event传递用户操作信息给X client
(3) X client进行程式运算
(4) X client利用Request传回所要显示的结果
(5) X server将结果显示在屏幕上
二) 启动过程
我们从控制台进入X一般是用startx命令。下面就从startx分析起。首先man startx和man xinit能够看到staratx和xinit的使用方法:
startx [[client] options .....] [-- [server] options ....]
xinit [[client] options ] [-- [server] [display] options]
把上面[client]和[server]分别称为client程式和server程式。man手册里写明其必须以/或./开头。
下面看看startx这个脚本,中文为我加的注释,这个脚本是安装x-window-system-core后得到的,都是XFree86,不同发行版的linux里该脚本应该大同小异:
#!/bin/sh
userclientrc=$HOME/.xinitrc #用户的client定义文档
userserverrc=$HOME/.xserverrc #用户的server定义文档
sysclientrc=/usr/X11R6/lib/X11/xinit/xinitrc #系统的client
sysserverrc=/usr/X11R6/lib/X11/xinit/xserverrc #系统的server
defaultclient=/usr/X11R6/bin/xterm #默认的client程式
defaultserver=/usr/X11R6/bin/X #默认的server程式
defaultclientargs="" #下面定义了client和server的参数变量
defaultserverargs=""
clientargs=""
serverargs=""
#假如用户client文档存在则使用用户文档里定义的client,否则使用系统定义的client
if [ -f $userclientrc ]; then
defaultclientargs=$userclientrc
elif [ -f $sysclientrc ]; then
defaultclientargs=$sysclientrc
fi
#假如用户server文档存在则使用用户文档里定义的server,否则使用系统定义的server
if [ -f $userserverrc ]; then
defaultserverargs=$userserverrc
elif [ -f $sysserverrc ]; then
defaultserverargs=$sysserverrc
fi
#下面循环处理client和server的参数
whoseargs="client"
while [ x"" != x ]; do #若第一个参数为空,退出循环
case "" in
# '' required to prevent cpp from treating "/*" as a C comment.
/''*|./''*) #假如是/*或./*形式(xinit程式需要其参数里的client程式和server程式必须以/或./开头,否则会被视为client程式和server程式的参数,见man xinit)
if [ "$whoseargs" = "client" ]; then #假如当前是在处理client的参数
if [ x"$clientargs" = x ]; then #假如clientargs为空,则赋值给client变量,也即上面#startx使用方法里的[client]参数
client=""
else
clientargs="$clientargs " #否则clientargs赋值为$clientargs ,即上面#startx使用#方法里的options参数
fi
else #当前在处理server的参数,代码的含义同上
if [ x"$serverargs" = x ]; then
server=""
serverargs="$serverargs "
fi
fi
;;
--)#假如为--,则表示开始处理server的参数,--为client和server参数的分界
whoseargs="server"
;;
*)
if [ "$whoseargs" = "client" ]; then #处理给client程式的参数
clientargs="$clientargs "
else #处理给server程式的参数
# display must be the FIRST server argument
#屏幕编号必须为第一个给server程式的参数,以的形式(x为数字),这可从上面startx和xinit 的使用
#方法的区别看出,xinit多了个[display],这里即过滤出这个[display]。试试看这两个命令:
#xinit /usr/bin/X11/xeyes -display localhost:1 -- /usr/bin/X11/X :1 -dpi 70&
#xinit /usr/bin/X11/xeyes -display localhost:1 -- /usr/bin/X11/X -dpi 70 :1&
#即可看出不把屏幕编号作为第一个server参数的后果
if [ x"$serverargs" = x ] && expr "" : ':[0-9][0-9]*$' > /dev/null 2>&1; then
display=""
else #处理屏幕编号以外的参数
serverargs="$serverargs "
fi
fi
;;
esac
shift #任何参数左移一次
done
# process client arguments
if [ x"$client" = x ]; then #假如client程式为空
# if no client arguments either, use rc file instead
if [ x"$clientargs" = x ]; then #且clientargs为空,赋值$defaultclientargs给client程式
client="$defaultclientargs"
else
client=$defaultclient #使用默认的client程式
fi
fi
# process server arguments处理server参数,同上
if [ x"$server" = x ]; then
# if no server arguments or display either, use rc file instead
if [ x"$serverargs" = x -a x"$display" = x ]; then
server="$defaultserverargs"
else
server=$defaultserver
fi
fi
#…………省略授权代码若干
xinit $client $clientargs -- $server $display $serverargs #把处理过的参数交由xinit程式处理
#…………
由上面代码能够得出startx主要是置X client和X server所在的位置,并处理相关参数,最后交给xinit处理。能够看出startx 配置X client的位置是先搜寻$HOME/.xinitrc,然后是/etc/X11/xinit/xinitrc;配置X server的位置是先搜寻$HOME/.xserverrc,然后是/etc/X11/xinit/xserverrc。这就解释了我们平常为什么说启动X Window时用户目录下的.xinitrc和.xserverrc文档优先级要高。所以我们用startx命令启动X时,假如用户目录存在.xinitrc和.xserverrc文档,则实际上等价于命令xinit $HOME/.xinitrc -- $HOME/.xserverrc 。假如用户目录不存在那两个文档,则等价于xinit /usr/X11R6/lib/X11/xinit/xinitrc -- /usr/X11R6/lib/X11/xinit/xserver。别的情况类推。
至于xinit,则根据startx传过来的参数启动X server,成功后根据xinitrc启动X client。
以上即为X Window System的启动过程,startx只是负责一些参数传递,真正的X启动由xinit实现。实际上能够分为启动X server和启动X client两部分。下面在用户目录下构造.xinitrc(即X client)和.xserverrc(即X server)文档。在.xserverrc里写入/usr/bin/X11/X :1。.xinitrc里写入/usr/bin/X11/xeyes -display localhost:1。这就是最简单的X server X client了,只但是把屏幕编号从默认的0改为了1,这里X server即是/usr/bin/X11/X 程式,X client即是/usr/bin/X11/xeyes 程式。
总结下单机用startx启动过程吧:
(1) startx置X client和X server的位置,处理参数并调用xinit
(2) xinit根据传过来的参数启动X server,成功后呼叫X client
(3) 根据xinitrc配置相关资源,启动窗口管理器,输入法和其他应用程式等X client程式。
但还未搞清楚gnome是怎么起来的!gnome当然属于X client了,看上面启动过程第(3)步。
这里分两种情况看吧,第一种是用系统的xinitrc文档。看/etc/X11/xinit/xinitrc文档(我的sarge装x-window-system-core和gnome-core),里面只包含了. /etc/X11/Xsession一句话。接着看/etc/X11/Xsession这个脚本,只看关键部分吧。最后面有:
SESSIONFILES=$(run_parts $SYSSESSIONDIR)
if [ -n "$SESSIONFILES" ]; then
for SESSIONFILE in $SESSIONFILES; do
. $SESSIONFILE
done
fi
exit 0
接着看run_parts(),位于本文档中间:
run_parts () {
# until run-parts --noexec is implemented
if [ -z "" ]; then
internal_errormsg "run_parts() called without an argument."
fi
if [ ! -d "" ]; then
internal_errormsg "run_parts() called, but "" does not exist or is"
"not a directory."
fi
for F in $(ls ); do
if expr "$F" : '[[:alnum:]_-] $' > /dev/null 2>&1; then
echo "/$F"
fi
fi
done
}
大概意思就是run_parts () 把$SYSSESSIONDIR目录下的文档名取出来赋值给$SESSIONFILES,然后循环运行该目录下的文档。看看该目录,即/etc/X11/Xsession.d目录,能够看到几个以数字开头的文档,实际上这些数值就表示了这几个文档被运行的优先级,数字小的优先级高,因为在上面的run_parts () 里是用ls命令显示该目录下的文档,所以前面数字小的被ls时显示在前面,所以被
for SESSIONFILE in $SESSIONFILES; do
. $SESSIONFILE
done
这个for循环执行时也先被执行。看到/etc/X11/Xsession.d目录下有个55gnome-session_gnomerc文档,里面提到了STARTUP变量。然后运行:
xdkui@Debian:/etc/X11/Xsession.d$ grep STARTUP *
看到50xfree86-common_determine-startup文档。里面有
if [ -z "$STARTUP" ]; then
if [ -x /usr/bin/x-session-manager ]; then
STARTUP=x-session-manager
elif [ -x /usr/bin/x-window-manager ]; then
STARTUP=x-window-manager
elif [ -x /usr/bin/x-terminal-emulator ]; then
STARTUP=x-terminal-emulator
fi
fi
即配置启动程式,实际上配置STARTUP变量,假如以上程式都没有找到,则会报错退出,即X环境没有被启动。再运行
xdkui@Debian:/etc/X11/Xsession.d$ grep STARTUP *
看到优先级最低也即最后被运行的99xfree86-common_start文档,里面只有一句话:
exec $STARTUP
好了,到这里就启动我们的X client了,终于完了^_^。总结下这第一种方式的启动过程,简单的说就是依次顺序查找/usr/bin/x-session-manager ,x-window-manager,/usr/bin/x-terminal-emulator 这三个文档。假如存在则启动之,也即X client。假如三个都不存在则报错退出了。看/usr/bin/x-session-manager文档能够看到是个符号连接,最终连接到/usr/bin/gnome-session,也就是gnome 了。至于我们在gnome 启动时可能会配置启动输入法等程式,那就归gnome-session管了,也就不再分析了。能够试着把/usr/bin/x-session-manager 改为指向xfce4-session(假如安装了的话) ,再startx就会启动xfce4环境了。大概RedHat的switchdesk工具就是改这个连接实现的吧?。或删掉/usr/bin/x-session-manager ,再startx,只启动了/usr/bin/x-window-manager 所指向的window manager了吧,我这里是blackbox。
下面看第二种情况,即用户目录的xinitrc文档$HOME/.xinitrc。对比hiweed-debian-desktop_0.55_i386,存在$HOME/.xinitrc文档,在里面有exec xfce4-session。故其X client能够说最主要的x-session-manger是从$HOME/.xinitrc启动的。也就不会经过上面第一种情况的执行过程了。
终于把gnome(或说x-session-manger)的启动过程弄明白了,下面说点别的吧。xinit程式同时启动X server和X client,这在单机上还可。要是位于网络上的两台电脑分别是client和server,则xinit就无能为力了。这时就得靠纯“手工”来启动X了。下面简单的“手工”启动X server和X client:在CUI模式下运行命令:
xdkui@Debian:~$X :1&
看到了一个灰色的全屏幕和一个鼠标指针,这就是X server了,其屏幕编号为1。下面构造X client,按Ctrl Alt F1回到刚才的CUI(Ctrl Alt F7对应本机的第一个启动的X server,Ctrl Alt F8对应第二个,有人说F7对应屏幕编号为0的X server实际上是不对的,假如第一个启动的屏幕编号为1,第二个启动的编号为0,则F7对应1屏幕,F8对应0屏幕),运行命令:xdkui@Debian:~$xeyes -display localhost:1&
然后按Ctrl Alt F7,看到我们的X client也就是xeyes了吧。再回到CUI,运行
xdkui@Debian:~$X&
开启一个屏幕编号0的X server,CUI下再运行
xdkui@Debian:~$xterm&
这时Ctrl Alt F7对应屏幕编号1;而F8对应屏幕编号0,且其X client为xterm。先退出上面的两个X server,下面复杂点手动启动我们的gnome吧,首先
xdkui@Debian:~$X&
然后
xdkui@Debian:~$gnome-session
看到的就和用startx 启动的X相同了,这时X server是X这个程式,X client是gnome-session及其启动的窗口管理器等程式。看到这里感觉xinit用处并不大(??不知是否正确),简单的脚本就能够实现。本来想把xinit反汇编了分析下,可懒得搞了^_^这是位于本机的情况,对于X server和X client位于不同主机的情况见下面本文第三部分。
个人感觉对于X Window System,搞清楚X server和X client关系很重要。一般X server很简单,就是/usr/bin/X11/X程式;X client则花样繁多,从高级的CDE,GNOME,KDE,到低级一点的只有twm,Window Maker,blackbox等窗口管理器,再到最简陋的只有xterm,rxvt,xeyes等单个x程式。正是由于X client的各种搭配,使得我们的X Window System看起来多样化。这可能也是X Window System最大的卖点之一吧 ^_^
三) 跨网络运行X Window System
一般用来做服务器的系统(Linux,FreeBSD,Solaris等等)都不会装X server,甚至很多都没有显示器。这样能够在这些系统里安装简单的X client,以GUI的方式远程显示在管理员们所坐的X server里。我们实验室用FreeBSD做网关,提供WWW,FTP服务,一般在管理员的本地机器起个X server,然后ssh或telnet上网关运行X client程式显示在本地显示器上,当然,也可用XDMCP(X Display Manager Control Protocol),man xsession里提到/etc/X11/Xsession一般被startx(我的/etc/X11/xinit/xinitrc里调用Xsession脚本)或display manager调用,但有的display manager只调用Xsession而不是xinitrc,故为了startx和display manager两种方式下都可正常启动GUI,最好把X client启动的程式放在Xsession文档里。远程运行X client程式需要配置DISPLAY环境变量,配置为 主机名称:屏幕编号(如192.168.1.2:0,则表示X server是192.168.1.2这台机器上的0号屏幕);或是给X client程式加个—display参数。由于条件限制,只测试了位于TCP/IP网络环境,X server为192.168.1.2,X client为192.168.1.1。
1) Windows系统做X server
a) 用ssh或telnet方式
Windows下面的X server软件有很多种,我这里使用X-win32。在Windows里运行X-win32程式,则相当于本地机器是个X server。远程登录上Debian(我这里是用VMware仿真网络环境,直接进虚拟机即可^_^),运行:
xdkui@xclient:~$export DISPLAY=192.168.1.2:0
xdkui@xclient:~$xterm&
这时即在Windows里的X server里看到了xterm了,至于X client还运行什么程式就看您的需要了,文档管理器阿,资源查看器等。当然,这里X-win32要配置好授权,似乎默认是禁止接入控制,即任何X client都可使用这个X server。
b) XDMCP方式
常见的Display Manager有xdm,gdm,kdm等。我这里使用的是gdm。需要修改gdm的配置文档/etc/X11/gdm/gdm.conf,修改[xdmcp]段的Enable=true,使得能够远程登录,在X client运行gdm。
在X-win32里建一个XDMCP的session,查询方式,填入IP为运行gdm的机器地址。连接,即可看到登录界面,下面的就不用说了,享受吧
2) Linux和Linux互联
a) ssh或telnet方式
在linux本地起个X server,需要注意授权问题,建立文档/etc/X0.hosts,填入X client的IP192.168.1.1,其中X0.hosts表示本地第0个屏幕允许连接的X client地址,建立X1.hosts文档则是本地第1个屏幕允许连接的X client地址,以此类推,man xserver里有。运行
xdkui@xserver:~$X&
运行该程式时别加-nolisten参数,否则不会在网络上侦听。
这个时候Ctrl Alt F7是X server,返回Ctrl Alt F1还能够ssh上X client机器上。
然后登录上X client,运行
xdkui@xclient:~$xterm –display 192.168.1.2:0
即可在本地的X server里看到xterm了,假如有的话,还可把gnome-session也显示在本地来。同样能够在linux里的VMware里做这个测试,需要用点手腕了^_^见下
b) XDMCP方式
在我们的X client里运行gdm(别忘了修改gdm.conf),然后在本地X server的CUI下面运行X -query 192.168.1.1(X client开gdm机器的地址)。能够看到登录界面了吧。
我是在linux里的VMware里做的测试,说说所用的手腕吧。在Ctrl Alt F1的CUI下正常运行startx&启动GUI,这时Ctrl Alt F7即为我的X server,X client启动的gnome,然后在这里运行VMware打开Debian虚拟机,并运行gdm。然后回到Ctrl Alt F1,运行X :1 -query 192.168.1.1。看到登录界面了吧。这时Ctrl Alt F7为我的0号屏幕,里面运行了虚拟机。Ctrl Alt F8为1号屏幕,在远程GUI登录X client。相当于我在本地起了两个X server。
X Window System设计的真是相当神奇,使用方法更是眼花缭乱。
总结:
X Window System的组成能够分为X server,X client,X protocol三部分。X server主要控制输入输出,维护字体,颜色等相关资源。他接受输入设备的输入信息并传递给X client,X client将这些信息处理后所返回的信息,也由X server负责输出到输出设备(即我们所见的显示器)上。X server传递给X client的信息称为Event,主要是键盘鼠标输入和窗口状态的信息。X client传递给X server的信息则称为Request,主要是需要X server建立窗口,更改窗口大小位置或在窗口上绘图输出文字等。X client主要是完成应用程式计算处理的部分,并不接受用户的输入信息,输入信息都是输入给X server,然后由X server以Event的形式传递给X client(这里感觉类似Windows的消息机制,系统接收到用户的输入信息,然后以消息的形式传递给窗口,再由窗口的消息处理过程处理)。X client对收到的Event进行相应的处理后,假如需要输出到屏幕上或更改画面的外观等,则发出Request给X server,由X server负责显示。
startx主要是置X client和X server所在的位置,并处理相关参数,最后交给xinit处理。能够看出startx 配置X client的位置是先搜寻$HOME/.xinitrc,然后是/etc/X11/xinit/xinitrc;配置X server的位置是先搜寻$HOME/.xserverrc,然后是/etc/X11/xinit/xserverrc。这就解释了我们平常为什么说启动X Window时用户目录下的.xinitrc和.xserverrc文档优先级要高。所以我们用startx命令启动X时,假如用户目录存在.xinitrc和.xserverrc文档,则实际上等价于命令xinit $HOME/.xinitrc -- $HOME/.xserverrc 。假如用户目录不存在那两个文档,则等价于xinit /usr/X11R6/lib/X11/xinit/xinitrc -- /usr/X11R6/lib/X11/xinit/xserver。别的情况类推。
至于xinit,则根据startx传过来的参数启动X server,成功后根据xinitrc启动X client。
以上即为X Window System的启动过程,startx只是负责一些参数传递,真正的X启动由xinit实现。实际上能够分为启动X server和启动X client两部分。下面在用户目录下构造.xinitrc(即X client)和.xserverrc(即X server)文档。在.xserverrc里写入/usr/bin/X11/X :1。.xinitrc里写入/usr/bin/X11/xeyes -display localhost:1。这就是最简单的X server X client了,只但是把屏幕编号从默认的0改为了1,这里X server即是/usr/bin/X11/X 程式,X client即是/usr/bin/X11/xeyes 程式。
总结下单机用startx启动过程吧:
(1) startx置X client和X server的位置,处理参数并调用xinit
(2) xinit根据传过来的参数启动X server,成功后呼叫X client
(3) 根据xinitrc配置相关资源,启动窗口管理器,输入法和其他应用程式等X client程式。
启动X窗口的分步骤方法:
(1) xinit
(2) gnome-session
尚存问题:
Gnome 和Gnome2 在配置文档和启动过程有何不同
在Fedora Gnome2中 假如是root用户 /root/.gnome2/ 中是否需要session目录 有何作用
Ubuntu系统启动过程详解
作者:杨硕,华清远见嵌入式学院讲师。
一. Ubuntu的启动流程
ubuntu的启动流程和我们熟知的RedHat的启动方式有所区别。
RedHat的启动过程如下图:
这是我们熟知的linux启动流程,但是ubuntu的启动流程和这个有些区别,我在ubuntu的/etc/目录下面找不到inittab这个文件,一开始很纳闷ubuntu是怎么启动的?一查资料发现ubuntu并没有采用init的方法,所以在/etc/目录下面找不到inittab,这主要是因为init采用串行的方式,引导很费时,RedHat9启动时串行执行大量脚本以及启动各种需要的服务,因此从ubuntu6.10开始逐步采用upSTart来代替init,进行服务进程的管理。为了对原有的init实现向后兼容,upstart可以说是在表象上保留了大部分原来init的特性,因此目前ubuntu初始化进程名仍然叫init,而改变的核心,则是Event机制。
Event机制就是将进程的触发、停止都看成是Event。Ubuntu的/etc/下有一个event.d,这个目录是upstart的核心。/etc/event.d/下面存放了目前upstart需要识别的各种event。这其中主要有三种:rc-default,rcX(X = 0,1,2,3,4,5,6,S),ttyX(X = 0,1,2,3,4,5,6,S)。
其中rc-default就类似与inittab文件,用来设置默认运行级别的。cat rc-default,我们可以看到:
# rc - runlevel compatibility
#
# This task guesses what the "default runlevel" should be and starts the
# appropriate script.
start ON stopped rcS
script
runlevel --reboot || true
if grep -q -w -- "-s\|single\|S" /proc/cmdline; then
telinit S
elif [ -r /etc/inittab ]; then
RL="$(sed -n -e "/^id:[0-9]*:initdefault:/{s/^id://;s/:.*//;p}" /etc/inittab || true)"
if [ -n "$RL" ]; then
telinit $RL
else
telinit 2
fi
else
telinit 2
fi
end script
默认的运行级别是2。
rcX是发生相应运行级别事件时需要运行程序的脚本,我们再cat一下rc2:
# rc2 - runlevel 2 compatibility
#
# This task runs the old sysv-rc runlevel 2 ("multi-user") scripts. It
# is usually started by the telinit compatibility wrapper.
start on runlevel 2
stop on runlevel [!2]
console output
script
set $(runlevel --set 2 || true)
if [ "$1" != "unknown" ]; then
PREVLEVEL=$1
RUNLEVEL=$2
export PREVLEVEL RUNLEVEL
fi
exec /etc/init.d/rc 2
end script
不去考虑细节,只要注意到前两行和倒数第二行就可以了。可以看到,rc2文件是定义在发生运行级别2的时候所要执行的东西,核心就是这句:exec /etc/init.d/rc 2。这样,我们就可以自然地过渡到下一个重要的目录,/etc/init.d/了。
/etc/init.d/中存放的都是服务或者任务的执行脚本。可以这么说,只要你安装了一个程序(特别是服务程序daemon),它可以在系统启动的时候运行,那么它必定会在/etc/init.d/中有一个脚本文件。回到上面的rc2,它执行了exec /etc/init.d/rc 2,也就是给/etc/init.d/rc传递了一个参数”2”,让它执行。Rc脚本里面有这样一段:
# Now run the START scripts for this runlevel.
# Run all scripts with the same level in parallel
.......
for s in /etc/rc$runlevel.d/S*
.......
这说明,当给rc脚本传递一个数字参数"X"的时候,它在经过一系列的设置后,将会开始执行/etc/rcX.d/下S开头的脚本。这就过渡到下一个目录/etc/rcX.d/了。
ls一下/etc/rcX.d/,发现里面全是一堆到/etc/init.d/中的脚本符号链接,不同的是它们的开头加上了S和一个数字。熟悉原本init的人应该知道,S表示在启动时运行,数字则表示执行的先后顺序。其中有一个链接叫做S30gdm,gdm的意思是gnome display management,也就是用来启动gnome桌面的。
综上所述,upstart管理的ubuntu启动过程如下图所示:
二. x-window启动过程解析
从控制台进入X一般用startx命令,故启动X应该从startx这个脚本开始分析。以下是startx脚本的一部分:
#!/bin/sh
userclientrc=$HOME/.xinitrc #用户的client定义文件
userserverrc=$HOME/.xserverrc #用户的server定义文件
sysclientrc=/usr/X11R6/lib/X11/xinit/xinitrc #系统的client
sysserverrc=/usr/X11R6/lib/X11/xinit/xserverrc #系统的server
defaultclient=/usr/X11R6/bin/xterm #默认的client程序
defaultserver=/usr/X11R6/bin/X #默认的server程序
defaultclientargs="" #下面定义了client和server的参数变量
defaultserverargs=""
clientargs=""
serverargs=""
……
可以看到,startx主要是置X client和X server所在的位置,并处理相关参数,最后交给xinit处理。可以看出startx 设置X client的位置是先搜寻$HOME/.xinitrc,然后是/etc/X11/xinit/xinitrc;设置X server的位置是先搜寻$HOME/.xserverrc,然后是/etc/X11/xinit/xserverrc。在ubuntu8.10的$HOME下面没有.xinitrc和.xerverrc,所以startx直接去/etc/下面找x-client和x-server,完成启动x的工作。
总结一下x-window的启动流程图:
“本文由华清远见http://www.embedu.org/index.htm提供”
(一)手工启动
手工启动就是要徒手分别启动X server和X client
启动X:后台运行/usr/bin/X11/X,即
user@Debian:~$/usr/bin/X11/X :1 &
启动Client:如
user@Debian:~$xeyes -display localhost:1&
或 user@Debian:~$gnome-session
(二)通过xinit启动(也就就是通过startx启动)
(1)startx按如下顺序搜索X server配置文件和X Client配置文件,并设置一些参数:
X server:$HOME/.xserverrc -------> /etc/X11/xinit/xserverrc
X client:$HOME/.xinitrc ------> /etc/X11/xinit/xinitrc
(2)startx用取得的参数调用xinit启动X server
(3)xinit通过startx传来的参数,启动Client程序,如term、xdm等,一般就是执行xinitrc的过程。
若用系统默认的配置文件的话,xinit就会依次顺序查找/usr/bin/x-session-manager ,x-window-manager,/usr/bin/x-terminal-emulator 这三个文件。如果存在则启动之,也即X client。如果三个都不存在则报错退出了。x-session-manager是一个符号连接,指向具体的session-manager,如gnome-session-manager。
如果用$HOME目录下的.xinitrc的话,以hiweed-debian- desktop_0.55_i386为例,里面有exec xfce4-session,用于启动桌面系统。
(三)通过Display Manager(即xdm、gdm、kdm等)启动
当Run Level为5时,会启动Display Manager,Display Manager只管启动session,而不管其他东西。
注意一点:xdm/gdm不读取$HOME/.xinitrc,改用了/etc/X11/xdm/Setup_0来设置的。
------------------------------------------------------=============================---------------------------------------------------------