X Window System介绍

1、概述

    X Window System是1984年由麻省理工学院(MIT)和DEC公司共同开发研究的,是执行在UNIX系统上的视窗系统。严格地说,X Window System并非一个软件,而是一个协议,这个协议定义一个系统成品所必需具备的功能(就如同TCP/IP、DECnet或IBM的SNA,这些也都是协议,定义软件所应具备的功能)。能满足此协议及符合X协会其它规范的系统便可称为X。X Window System独有的网络通透性(Network Transparency),使其成为UNIX平台上的工业标准,如今UNIX的工作站或大型主机差点儿都执行着X
Window。X Window是非常巧妙的设计,非常多时候它在概念上比其他窗体系统先进,以至于经过非常多年它仍然是工作站上的工业标准。很多其他窗体系统的概念都是从X Window学来的。

    X Window System本身是一个很复杂的图形化作业环境,我们能够将它分成3个部分,各自是X Server、X Client和X Protocol。X Server主要是处理输入输出的信息,X Client运行大部分应用程序的运算功能,X Protocol则是建立X Server和X Client的沟通管道。

    (1)X Server

    X Server主要负责处理输入输出的信息,而且维护字体、颜色等相关资源。它接收输入设备(如键盘、鼠标)的信息,将这些信息交给X Client处理,而X Client所传来的信息就由X Server负责输出到输出设备(如显示卡、荧幕)上。X Server传给X Client的信息称作Events(事件)。X Client传给X Server的信息称作Request(要求)。Events(事件)主要包含键盘的输入和鼠标的移动、按下等动作,而Request(要求)主要是X Client要求对显示卡及屏幕的输出作调整。

    (2)X Client

    X Client主要负责应用程序的运算处理部分,它将X Server所传来的Events作运算处理后,再将结果以Request的方式去要求X Server显示在屏幕上的图形视窗。在X Window System的结构中,X Server和X Client所负责的部分是分开的,所以X Client和硬件无关,仅仅和程序运算有关。这样有一个优点,比如更换显示卡时,X Client部分不须要又一次编写;由于X Server和X Client是分开的,所以能够将两者分别安装在不同电脑上,这样就能够利用本地端的屏幕、键盘和鼠标来操作远端的X
Client程序。常见的X Client有大家熟悉的gdm, xterm, xeyes等。

    (3)X Protocol

    X Protocol就是X server与X client之间通信的协议。X protocol支持如今经常使用的网络通信协议。比如測试TCP/IP,能够看到X server侦听在tcp 6000port上。那X protocol就是位于传输层以上了,应该属于应用层。通常,X server和X client在两台机器上时,则之间一般使用TCP/IP协议通信,若在同一台机器,则使用高效的操作系统内部通信协议。

    (4)X Library、X Toolkit和Widget

    X Client主要就应用程序,而开发程序大多会提供函数库,以方便开发人员开发,在X则提供有X Library(X Lib),X Library主要提供X Protocol的存取能力,因为X Server仅仅是依据X Client所给的Request(要求)去显示画面,因此全部的图形使用界面都交由X Client负责。我们没有必要每写一个应用程序都得从头再开发一个界面,所以有了图形界面库X Toolkit和Widget的产生,开发人员就能够使用Toolkit和Widget来创建button、对话框、轴、窗体等视窗结构,这样开发人员能够easy地开发各种程序。

    总结下执行过程:

    (1)用户通过鼠标键盘对X server下达操作命令

    (2)X server利用Event传递用户操作信息给X client

    (3)X client进行程序运算

    (4)X client利用Request传回所要显示的结果

    (5)X server将结果显示在屏幕上

    能够看出,X Window的工作方式跟Microsoft Windows有着本质的不同。Microsoft Windows的图形用户界面(GUI)是跟系统紧密相联的。而X Window则不是,它实际上是在系统核心(kernel)的上面执行的一个应用程序。

    X Window的执行分为4层。最底层的是X Server(server),提供图形界面的驱动,为X Window提供服务。上面的一层是用于网络通信的网络协议,即X网络协议,这部分使远程执行X Window成为可能。仅仅须要在server上执行一个X Server,而客户机(Client)上执行更上一层的程序,则能够实现X Window的远程执行。再往上的一层是称作Xlib的函数接口,介于基础系统和较高层应用程序之间。应用程序的实现是通过调用这一层的函数实现的。最顶层就是窗体管理器了,也就是一般所说的WM(Window
Manager),这一层的软件是用户常常接触的,比方fvwm、AfterStep、Enlightment以及WindowMaker等。

    从上面的介绍来看,X Window的执行是一种客户机/server(Client/Server)的模式,server用于显示客户机执行的应用程序,又被称为显示server (Display Server)。显示server位于硬件和客户机之间,它跟踪全部来自输入设备(比方键盘、鼠标)的输入动作,经过处理后将其送回客户机。这样,用户能够在 Microsoft Windows的机器上执行X Client,截取并传送用户的输入,仅仅是将X Window的屏幕输出显示在用户的屏幕上。客户机的输入和输出系统跟Xserver之间的通信都是遵守X协议的。

    搞清楚X server与X client关系非常重要。一般X server非常easy,就是/usr/bin/X11/X程序或Xorg程序,在Microsoft Windows上经常使用的X server有Xming,Xmanager,Exceed和X-win32等。而X client则花样繁多,从高级的CDE,GNOME,KDE,到低级一点的仅仅有twm,Window Maker,blackbox等窗体管理器,再到最简陋的仅仅有xterm,rxvt,xeyes等单个x程序。正是因为X client的各种搭配,使得我们的X
Window System看起来多样化。

    注意,X中所提及的“client”和“server”等字眼用词与人们一般想定的相反,“server”反而是在用户本地端的自有机器上执行,而非是在远程的还有一部机器上执行。非常多熟悉Internet原理的人首次遇到X Window的这两个概念都会搞错。假设他从一台Windows机器上使用Exceed通过XDMCP登录到一台Sunserver,他就说Exceed是client(client),而Sun机器是server(server)。这就全然搞错了。X server不是指你登录的那台机器,而是指一个程序,它负责在某台机器上接受客户的要求,在屏幕上显示客户请求的图形,而且把消息(键盘,鼠标,窗体消息)通知客户程序。这个样例里本地的Exceed就是一个X
server,它负责控制这台Windows机器上的显示(display),远程Sun机器上的程序xterm, xxgdb, dtwm(CDE的窗体管理器)等,是客户程序。它们一般会使用TCP 6000号port连接Windows机器,而Windows机器的6000号port是由Exceed来bind和listen的。比方,当你通过telnet启动Sun机器上的xterm,就会 Exceed的屏幕上显示一个窗体。实际发生的事情是: xterm请求连接Windows机器的6000号port,跟Exceed连接,然后xterm请求得到资源,然后xterm请求在屏幕上显示一个窗体。你在xterm的窗体里按下"A"键时,Exceed会把这个事件通知xterm进程,然后xterm会发送数据报,请求Exceed,
“请在坐标(100,30)处显示一个字母A,然后在后面显示一个矩形作为光标。”这样你的xterm窗体里就会多显示一个字母。

    实际的远端client的样例有:图形化管理远程计算机;在远端UNIX计算机上执行计算密集的仿真程序并把结果显示到本地的Windows桌面计算机;用一套显示器、键盘和鼠标控制同一时候执行在多台计算机上的图形化软件。

    2、X Window System的启动过程

    从控制台(即字符界面)进入X通常是用startx命令。在前面“Linux init程序分析“中介绍过startx(以Fedora为例),这里以Ubuntu为例。startx是用xinit程序来启动X的。首先man startx和man xinit能够看到staratx和xinit的用法:

    startx [ [client] options .....] [-- [server] [display] options ....]

    xinit [ [client] options ] [-- [server] [display] options ...]

    把上面[client]和[server]分别称为X client程序和X server程序。man手冊里写明其必须以/或者./开头,即必须是绝对路径或从当前路径開始。

