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的源碼,里面有各模塊設計的具體文檔說明。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM