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 6000端口上。那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来创建按钮、对话框、轴、窗口等视窗结构,这样开发者可以容易地开发各种程序。
    总结下运行过程:
    (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(服务器),提供图形界面的驱动,为X Window提供服务。上面的一层是用于网络通信的网络协议,即X网络协议,这部分使远程运行X Window成为可能。只需要在服务器上运行一个X Server,而客户机(Client)上运行更上一层的程序,则可以实现X Window的远程运行。再往上的一层是称作Xlib的函数接口,介于基础系统和较高层应用程序之间。应用程序的实现是通过调用这一层的函数实现的。最顶层就是窗口管理器了,也就是一般所说的WM(Window Manager),这一层的软件是用户经常接触的,比如fvwm、AfterStep、Enlightment以及WindowMaker等。
    从上面的介绍来看,X Window的运行是一种客户机/服务器(Client/Server)的模式,服务器用于显示客户机运行的应用程序,又被称为显示服务器 (Display Server)。显示服务器位于硬件和客户机之间,它跟踪所有来自输入设备(比如键盘、鼠标)的输入动作,经过处理后将其送回客户机。这样,用户可以在 Microsoft Windows的机器上运行X Client,截取并传送用户的输入,只是将X Window的屏幕输出显示在用户的屏幕上。客户机的输入和输出系统跟X服务器之间的通信都是遵守X协议的。
    搞清楚X server与X client关系很重要。一般X server很简单,就是/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中所提及的“客户端”和“服务器”等字眼用词与人们一般想定的相反,“服务器”反而是在用户本地端的自有机器上运行,而非是在远程的另一部机器上运行。很多熟悉Internet原理的人首次遇到X Window的这两个概念都会搞错。如果他从一台Windows机器上使用Exceed通过XDMCP登录到一台Sun服务器,他就说Exceed是客户端(client),而Sun机器是服务器(server)。这就完全搞错了。X server不是指你登录的那台机器,而是指一个程序,它负责在某台机器上接受客户的要求,在屏幕上显示客户请求的图形,并且把消息(键盘,鼠标,窗口消息)通知客户程序。这个例子里本地的Exceed就是一个X server,它负责控制这台Windows机器上的显示(display),远程Sun机器上的程序xterm, xxgdb, dtwm(CDE的窗口管理器)等,是客户程序。它们通常会使用TCP 6000号端口连接Windows机器,而Windows机器的6000号端口是由Exceed来bind和listen的。比如,当你通过telnet启动Sun机器上的xterm,就会 Exceed的屏幕上显示一个窗口。实际发生的事情是: xterm请求连接Windows机器的6000号端口,跟Exceed连接,然后xterm请求得到资源,然后xterm请求在屏幕上显示一个窗口。你在xterm的窗口里按下"A"键时,Exceed会把这个事件通知xterm进程,然后xterm会发送数据报,请求Exceed, “请在坐标(100,30)处显示一个字母A,然后在后面显示一个矩形作为光标。”这样你的xterm窗口里就会多显示一个字母。
    实际的远端客户端的例子有:图形化管理远程计算机;在远端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这个脚本。

[python] view plain copy
  1. #!/bin/bash  
  2.   
  3. #  
  4. # This is just a sample implementation of a slightly less primitive  
  5. # interface than xinit.  It looks for user .xinitrc and .xserverrc  
  6. # files, then system xinitrc and xserverrc files, else lets xinit choose  
  7. # its default.  The system xinitrc should probably do things like check  
  8. # for .Xresources files and merge them in, startup up a window manager,  
  9. # and pop a clock and serveral xterms.  
  10. #  
  11. # Site administrators are STRONGLY urged to write nicer versions.  
  12. #  
  13.   
  14. unset DBUS_SESSION_BUS_ADDRESS  
  15. unset SESSION_MANAGER  
  16.    
  17. userclientrc=$HOME/.xinitrc                  # 用户的client定义文件  
  18. sysclientrc=/etc/X11/xinit/xinitrc           # 系统的client定义文件  
  19.   
  20. userserverrc=$HOME/.xserverrc                # 用户的server定义文件  
  21. sysserverrc=/etc/X11/xinit/xserverrc         # 系统的server定义文件  
  22. defaultclient=xterm                          # 默认的client程序   
  23. defaultserver=/usr/bin/X                     # 默认的server程序   
  24. defaultclientargs=""                         # 下面定义了client和server的参数变量  
  25. defaultserverargs=""  
  26. defaultdisplay=":0"  
  27. clientargs=""  
  28. serverargs=""  
  29.   
  30. enable_xauth=1  
  31.   
  32. # 参数解析:将whoseargs变量赋值为字符串“client”,表示当前解析的指定client的参数  
  33. whoseargs="client"  
  34. while [ x"$1" != x ]; do                     # 若第一个参数为空,则直接退出循环  
  35.     case "$1" in  
  36.     # 需要单引号''以避免cpp把"/*"当作注释  
  37.     /''*|\./''*)            # 如果$1是/*或者./*形式 (xinit程序要求其指定的client程序和server程序必须以/或./开头,  
  38.                             # 否则会被视为client程序和server程序本身的options参数,见man xinit)   
  39.         if [ "$whoseargs" = "client" ]; then       # 解析client程序的参数  
  40.             if [ x"$client" = x ] && [ x"$clientargs" = x ]; then  
  41.                 client="$1"              # 解析出用户指定的client程序  
  42.             else  
  43.                 clientargs="$clientargs $1"   #解析出client程序的options参数  
  44.             fi  
  45.         else  
  46.             if [ x"$server" = x ] && [ x"$serverargs" = x ]; then  
  47.                 server="$1"                  # 解析出用户指定的X server程序  
  48.             else  
  49.                 serverargs="$serverargs $1"  # 解析出X server的options参数  
  50.             fi  
  51.         fi  
  52.         ;;  
  53.     --)                       # 遇到“- -”就解析server  
  54.         whoseargs="server"  
  55.         ;;  
  56.     *)  
  57.         if [ "$whoseargs" = "client" ]; then  
  58.             clientargs="$clientargs $1"  
  59.         else  
  60.             # 解析[display]参数,屏幕编号[display]必须为第一个给server程序的参数,以:x的形式(x为数字)  
  61.             if [ x"$serverargs" = x ] && \  
  62.                 expr "$1" : ':[0-9][0-9]*> /dev/null 2>&1; then  
  63.                 display="$1"  
  64.             else  
  65.                 serverargs="$serverargs $1"   # 解析[display]以外的参数  
  66.             fi  
  67.         fi  
  68.         ;;  
  69.     esac  
  70.     shift         # 所有参数左移一次  
  71. done  
  72.   
  73. # 处理client参数  
  74. if [ x"$client" = x ]; then    # 如果用户没有指定X client,则使用默认的X client即xterm  
  75.     client=$defaultclient  
  76.   
  77.     # 如果没有client的选项参数,则用rc文件代替  
  78.     if [ x"$clientargs" = x ]; then  
  79.         if [ -f "$userclientrc" ]; then  
  80.             client=$userclientrc  
  81.         elif [ -f "$sysclientrc" ]; then  
  82.             client=$sysclientrc  
  83.         fi  
  84.   
  85.         clientargs=$defaultclientargs  
  86.     fi  
  87. fi  
  88.   
  89. # 处理server参数  
  90. if [ x"$server" = x ]; then     # 如果用户没有指定X server,则使用默认的X server即X  
  91.     server=$defaultserver  
  92.   
  93.     # 如果没有server的选项参数或display参数,使用默认值  
  94.     if [ x"$serverargs" = x -a x"$display" = x ]; then  
  95.     # 为了兼容性的考虑,如果没有server的命令行参数,只使用xserverrc文件  
  96.     if [ -f "$userserverrc" ]; then  
  97.         server=$userserverrc  
  98.     elif [ -f "$sysserverrc" ]; then  
  99.         server=$sysserverrc  
  100.     fi  
  101.   
  102.     serverargs=$defaultserverargs  
  103.     display=$defaultdisplay  
  104.     fi  
  105. fi  
  106.   
  107. if [ x"$enable_xauth" = x1 ] ; then  
  108.     if [ x"$XAUTHORITY" = x ]; then       # 如果环境变量XAUTHORITY为空,就设定为$HOME/.Xauthority  
  109.         XAUTHORITY=$HOME/.Xauthority  
  110.         export XAUTHORITY  
  111.     fi  
  112.   
  113.     removelist=  
  114.   
  115.     # 设置本机的默认Xauth信息  
  116.   
  117.     # 检查GNU主机名,如果hostname –version中不包含GNU 就将hostname变量设定为命令hostname –f返回的字符串  
  118.     if hostname --version > /dev/null 2>&1; then  
  119.         if [ -z "`hostname --version 2>&1 | grep GNU`" ]; then  
  120.             hostname=`hostname -f`  
  121.         fi  
  122.     fi  
  123.   
  124.     if [ -z "$hostname" ]; then  
  125.         hostname=`hostname`  
  126.     fi  
  127.   
  128.     authdisplay=${display:-:0}  
  129.   
  130.     mcookie=`/usr/bin/mcookie`  
  131.   
  132.     if test x"$mcookie" = x; then  
  133.         echo "Couldn't create cookie"  
  134.         exit 1  
  135.     fi  
  136.     dummy=0  
  137.   
  138.     # 为server创建带有auth信息的文件,假设为屏幕编号为':0'  
  139.     xserverauthfile=`mktemp --tmpdir serverauth.XXXXXXXXXX`  
  140.     trap "rm -f '$xserverauthfile'" HUP INT QUIT ILL TRAP KILL BUS TERM  
  141.     xauth -q -f "$xserverauthfile" << EOF  
  142. add :$dummy . $mcookie  
  143. EOF  
  144.   
  145.     serverargs=${serverargs}" -auth "${xserverauthfile}  
  146.   
  147.   
  148.     # now add the same credentials to the client authority file  
  149.     # if '$displayname' already exists do not overwrite it as another  
  150.     # server man need it. Add them to the '$xserverauthfile' instead.  
  151.     for displayname in $authdisplay $hostname$authdisplay; do  
  152.         authcookie=`xauth list "$displayname" \  
  153.         | sed -n "s/.*$displayname[[:space:]*].*[[:space:]*]//p"2>/dev/null;  
  154.         if [ "z${authcookie}" = "z" ] ; then  
  155.             xauth -q << EOF   
  156. add $displayname . $mcookie  
  157. EOF  
  158.         removelist="$displayname $removelist"  
  159.         else  
  160.             dummy=$(($dummy+1));  
  161.             xauth -q -f "$xserverauthfile" << EOF  
  162. add :$dummy . $authcookie  
  163. EOF  
  164.         fi  
  165.     done  
  166. fi  
  167.   
  168. # #下面的语句通过xinit启动X server和Clients,把处理的参数传给它  
  169. xinit "$client" $clientargs -- "$server" $display $serverargs  
  170.   
  171. retval=$?  
  172. if [ x"$enable_xauth" = x1 ] ; then  
  173.     if [ x"$removelist" != x ]; then  
  174.         xauth remove $removelist  
  175.     fi  
  176.     if [ x"$xserverauthfile" != x ]; then  
  177.         rm -f "$xserverauthfile"  
  178.     fi  
  179. fi  
  180.   
  181. 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文件:

[python] view plain copy
  1. #!/bin/sh      # 注意该脚本用的是Bourne shell解析的  
  2. #  
  3. # /etc/X11/Xsession  
  4. #  
  5. # global Xsession file -- used by display managers and xinit (startx)  
  6.   
  7. # $Id: Xsession 967 2005-12-27 07:20:55Z dnusinow $  
  8.   
  9. set -e         # 打开errexit选项,该选项表示如果下面有命令返回的状态非0,则退出程序  
  10.   
  11. PROGNAME=Xsession  
  12.   
  13. # 下面4个是信息输出函数,可以不管  
  14. message () {  
  15.   # pretty-print messages of arbitrary length; use xmessage if it  
  16.   # is available and $DISPLAY is set  
  17.   MESSAGE="$PROGNAME: $*"  
  18.   echo "$MESSAGE" | fold -s -w ${COLUMNS:-80} >&2  
  19.   if [ -n "$DISPLAY" ] && which xmessage > /dev/null 2>&1; then  
  20.     echo "$MESSAGE" | fold -s -w ${COLUMNS:-80} | xmessage -center -file -  
  21.   fi  
  22. }  
  23.   
  24. message_nonl () {  
  25.   # pretty-print messages of arbitrary length (no trailing newline); use  
  26.   # xmessage if it is available and $DISPLAY is set  
  27.   MESSAGE="$PROGNAME: $*"  
  28.   echo -n "$MESSAGE" | fold -s -w ${COLUMNS:-80} >&2;  
  29.   if [ -n "$DISPLAY" ] && which xmessage > /dev/null 2>&1; then  
  30.     echo -n "$MESSAGE" | fold -s -w ${COLUMNS:-80} | xmessage -center -file -  
  31.   fi  
  32. }  
  33.   
  34. errormsg () {  
  35.   # exit script with error  
  36.   message "$*"  
  37.   exit 1  
  38. }  
  39.   
  40. internal_errormsg () {  
  41.   # exit script with error; essentially a "THIS SHOULD NEVER HAPPEN" message  
  42.   # One big call to message() for the sake of xmessage; if we had two then  
  43.   # the user would have dismissed the error we want reported before seeing the  
  44.   # request to report it.  
  45.   errormsg "$*" \  
  46.            "Please report the installed version of the \"x11-common\"" \  
  47.            "package and the complete text of this error message to" \  
  48.            "<[email protected]>."  
  49. }  
  50.   
  51. # 初始化被所有session脚本使用的变量  
  52.   
  53. OPTIONFILE=/etc/X11/Xsession.options  
  54.   
  55. SYSRESOURCES=/etc/X11/Xresources  
  56. USRRESOURCES=$HOME/.Xresources  
  57.   
  58. SYSSESSIONDIR=/etc/X11/Xsession.d  
  59. USERXSESSION=$HOME/.xsession  
  60. USERXSESSIONRC=$HOME/.xsessionrc  
  61. ALTUSERXSESSION=$HOME/.Xsession  
  62. ERRFILE=$HOME/.xsession-errors  
  63.   
  64. # 尝试创建一个error文件,如果不能创建则退出  
  65. if (umask 077 && touch "$ERRFILE"2> /dev/null && [ -w "$ERRFILE" ] &&  
  66.   [ ! -L "$ERRFILE" ]; then  
  67.   chmod 600 "$ERRFILE"  
  68. elif ERRFILE=$(tempfile 2> /dev/null); then  
  69.   if ! ln -sf "$ERRFILE" "${TMPDIR:=/tmp}/xsession-$USER"; then  
  70.     message "warning: unable to symlink \"$TMPDIR/xsession-$USER\" to" \  
  71.              "\"$ERRFILE\"; look for session log/errors in" \  
  72.              "\"$TMPDIR/xsession-$USER\"."  
  73.   fi  
  74. else  
  75.   errormsg "unable to create X session log/error file; aborting."  
  76. fi  
  77.   
  78. # 截短ERRFILE,如果它太大了,以避免硬盘空间的DoS攻击  
  79. if [ "`stat -c%s \"$ERRFILE\"`" -gt 500000 ]; then  
  80.   T=`mktemp -p "$HOME"`  
  81.   tail -c 500000 "$ERRFILE" > "$T" && mv -f "$T" "$ERRFILE" || rm -f "$T"  
  82. fi  
  83.   
  84. exec >>"$ERRFILE" 2>&1  
  85.   
  86. echo "$PROGNAME: X session started for $LOGNAME at $(date)"  
  87.   
  88. # 理智的检查:#如果/etc/X11/Xsession.d不存在或不是一个目录则打印错误信息并退出  
  89. if [ ! -d "$SYSSESSIONDIR" ]; then  
  90.   errormsg "no \"$SYSSESSIONDIR\" directory found; aborting."  
  91. fi  
  92.   
  93. # Attempt to create a file of non-zero length in /tmp; a full filesystem can  
  94. # cause mysterious X session failures.  We do not use touch, :, or test -w  
  95. # because they won't actually create a file with contents.  We also let standard  
  96. # error from tempfile and echo go to the error file to aid the user in  
  97. # determining what went wrong.  
  98. WRITE_TEST=$(tempfile)  
  99. if ! echo "*" >>"$WRITE_TEST"; then  
  100.   message "warning: unable to write to ${WRITE_TEST%/*}; X session may exit" \  
  101.           "with an error"  
  102. fi  
  103. rm -f "$WRITE_TEST"  
  104.   
  105. # use run-parts to source every file in the session directory; we source  
  106. # instead of executing so that the variables and functions defined above  
  107. # are available to the scripts, and so that they can pass variables to each  
  108. # other  
  109. SESSIONFILES=$(run-parts --list $SYSSESSIONDIR)   # 将/etc/X11/Xsession.d目录中的所有文件都读出,并存入SESSIONFILES变量中  
  110. if [ -n "$SESSIONFILES" ]; then  
  111.   set +e       # 关闭errexit选项  
  112.   for SESSIONFILE in $SESSIONFILES; do        # 执行Xsession.d下的每一个脚本  
  113.     . $SESSIONFILE  
  114.   done  
  115.   set -e  
  116. fi  
  117.   
  118. exit 0  
  119.   
  120. # 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程序,把本机的用户名添加到允许连接X server的用户名列表中。用户名由`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的启动过程,核心的流程总结如下:
[python] view plain copy
  1. /usr/bin/startx  
  2.     --->xinit /etc/X11/xinit/xinitrc -- /etc/X11/xinit/xinitrc  
  3.         --->./etc/X11/Xsession  
  4.             --->/etc/X11/Xsession.d/  
  5.                 --->50x11-common_determine-startup  
  6.                     --->/etc/X11/Xsession.options        # 寻找相关配置选项  
  7.                     --->STARTUP=$HOME/.xsession      # 如果有.xsession脚本,则设置成运行它  
  8.                     --->STARTUP=/usr/bin/x-session-manager   # 如果没有.xsession脚本,则设置成运行x-session-manager  
  9.                         --->/usr/bin/gnome-session   # x-session-manager指向gnome-session程序  
  10.                 --->55gnome-session_gnomerc  
  11.                     --->$HOME/.gnomerc       # 选择了gnome-session,则运行$HOME/.gnomerc  
  12.                 --->75dbus_dbus-launch       # 启动dbus  
  13.                 --->80im-switch      # 设置输入法  
  14.                 --->99x11-common_start  
  15.                     --->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.
[email protected]'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传送过来的密码文件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的源代码,里面有各模块设计的详细文档说明。



你可能感兴趣的:(windows,server,Microsoft,脚本,ubuntu,System)