以下看看/usr/bin/startx这个脚本。

#!/bin/bash

#
# 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.
# unset DBUS_SESSION_BUS_ADDRESS
unset SESSION_MANAGER userclientrc=$HOME/.xinitrc # 用户的client定义文件
sysclientrc=/etc/X11/xinit/xinitrc # 系统的client定义文件 userserverrc=$HOME/.xserverrc # 用户的server定义文件
sysserverrc=/etc/X11/xinit/xserverrc # 系统的server定义文件
defaultclient=xterm # 默认的client程序
defaultserver=/usr/bin/X # 默认的server程序
defaultclientargs="" # 以下定义了client和server的參数变量
defaultserverargs=""
defaultdisplay=":0"
clientargs=""
serverargs="" enable_xauth=1 # 參数解析:将whoseargs变量赋值为字符串“client”,表示当前解析的指定client的參数
whoseargs="client"
while [ x"$1" != x ]; do # 若第一个參数为空,则直接退出循环
case "$1" in
# 须要单引號''以避免cpp把"/*"当作凝视
/''*|\./''*) # 假设$1是/*或者./*形式 (xinit程序要求其指定的client程序和server程序必须以/或./开头,
# 否则会被视为client程序和server程序本身的options參数,见man xinit)
if [ "$whoseargs" = "client" ]; then # 解析client程序的參数
if [ x"$client" = x ] && [ x"$clientargs" = x ]; then
client="$1" # 解析出用户指定的client程序
else
clientargs="$clientargs $1" #解析出client程序的options參数
fi
else
if [ x"$server" = x ] && [ x"$serverargs" = x ]; then
server="$1" # 解析出用户指定的X server程序
else
serverargs="$serverargs $1" # 解析出X server的options參数
fi
fi
;;
--) # 遇到“- -”就解析server
whoseargs="server"
;;
*)
if [ "$whoseargs" = "client" ]; then
clientargs="$clientargs $1"
else
# 解析[display]參数,屏幕编号[display]必须为第一个给server程序的參数,以:x的形式(x为数字)
if [ x"$serverargs" = x ] && \
expr "$1" : ':[0-9][0-9]*> /dev/null 2>&1; then
display="$1"
else
serverargs="$serverargs $1" # 解析[display]以外的參数
fi
fi
;;
esac
shift # 全部參数左移一次
done # 处理client參数
if [ x"$client" = x ]; then # 假设用户没有指定X client,则使用默认的X client即xterm
client=$defaultclient # 假设没有client的选项參数,则用rc文件取代
if [ x"$clientargs" = x ]; then
if [ -f "$userclientrc" ]; then
client=$userclientrc
elif [ -f "$sysclientrc" ]; then
client=$sysclientrc
fi clientargs=$defaultclientargs
fi
fi # 处理server參数
if [ x"$server" = x ]; then # 假设用户没有指定X server,则使用默认的X server即X
server=$defaultserver # 假设没有server的选项參数或display參数,使用默认值
if [ x"$serverargs" = x -a x"$display" = x ]; then
# 为了兼容性的考虑,假设没有server的命令行參数,仅仅使用xserverrc文件
if [ -f "$userserverrc" ]; then
server=$userserverrc
elif [ -f "$sysserverrc" ]; then
server=$sysserverrc
fi serverargs=$defaultserverargs
display=$defaultdisplay
fi
fi if [ x"$enable_xauth" = x1 ] ; then
if [ x"$XAUTHORITY" = x ]; then # 假设环境变量XAUTHORITY为空,就设定为$HOME/.Xauthority
XAUTHORITY=$HOME/.Xauthority
export XAUTHORITY
fi removelist= # 设置本机的默认Xauth信息 # 检查GNU主机名,假设hostname –version中不包括GNU 就将hostname变量设定为命令hostname –f返回的字符串
if hostname --version > /dev/null 2>&1; then
if [ -z "`hostname --version 2>&1 | grep GNU`" ]; then
hostname=`hostname -f`
fi
fi if [ -z "$hostname" ]; then
hostname=`hostname`
fi authdisplay=${display:-:0} mcookie=`/usr/bin/mcookie` if test x"$mcookie" = x; then
echo "Couldn't create cookie"
exit 1
fi
dummy=0 # 为server创建带有auth信息的文件,假设为屏幕编号为':0'
xserverauthfile=`mktemp --tmpdir 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
fi # #以下的语句通过xinit启动X server和Clients,把处理的參数传给它
xinit "$client" $clientargs -- "$server" $display $serverargs retval=$?
if [ x"$enable_xauth" = x1 ] ; then
if [ x"$removelist" != x ]; then
xauth remove $removelist
fi
if [ x"$xserverauthfile" != x ]; then
rm -f "$xserverauthfile"
fi
fi exit $retval

以上即为X Window System的启动过程,startx仅仅是负责一些參数传递,真正的X启动由xinit实现。我们能够知道,startx将会先解析用户的參数,假设该用户指定了该參数(即解析结果不为空),那么startx就会以该參数来启动xinit,否则就会解析(与其说是解析,还不如说是运行)$HOME文件夹下的rc文件,假设该文件不存在,就会解析系统文件夹下(/etc/X11/xinit/)的rc文件,假设这个文件也不存在,那startx就将以默认的client(xterm)和server(/usr/bin/X)为參数来启动xinit。比如,能够在用户文件夹下构造.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。

    到眼下为止,我们还不知道只在终端输入startx是怎么样启动gnome桌面的,gnome当然属于X client了。通过对startx的分析可知,startx主要有三种启动方式:

    (1)一种是自己指定要启动的client和server, 比如:startx /usr/bin/xclock -- /usr/bin/X :0;

    (2)一种是通过在$HOME下新建.xinitrc文件来指定要启动的多个client和.xserverrc来指定要启动的server(注意:这两个文件本来是不存在的);

    (3)另一种是直接输入startx而不指定參数,这也就是我们启动gnome桌面的方法。

    在第(3)中启动方法中,我们能够知道,startx脚本会先去看系统文件夹(/etc/X11/xinit/)下的rc文件是否存在,假设不存在就会用默认的xterm和/usr/bin/X来启动xinit。显然,startx启动的不是xterm,而是gnome桌面,因此gnome的启动是通过系统文件/etc/X11/xinit/xinitrc来指定的。在“Linux init程序分析”中具体介绍过的gnome的启动。这里以Ubuntu为例,/etc/X11/xinit/xinitrc文件里仅仅包括了. /etc/X11/Xsession一句话,因此gnome是通过Xsession脚本启动的(在Fedora中则是直接用xinitrc来启动gnome)。以下是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 # 以下4个是信息输出函数,能够无论
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>."
} # 初始化被全部session脚本使用的变量 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 # 尝试创建一个error文件,假设不能创建则退出
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 # 截短ERRFILE,假设它太大了,以避免硬盘空间的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)" # 理智的检查:#假设/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
SESSIONFILES=$(run-parts --list $SYSSESSIONDIR) # 将/etc/X11/Xsession.d文件夹中的全部文件都读出,并存入SESSIONFILES变量中
if [ -n "$SESSIONFILES" ]; then
set +e # 关闭errexit选项
for SESSIONFILE in $SESSIONFILES; do # 运行Xsession.d下的每个脚本
. $SESSIONFILE
done
set -e
fi exit 0 # vim:set ai et sts=2 sw=2 tw=80:

从以上的对Xsession脚本文件的分析,能够看出,Xsession脚本不过运行了/etc/X11/Xsession.d文件夹下的全部文件,每个文件名称都以数字开头,这些数字就表示了文件被运行的优先级,数字小的优先级高,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变量仍然为空(即没有使用用户指定的.xsession脚本),则将其设置为/usr/bin下的x-session-manager,x-window-manager或x-terminal-emulator,它们都是指向/etc/alternatives/下对应程序的符号链接。注意这个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,假设选择的是gnome-session,则运行$HOME/.gnomerc(假设该文件存在而且可读)。

    (6)60x11-common_localhost:使用xhost程序,把本机的username加入到同意连接X server的username列表中。username由`id -un`命令给出。

    (7)60xdg_path-on-session:依据选择的窗体会话,通过设置XDG_CONFIG_DIRS变量来加入额外的xdg路径。

    (8)60xdg-user-dirs-update:用xdg-user-dirs-update自己主动生成$HOME下的目录,该命令主要是依据/etc/xdg/user-dirs.defaults文件的内容来为用户创建目录的。

    (9)70gconfd_path-on-session:依据选择窗体会话,加入额外的gconf路径。

    (10)75dbus_dbus-launch:把use-session-dbus选择放入Xsession.options文件里,表示使用在窗体会话中使用dbus。把启动/usr/bin/dbus-launch程序的选择加入到STARTUP变量中。

    (11)80im-switch:该文件主要用于设置输入法。详细的请自己參考文件内容。

    (12)90consolekit:假设环境变量$XDG_SESSION_COOKIE为空,而且/usr/bin/ck-launch-session可运行,则将STARTUP又一次赋值为” /usr/bin/ck-launch-session $STARTUP”。至于ck-launch-session的功能,我也不是非常清楚,预计是和session有关,对窗体会话进行一些检查。

    (13)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”。

    (14)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终于指向的是gnome-session。

    gnome-session就是终于启动GNOME桌面环境的,这个程序一般被登入管理器gdm、xdm和脚本startx调用。总结一下Ubuntu中Gnome的启动过程,核心的流程总结例如以下:

/usr/bin/startx
--->xinit /etc/X11/xinit/xinitrc -- /etc/X11/xinit/xinitrc
--->./etc/X11/Xsession
--->/etc/X11/Xsession.d/
--->50x11-common_determine-startup
--->/etc/X11/Xsession.options # 寻找相关配置选项
--->STARTUP=$HOME/.xsession # 假设有.xsession脚本,则设置成执行它
--->STARTUP=/usr/bin/x-session-manager # 假设没有.xsession脚本,则设置成执行x-session-manager
--->/usr/bin/gnome-session # x-session-manager指向gnome-session程序
--->55gnome-session_gnomerc
--->$HOME/.gnomerc # 选择了gnome-session,则执行$HOME/.gnomerc
--->75dbus_dbus-launch # 启动dbus
--->80im-switch # 设置输入法
--->99x11-common_start
--->exec $STARTUP # 启动gnome会话,进入gnome桌面

3、跨网络执行X Window System

    通经常使用来做服务器的系统(Linux,FreeBSD,Solaris等等)都用字符界面,不会装X server,甚至非常多都没有显示器。这样能够在这些系统里安装简单的X client,以GUI的方式远程显示在管理员们所坐的X server里。比如能够用FreeBSD做网关,提供WWW,FTP服务,一般在管理员的本地机器起个X server,然后通过ssh或telnet登录远程到FreeBSD系统,执行X client程序显示在本地显示器上,当然,也可用XDMCP(X Display Manager Control
Protocol)的方式来登录执行。man xsession手冊里提到/etc/X11/Xsession一般被startx(Ubuntu中在/etc/X11/xinit/xinitrc里调用 Xsession脚本)或display manager调用,但有的display manager仅仅调用Xsession而不是xinitrc,故为了startx和display manager两种方式下都可正常启动GUI,最好把X client启动的程序放在Xsession文件中。远程执行X client程序须要设置DISPLAY环境变量,设置为
Xserver主机名称:屏幕编号(如192.168.1.115:0,则表示X server是192.168.1.115这台机器上的0号屏幕);或是给X client程序加个—display參数。这里我们在TCP/IP网络环境中測试X Window System。

    在VMWare虚拟机中安装Fedora 14,地址为192.168.1.115,使用/usr/bin/X作为X server。安装Ubuntu 10.04,地址为192.168.1.116。如今我们要使它们默认启动到字符界面。Fedora中比較简单,改动/etc/inittab文件,把当中的默认执行由5改成3,重新启动就可以。Ubuntu中使用grub v2,须要把/etc/default/grub文件里的GRUB_CMDLINE_LINUX_DEFAULT变量改动成"quiet splash text",即加上一个text參数,然后执行sudo
update-grub,又一次生成grub启动菜单的配置文件/boot/grub/grub.cfg。重新启动就可以。

    (1)配置X Server

    第一步:在$HOME下生成.Xauthority认证文件里

[jackzhou@localhost ~]$ xauth add 192.168.1.115:0 . `mcookie`

xauth: creating new authority file /root/.Xauthority

    第二步:查看认证文件

[jackzhou@localhost ~]$ xauth list

192.168.1.115:0  MIT-MAGIC-COOKIE-1  728ef8138827dcc82b7aa562d946796a

    第三步:通过上面的认证文件生成一个密钥文件jackcookie

[jackzhou@localhost ~]$ xauth extract jackcookie 192.168.1.115:0

[jackzhou@localhost ~]$ ls -l jackcookie

-rw-------. 1 jackzhou jackzhou 49 Jul 17 13:20 jackcookie

    第四步:将生成的密钥文件jackcookie,复制到X Client端。注意这须要Ubuntu上安装有open ssh server,能够用sudo apt-get install openssh-server安装。

[jackzhou@localhost ~]$ scp jackcookie 192.168.1.116:$HOME

The authenticity of host '192.168.1.116 (192.168.1.116)' can't be established.

RSA key fingerprint is fe:a2:ef:ab:75:37:04:47:c6:4d:02:9d:58:1c:f7:35.

Are you sure you want to continue connecting (yes/no)? yes

Warning: Permanently added '192.168.1.116' (RSA) to the list of known hosts.

jackzhou@192.168.1.116's password:

jackcookie                                      100%   49     0.1KB/s   00:00

    第五步:在后台启动X Server

[jackzhou@localhost ~]$ X -auth $HOME/.Xauthority &

    这样X server会在tty7上执行(tty7上是执行图形界面的),通过Ctrl+Alt+F7能够切换到X界面,上面一片黑暗,仅仅显示一个光标。能够通过Ctrl+Alt+F1切换回原来的字符界面,因为在不同的tty上执行,它们互不影响。

    (2)配置X Client

    第一步:将X Server传送过来的password文件jackcookie,进行导入操作

jackzhou@jackzhou-desktop:~$ ls -l jackcookie

-rw------- 1 jackzhou jackzhou 2011-07-17 13:17 jackcookie

jackzhou@jackzhou-desktop:~$ xauth merge jackcookie

jackzhou@jackzhou-desktop:~$ ls -l jackcookie

-rw------- 1 jackzhou jackzhou 49 2011-07-17 13:21 jackcookie

    第二步:配置DISPLAY环境变量

jackzhou@jackzhou-desktop:~$ export DISPLAY=192.168.1.115:0

    第三步:启动各种X Client,如xterm和xeye、、xclock、twm、gedit、gnome-terminal,甚至gnome-session程序,都行。注意twm在Ubuntu中默认没有安装,能够用apt-get安装。

jackzhou@jackzhou-desktop:~$ xterm &

jackzhou@jackzhou-desktop:~$ xeyes &

jackzhou@jackzhou-desktop:~$ twm &

    这样在Fedora的X Server上就会显示Ubuntu中对应的X client界面了。通常的应用场景是X client机器在远程且没有显示器,X Server机器在本地,你能够通过在Fedora中使用ssh 192.168.1.116登录到远程的X client机器,来配置X Client,而不用直接跑到远程的机器上去配。

    要更加深入地研究X Window System,可參考man xserver和man x的手冊页,Wikipedia的介绍http://zh.wikipedia.org/zh-cn/X_Window,以及Xorg Foundation的官方网站http://www.x.org/wiki/。下载X11R7.6的源码,里面有各模块设计的具体文档说明。

上一篇:一口气带你读懂80年IT发展史


下一篇:一、【Docker笔记】进入Docker世界