分页: 4/6 第一页 上页 1 2 3 4 5 6 下页 最后页 [ 显示模式: 摘要 | 列表 ]
Feb 5
如果自己的服务器也能够实现简记域名就好了。其实这并不复杂。你也可以做一个简记域名系统。
  简记域名系统的关键技术在于:实现Web页面的重定向(Redirctory)。在本质上,简





















































  echo '<meta http-equiv="refresh" content="0;','url=',,'">';}
Dec 20

  Apache服务器的主要安全缺陷

  正如我们前言所说尽管Apache服务器应用最为广泛,设计上非常安全的程序。但是同其它应用程序一样,Apache也存在安全缺陷。毕竟它是完全源代码,Apache服务器的安全缺陷主要是使用HTTP协议进行的拒绝服务攻击(denial of service)、缓冲区溢出攻击以及被攻击者获得root权限三缺陷和最新的恶意的攻击者进行“拒绝服务”(DoS)攻击。合理的网络配置能够保护Apache服务器免遭多种攻击。我们来介绍一下主要的安全缺陷:

  (1)使用HTTP协议进行的拒绝服务攻击(denial of service)的安全缺陷

  这种方法攻击者会通过某些手段使服务器拒绝对HTTP应答。这样会使Apache对系统资源(CPU时间和内存)需求的剧增,最终造成Apache系统变慢甚至完全瘫痪。

  (2)缓冲区溢出的安全缺陷

  该方法攻击者利用程序编写的一些缺陷,使程序偏离正常的流程。程序使用静态分配的内存保存请求数据,攻击者就可以发送一个超长请求使缓冲区溢出。

  (3)被攻击者获得root权限的安全缺陷

  该安全缺陷主要是因为Apache服务器一般以root权限运行(父进程),攻击者会通过它获得root权限,进而控制整个Apache系统。

  (4)恶意的攻击者进行“拒绝服务”(DoS)攻击的安全缺陷

  这个最新在6月17日发现的漏洞,它主要是存在于Apache的chunk encoding中,这是一个HTTP协议定义的用于接受web用户所提交数据的功能。 所有说使用最高和最新安全版本对于加强Apache Web服务器的安全是至关重要的。

  请广大Apache服务器管理员去http://www.apache.org/dist/httpd/下载补丁程序以确保其WEB服务器安全!

  正确维护和配置Apache服务器

  虽然Apache服务器的开发者非常注重安全性,由于Apache服务器其庞大的项目, 难免会存在安全隐患。正确维护和配置Apache WEB服务器就很重要了。我们应注意的一些问题:

  (1)Apache服务器配置文件

  Apache Web服务器主要有三个配置文件,位于/usr/local/apache/conf目录下。 这三个文件是:

  httpd.conf----->主配置文件
  srm.conf------>填加资源文件
  access.conf--->设置文件的访问权限

  注:具体配置可以参考:http://httpd.apache.org/docs/mod/core.html

  (2)Apache服务器的目录安全认证

  在Apache Server中是允许使用 .htaccess做目录安全保护的,欲读取这保护的目录需要先键入正确用户帐号与密码。这样可做为专门管理网页存放的目录或做为会员区等。在保护的目录放置一个档案,档名为.htaccss
  AuthName "会员专区"
  AuthType "Basic"
  AuthUserFile "/var/tmp/xxx.pw" ----->把password放在网站外 require valid-user 到apache/bin目录,建password档 % ./htpasswd -c /var/tmp/xxx.pw username1 ----->第一次建档要用参数"-c" % /htpasswd /var/tmp/xxx.pw username2 这样就可以保护目录内的内容,进入要用合法的用户.

  注:采用了Apache内附的模组。

  也可以采用在httpd.conf中加入: 
  options indexes followsymlinks 
  allowoverride authconfig 
  order allow,deny 
  allow from all 

  (3)Apache服务器访问控制

  我们就要看三个配置文件中的第三个文件了,即access.conf文件,它包含一些指令控制允许什么用户访问Apache目录。应该把deny from all设为初始化指令,再使用allow from指令打开访问权限。

  <directory /usr/local/http/docs/private>
  <limit>
  order deny,allow
  deny from all
  allow from safechina.net
  </limit>
  </directory>
  设置允许来自某个域、IP地址或者IP段的访问。


  (4)Apache服务器的密码保护问题

  我们再使用.htaccess文件把某个目录的访问权限赋予某个用户。系统管理员需要在httpd.conf或者rm.conf文件中使用 AccessFileName指令打开目录的访问控制。如:

  AuthName PrivateFiles
  AuthType Basic
  AuthUserFile /path/to/httpd/users
  require Phoenix
  # htpasswd -c /path/to/httpd/users Phoenix

  设置Apache服务器的WEB和文件服务器

  我们在Apache服务器上存放WEB服务器的文件,供用户访问,并设置/home/ftp/pub目录为文件存放区域,用http://download.your.com/pub/来访问。在防火墙上设置apache反向代理技术,由防火墙代理访问。 
 
  (1)Apache服务器的设置 

  apache服务器采用默认配置。主目录为/home/httpd/html,主机域名为Phoenix.your.com, 且别名到www.your.com中, 并且设置srm.conf加一行别名定义如下:

  Alias /pub /home/ftp/pub/ 

  更改默认应用程序类型定义如下: 
  DefaultType application/octet-stream 

  最后在/etc/httpd/conf/access.conf中增加一项定义 
  Options Indexes 
  AllowOverride AuthConfig 
  order allow,deny 
  allow from all 

  注:Options Indexes允许在找不到index.html文件的情况下允许列出目录/文件列表。AllowOverride AuthConfig允许做基本的用户名和口令验证。这样的话,需要在/home/ftp/pub目录下放入.htaccess,内容如下: 
  [root@ pub]# more .htaccess 
  AuthName Branch Office Public Software Download Area 
  AuthType Basic 
  AuthUserFile /etc/.usrpasswd 
  require valid-user 
  用# htpasswd -c /etc/.usrpasswd user1  分别创建不同的允许访问/pub下文件服务的外部用户名和口令。
 
  (2)在防火墙上配置反向代理技术.
 
  在/etc/httpd/conf/httpd.conf  中加入 NameVirtualHost xxx.xxx.xxx.xxx # xxx.xxx.xxx.xxx ----->是防火墙外部在互联网上永久IP地址 
  servername www.your.com 
  errorlog /var/log/httpd/error_log 
  transferlog /var/log/httpd/access_log 
  rewriteengine on 
  proxyrequests off 
  usecanonicalname off 
  rewriterule ^/(.*)$ http://xxx.xxx.xx.x/$1 Apache服务器的IP地址。

  servername http://download.your.com/pub/
  errorlog /var/log/httpd/download/error_log 
  transferlog /var/log/httpd/download/access_log 
  rewriteengine on 
  proxyrequests off 
  usecanonicalname off 
  rewriterule ^/(.*)$ http://xxx.xxx.xx.x/$1 同上Apache服务器的IP地址。

  设置防火墙上的DNS,让download.your.com和www.your.com 都指向防火墙的外部网地址xxx.xxx.xxx.xxx。
用http://www.your.com访问主页,用http://download.your.com/pub/访问公共文件的下载区。

  注:还需要在apache服务器主机上建立目录/var/log/httpd/download/,否则会出错。另外,也可以设置防火墙主机上的/home/httpd/html/index.html的属性为750来阻止访问,这是防外部用户能访问到防火墙上的Apache服务器的http://www.your.com中。 

  总结:Apache Server是一个非常优秀,非常棒的服务器,只要你正确配置和维护好Apache服务器,
你就会感受到Apache Server 所带来的好处,同样希望你能够通过阅读本文达到理论和实践双丰收的目的。
谢谢。

Nov 25
后缀是bat的文件就是批处理文件,是一种文本文件。简单的说,它的作用就是自动的连续执行多条命令,批处理文件的内容就是一条一条的命令。那它有什么用呢? 比如,在启动wps软件时,每次都必须执行

C:\>cd wps
  C:\WPS>spdos
  C:\WPS>py
  C:\WPS>wbx
  C:\WPS>wps
如果每次用WPS之前都这样执行一次,您是不是觉得很麻烦呢?
如果有一个方法,只需编写一个批处理文件,就会自动执行刚才的所有命令,您想不想学呢? 当您看完此节,自己编写的第一个批处理文件顺利执行时,您一定会大吃一惊的。

常用命令
  echo、@、call、pause、rem 是批处理文件最常用的几个命令,我们就从他们开始学起。 echo 表示显示此命令后的字符
echo off 表示在此语句后所有运行的命令都不显示命令行本身
@ 与echo off相象,但它是加在其它命令行的最前面,表示运行时不显示命令行本身。
call 调用另一条批处理文件(如果直接调用别的批处理文件 ,执行完那条文件后将无法执行当前文件后续命令)
pause 运行此句会暂停,显示Press any key to continue... 等待用户按任意键后继续
rem 表示此命令后的字符为解释行,不执行,只是给自己今后查找用的

  例:用edit编辑a.bat文件,输入下列内容后存盘为c:\a.bat,执行该批处理文件后可实现:将根目录中所有文件写入 a.txt中,启动UCDOS,进入WPS等功能。

  批处理文件的内容为:         文件表示:

    echo off            不显示命令行
    dir c:\*.* >a.txt       将c盘文件列表写入a.txt
    call c:\ucdos\ucdos.bat    调用ucdos
    echo 你好            显示"你好"
    pause              暂停,等待按键继续
    rem 使用wps           注释将使用wps
    cd ucdos            进入ucdos目录
    wps               使用wps  

  批处理文件中还可以像C语言一样使用参数,这只需用到一个参数表示符%。

   %表示参数,参数是指在运行批处理文件时在文件名后加的字符串。变量可以从 %0到%9,%0表示文件名本身,字符串用%1到%9顺序表示。

  例如,C:根目录下一批处理文件名为f.bat,内容为 format %1
  则如果执行C:\>f a:    则实际执行的是format a:

  又如C:根目录下一批处理文件的名为t.bat,内容为 type %1 type %2

  那么运行C:\>t a.txt b.txt 将顺序地显示a.txt和b.txt文件的内容
此外电脑每次启动时都会寻找autoexec.bat这条批处理文件,从而可执行一些每次开机都要执行的命令,如设置路径path、加载鼠标驱动mouse、磁盘加速smartdrv等,可以使您的电脑真正自动化。

特殊命令

  if goto choice for 是批处理文件中比较高级的命令,如果这几个你用得很熟练,你就是批处理文件的专家啦。 if 表示将判断是否符合规定的条件,从而决定执行不同的命令。 有三种格式:
1、if "参数" == "字符串"  待执行的命令
参数如果等于指定的字符串,则条件成立,运行命令,否则运行下一句。(注意是两个等号)
如if "%1"=="a" format a:

2、if exist 文件名  待执行的命令
如果有指定的文件,则条件成立,运行命令,否则运行下一句。如if exist config.sys edit config.sys

3、if errorlevel 数字  待执行的命令
如果返回码等于指定的数字,则条件成立,运行命令,否则运行下一句。如if errorlevel 2 goto x2  DOS程序运行时都会返回一个数字给DOS,称为错误码errorlevel或称返回码

goto 批处理文件运行到这里将跳到goto 所指定的标号处, 一般与if配合使用。 如:
goto end

:end
echo this is the end

标号用 :字符串 表示,标号所在行不被执行

choice 使用此命令可以让用户输入一个字符,从而运行不同的命令。使用时应该加/c:参数,c:后应写提示可输入的字符,之间无空格。它的返回码为1234……

如: choice /cme defrag,mem,end
将显示
defrag,mem,end[D,M,E]?

例如,test.bat的内容如下:
@echo off
choice /cme defrag,mem,end
if errorlevel 3 goto defrag 应先判断数值最高的错误码
if errorlevel 2 goto mem
if errotlevel 1 goto end

efrag
c:\dos\defrag
goto end

:mem
mem
goto end

:end
echo good bye

此文件运行后,将显示 defrag,mem,end[D,M,E]? 用户可选择d m e ,然后if语句将作出判断,d表示执行标号为defrag的程序段,m表示执行标号为mem的程序段,e表示执行标号为end的程序段,每个程序段最后都以goto end将程序跳到end标号处,然后程序将显示good bye,文件结束。

for 循环命令,只要条件符合,它将多次执行同一命令。

格式FOR [%%f] in (集合) DO [命令]
只要参数f在指定的集合内,则条件成立,执行命令

如果一条批处理文件中有一行:
for %%c in (*.bat *.txt) do type %%c
含义是如果是以bat或txt结尾的文件,则显示文件的内容。

autoexec.bat

   DOS在启动会自动运行autoexec.bat这条文件,一般我们在里面装载每次必用的程序,如: path(设置路径)、smartdrv(磁盘加速)、 mouse(鼠标启动)、mscdex(光驱连接)、 doskey(键盘管理)、set(设置环境变量)等。

  如果启动盘根目录中没有这个文件,电脑会让用户输入日期和时间。

  例如,一个典型的autoexec.bat内容如下:

@echo off                  不显示命令行

prompt $p$g                 设置提示符前有目录提示

path c:\dos;c:\;c:\windows;c:\ucdos;c:\tools    设置路径

lh c:\dos\doskey.com                加载键盘管理

lh c:\mouse\mouse.com              加载鼠标管理

lh c:\dos\smartdrv.exe               加载磁盘加速管理

lh c:\dos\mscdex /S /D:MSCD000 /M:12 /V    加载CD-ROM驱动

set temp=c:\temp                  设置临时目


IF -EXIST

首先用记事本建立一个文件,文件内容如下:
@echo off
IF EXIST \AUTOEXEC.BAT TYPE \AUTOEXEC.BAT
IF NOT EXIST \AUTOEXEC.BAT ECHO \AUTOEXEC.BAT does not exist
在C盘保存文件为TEST.BAT
然后执行命令
C:\>TEST1.BAT
这时,如果AUTOEXEC.BAT中有内容的话会显示出来。

接着再建立一个文件,内容如下:
@ECHO OFF
IF EXIST %1 TYPE %1
IF NOT EXIST %1 ECHO %1 does not exist
也保存在C盘,文件名为TEST2.BAT
然后执行命令
C:\>TEST2 AUTOEXEC.BAT
同样,如果AUTOEXEC.BAT中有内容的话会显示出来。

说明:
1. IF EXIST 是用来测试文件是否存在的,格式为
IF EXIST [路径+文件名] 命令
2. 其中第二个文件中的%1是参数,DOS允许传递9个批参数信息给批处理文件,分别为%1---------%9 ,有点想实参和形参的关系,%1是形参,AUTOEXEC.BAT是实参。
更进一步的,建立一个名为ABC.BAT的文件,内容如下:
IF ‘%1’ = = ‘ A ’ ECHO XIAO
IF ‘%1’ = = ‘ B ’ ECHO TIAN
IF ‘%1’ = = ‘ C ’ ECHO XIN
完成后运行C:\>ABC.BAT A B C
屏幕上会显示C:\>XIAOTIANXIA
如果执行C:\>ABC.BAT A B
屏幕上会显示C:\>XIAOTIAN
DOS将一个空字符串附给参数%3。
可以将NOT放在IF和条件之间,指示IF在条件为假时执行某一命令。
注意:这个命令可在DOS下输入直接运行。

IF-ERRORLEVEL

用记事本建立一个文件XIAO.BAT,内容如下
@ECHO OFF
XCOPY C:\AUTOEXEC.BAT D:\
IF ERRORLEVEL = = 0 ECHO 成功拷贝文件
然后执行文件
C:\>XIAO.BAT
如果文件拷贝成功,屏幕就会显示:成功拷贝文件
IF ERRORLEVEL 是用来测试它的上一个DOS命令的返回值的,注意只是上一个命令的返回值,因此下面的批处理文件是错误的
@ECHO OFF
XCOPY C:\AUTOEXEC.BAT D:\
IF ERRORLEVEL = = 0 ECHO 成功拷贝文件
IF ERRORLEVEL = = 1 ECHO 未找到拷贝文件
IF ERRORLEVEL = = 2 ECHO 用户通过ctrl-c中止拷贝操作
IF ERRORLEVEL = = 3 ECHO 预置错误阻止文件拷贝操作
IF ERRORLEVEL = = 4 ECHO 拷贝过程中写盘错误
无论拷贝是否成功,后面的:
未找到拷贝文件
用户通过ctrl-c中止拷贝操作
预置错误阻止文件拷贝操作
拷贝过程中写盘错误
都将显示出来。
注意:这个命令是可以在DOS下直接输入的。
例如:
C:\>XCOPY \AUTOEXEC.BAT D:\
之后可以执行
C:\> IF ERRORLEVEL = = 0 ECHO 成功拷贝文件
如果成功,屏幕将显示:
成功拷贝文件

以下就是几个常用命令的返回值:
backup
出口状态 意义
0 备份成功
1 未找到备份文件
2 文件共享冲突阻止备份完成
3 用户用ctrl-c中止备份
4 由于致命的错误使备份操作中止
diskcomp
出口状态 意义
0 盘比较相同
1 盘比较不同
2 用户通过ctrl-c中止比较操作
3 由于致命的错误使比较操作中止
4 预置错误中止比较
diskcopy
出口状态 意义
0 盘拷贝操作成功
1 非致命盘读/写错
2 用户通过ctrl-c结束拷贝操作
3 因致命的处理错误使盘拷贝中止
4 预置错误阻止拷贝操作
format
出口状态 意义
0 格式化成功
3 用户通过ctrl-c中止格式化处理
4 因致命的处理错误使格式化中止
5 在提示“proceed with format(y/n)?”下用户键入n结束
xopy
出口状态 意义
0 成功拷贝文件
1 未找到拷贝文件
2 用户通过ctrl-c中止拷贝操作
4 预置错误阻止文件拷贝操作
5 拷贝过程中写盘错误

IF STRING = = STRING

首先用记事本建立一个名为XIAO.BAT的文件,文件内容如下:
@echo off
IF "%1" = = "A" FORMAT A:
接着执行
C:\>XIAO A
屏幕上就出现是否将A:盘格式化的内容。
这个语句的格式为
IF "参数" = = "字符串"  待执行的命令
参数如果等于指定的字符串,则条件成立,运行命令,否则运行下一句。
注意:要想在DOS下直接使用,只有这样
C:\> IF "A" = = "A" FORMAT A:
毫无意义。

GOTO

首先用记事本建立一个名为XIAO.BAT的文件,文件内容如下:
@ECHO OFF
IF EXIST C:\AUTOEXEC.BAT GOTO KB
: KB
COPY C:\AUTOEXEC.BAT D:\
: DONE
注意:
1. 标号前是冒号(:)
2. 标号的最后一行是: DONG
3. DOS支持最长为八位的标号,当无法区别两个标号时,将跳转至最近的一个标号。

FOR

首先用记事本建立一个名为XIAO.BAT的文件,文件内容如下:
@ECHO OFF
FOR %%C IN (*.BAT *.TXT *.SYS) DO TYPE %%C
接着执行
C:>XIAO.BAT
执行以后,屏幕上会将C:盘所有的以 *.BAT *.TXT *.SYS为扩展名的文件内容显示出来,当然不包括隐藏文件。
说明:字符%%C 表示FOR命令变量,FOR支持通配符
Nov 13
在介绍图象的压缩编码之前,先考虑一个问题:为什么要压缩?其实这个问题不用我回答,你也能想得到。因为图象信息的数据量实在是太惊人了。举一个例子就明白了,一张A4(210mm*297mm) 幅面的照片,若用中等分辨率(300dpi)的扫描仪按真彩扫描,其数据量为多少?让我们来计算一下:共有(300*210/25.4)*(300*297/25.4)个像素,每个像素占3个字节,其数据量为26M字节,其数据量之大可见一斑了。
如今在Internet上,传统基于字符界面的应用逐渐被能够浏览图象信息的WWW(World Wide Web)方式所取代。WWW尽管漂亮,但是也带来了一个问题:图象信息的数据量太大了,本来就已经非常紧张的网络带宽变得更加不堪重负,使得World Wide Web变成了World Wide Wait。
总之,大数据量的图象信息会给存储器的存储容量,通信干线信道的带宽,以及计算机的处理速度增加极大的压力。单纯靠增加存储器容量,提高信道带宽以及计算机的处理速度等方法来解决这个问题是不现实的,这时就要考虑压缩。压缩的理论基础是信息论。从信息论的角度来看,压缩就是去掉信息中的冗余,即保留不确定的信息,去掉确定的信息(可推知的),也就是用一种更接近信息本质的描述来代替原有冗余的描述。这个本质的东西就是信息量(即不确定因素)。
压缩可分为两大类,第一类压缩过程是可逆的,也就是说,从压缩后的图象能够完全恢复出原来的图象,信息没有任何丢失,称为无损压缩;第二类压缩过程是不可逆的,无法完全恢复出原图象,信息有一定的丢失,成为有损压缩。选择哪一类压缩,要折中考虑,尽管我们希望能够无损压缩,但是通常有损压缩的压缩比(即原图象占的字节数与压缩后图象占的字节数之比,压缩比越大,说明压缩效率越高)比无损压缩的高。
图象压缩一般是通过改变图象的表示方式来达到,因此压缩和编码是分不开的。图象压缩的主要应用是图象信息的传输和存储,可广泛地应用于广播电视,电视会议,计算机通讯,传真,多媒体系统,医学图象,卫星图象等领域。
压缩编码的方法有很多,主要分成以下4大类:1.像素编码;2.预测编码;3.变换编码;4.其它方法。
所谓像素编码是指,编码时对每个像素单独处理,不考虑像素之间的相关性。在像素编码中常用的几种方法有:1.脉冲编码调制(Pulse Code Modulation,PCM);2.熵编码(Entropy Coding);3.行程编码(Run Length Coding);4.位平面编码(Bit Plane Coding)。这里面,我们要介绍的是熵编码中的哈夫曼(Huffman)编码,行程编码(以读取.PCX文件为例)。
所谓预测编码是指,去掉相邻像素之间的相关性和冗余性,只对新的信息进行编码。举个简单的例子,因为像素的灰度是连续的,所以在一片区域中,相邻像素之间灰度值的差别可能很小。如果我们只记录第一个像素的灰度,其它像素的灰度都用它与前一个像素灰度之差来表示,就能起到压缩的目的。如248,2,1,0,1,3,实际上这6个像素的灰度是248,250,251,251,252,255。表示250需要8个比特,而表示2只需要两个比特,这样就实现了压缩。
常用的预测编码有Δ调制(Delta Modulation,简称DM);微分预测编码(Differential Pulse Code Modulation,DPCM),具体的细节,我们就不详述了。
所谓变换编码是指,将给定的图象变换到另一个数据域(如频域)上,使得大量的信息能用较少的数据来表示,从而达到压缩的目的。变换编码有很多,如1.离散傅立叶变换(Discrete Fourier Transform,DFT);2.离散余弦变换(Discrete Cosine Transform,DCT);3.离散哈达玛变换(Discrete Hadamard Transform,DHT)。
其它的编码方法也有很多,如混合编码(Hybird Coding),矢量量化(Vector Quantize,VQ),LZW算法。在这里,我们只介绍LZW算法的大体思想。
值得注意的是,近些年来出现了很多新的压缩编码方法,如使用人工神经元网络(Artificial Neural Network,ANN)的压缩编码算法;分形(Fractl);小波(Wavelet);基于对象(Object -Based)的压缩编码算法;基于模型(Model -Based)的压缩编码算法(应 用在MPEG4及未来的视频压缩编码标准中)。这些都超出了本讲座的范围。
本讲的最后,我们将以JPEG压缩编码标准为例,看看上面的几种编码方法在实际的压缩编码中是怎样应用的。

1. 哈夫曼(Huffman)编码
Huffman编码是一种常用的压缩编码方法,是Huffman于1952年为压缩文本文件建立的。它的基本原理是频繁使用的数据用较短的代码代替,较少使用的数据用较长的代码代替,每个数据的代码各不相同。这些代码都是二进制码,且码的长度是可变的。举个例子:假设一个文件中出现了8种符号S0,S1,S2,S3,S4,S5,S6,S7,那么每种符号要编码,至少需要3比特,假设编码成000,001,010,011,100,101,110,111(称做码字)。那么符号序列S0S1S7S0S1S6S2S2S3S4S5S0S0S1编码后变成000001111000001110010010011100101000000001,共用了42比特。我们发现S0,S1,S2这三个符号出现的频率比较大,其它符号出现的频率比较小,如果我们采用一种编码方案使得S0,S1,S2的码字短,其它符号的码字长,这样就能够减少占用的比特数。
例如,我们采用这样的编码方案:S0到S7的码字分别01,11,101,0000,0001,0010,0011,100,那么上述符号序列变成011110001110011101101000000010010010111,共用了39比特,尽管有些码字如S3,S4,S5,S6变长了(由3位变成4位),但使用频繁的几个码字如S0,S1变短了,所以实现了压缩。
上述的编码是如何得到的呢?随意乱写是不行的。编码必须保证不能出现一个码字和另一个的前几位相同的情况,比如说,如果S0的码字为01,S2的码字为011,那么当序列中出现011时,你不知道是S0的码字后面跟了个1,还是完整的一个S2的码字。我们给出的编码能够保证这一点。
下面给出具体的Huffman编码算法。
1.首先统计出每个符号出现的频率,上例S0到S7的出现频率分别为4/14,3/14,2/14,1/14,1/14,1/14,1/14,1/14。
2.从左到右把上述频率按从小到大的顺序排列。
3.每一次选出最小的两个值,作为二叉树的两个叶子节点,将和作为它们的根节点,这两个叶子节点不再参与比较,新的根节点参与比较。
4.重复3,直到最后得到和为1的根节点。
5.将形成的二叉树的左节点标0,右节点标1。把从最上面的根节点到最下面的叶子节点途中遇到的0,1序列串起来,就得到了各个符号的编码。
上面的例子用Huffman编码的过程如下图所示,其中圆圈中的数字是新节点产生的顺序。可见,我们上面给出的编码就是这么得到的。

图1. Huffman编码的示意图
产生霍夫曼编码需要对原始数据扫描两遍,第一遍扫描要精确地统计出原始数据中,每个值出现的频率,第二遍是建立霍夫曼树并进行编码,由于需要建立二叉树并遍历二叉树生成编码,因此数据压缩和还原速度都较慢,但简单有效,因而得到广泛的应用。

2.行程编码(Run Length Coding)
行程编码的原理也很简单:将一行中颜色值相同的相邻像素用一个计数值和该颜色值来代替。例如:aaabccccccddeee可以表示为3a1b6c2d3e。如果一幅图象是由很多块颜色相同的大面积区域组成,那么采用行程编码的压缩效率是惊人的。然而,该算法也导致了一个致命弱点,如果图象中每两个相邻点的颜色都不同,用这种算法不但不能压缩,反而数据量增加一倍。所以现在单纯采用行程编码的压缩算法用得并不多,PCX文件算是其中的一种.
PCX文件最早是PC Paintbrush软件所采用的一种文件格式,由于压缩比不高,现在用的并不是很多了。它也是由头信息,调色板,实际的图象数据三个部分组成。其中头信息的结构为:
typedef struct{
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
WORD xmin,ymin;
WORD xmax,ymax;
WORD hres;
WORD vres;
char palette[48];
char reserved;
char colour_planes;
WORD bytes_per_line;
WORD palette_type;
char filler[58];
} PCXHEAD;
其中值得注意的是以下几个数据:manufacturer为PCX文件的标识,必须为0x0a;xmin为最小的x坐标,xmax最大的x坐标,所以图象的宽度为xmax-xmin+1,同样图象的高度为ymax-yin+1;bytes_per_line为每个编码行所占的字节数,过一会儿详细介绍。
PCX的调色板在文件的最后。以256色PCX文件为例,倒数第769个字节为颜色数的标识,256时该字节必须为12,剩下的768(256*3)为调色板的RGB值。
为了讲起来方便,下面我们针对256色PCX文件,介绍一下它的解码过程。编码是解码的逆过程,有兴趣的读者可以试着自己来完成。
解码是以行为单位的,该行所占的字节数由bytes_per_line给定。为此,我们开一个大小为bytes_per_line的解码缓冲区。一开始,将缓冲区的所有内容清零。从文件中读出一个字节C,若C>0xc0,说明是行程(Run Length)信息,即C的低6位表示后面连续的字节个数(所以最多63个连续颜色相同的像素,若还有颜色相同的像素,将在下一个行程处理),文件的下一个字节就是实际的图象数据(即该颜色在调色板中的索引值);若C<0xc0,则表示C是实际的图象数据。如此反复,直到这bytes_per_line个字节处理完,这一行的解码完成。PCX就是有若干个这样的解码行组成。

实现256色PCX文件解码的源程序

3. LZW算法的大体思想
LZW是一种比较复杂的压缩算法,其压缩效率也比较高。我们在这里只介绍一下它的基本原理:LZW把每一个第一次出现的字符串用一个数值来编码,在还原程序中再将这个数值还成原来的字符串。例如:用数值0x100代替字符串"abccddeee",每当出现该字符串时,都用0x100代替,这样就起到了压缩的作用。
至于0x100与字符串的对应关系则是在压缩过程中动态生成的,而且这种对应关系隐含在压缩数据中,随着解压缩的进行,这张编码表会从压缩数据中逐步得到恢复,后面的压缩数据再根据前面数据产生的对应关系产生更多的对应关系,直到压缩文件结束为止。LZW是无损的。GIF文件采用了这种压缩算法。
要注意的是,LZW算法由Unisys公司在美国申请了专利,要使用它首先要获得该公司的认可。

4.JPEG压缩编码标准
JPEG是联合图象专家组(Joint Picture Expert Group)的英文缩写,是国际标准化组织(ISO)和CCITT联合制定的静态图象的压缩编码标准。和相同图象质量的其它常用文件格式(如GIF,TIFF,PCX)相比,JPEG是目前静态图象中压缩比最高的。我们给出具体的数据来对比一下。例图采用Windows95目录下的Clouds.bmp,原图大小为640*480,256色。用工具SEA(version1.3)将其分别转成24位色BMP,24位色JPEG,GIF(只能转成256色)压缩格式,24位色TIFF压缩格式,24位色TGA压缩格式,得到的文件大小(以字节为单位)分别为:921,654;17,707;177,152;923,044;768,136。可见JPEG比其它几种压缩比要高得多,而图象质量都差不多(JPEG处理的颜色只有真彩和灰度图)。 正是由于其高压缩比,使得JPEG被广泛地应用于多媒体和网络程序中,例如HTML语法中选用的图象格式之一就是JPEG(另一种是GIF),这是显然的,因为网络的带宽是非常宝贵的,选用一种高压缩比的文件格式是十分必要的。
JPEG有几种模式,其中最常用的是基于DCT变换的顺序型模式,又称为基本系统(Baseline),以下都是针对这种格式进行讨论。

JPEG的压缩原理
JPEG的压缩原理其实上面介绍的那些原理的综合,博采众家之长,这也正是JPEG有高压缩比的原因。其编码器的流程为

图3. 编码器流程
解码器基本上为上述过程的逆过程:

图4. 解码器流程

8*8的图象经过DCT变换后,其低频分量都集中在左上角,高频分量分布在右下角(DCT变换实际上是空间域的低通滤波器)。由于该低频分量包含了图象的主要信息(如亮度),而高频与之相比,就不那么重要了,所以我们可以忽略高频分量,从而达到压缩的目的。如何将高频分量去掉,这就要用到量化,它是产生信息损失的根源。这里的量化操作,就是将某一个值除以量化表中对应的值。由于量化表左上角的值较小,右上角的值较大,这样就起到了保持低频分量,抑制高频分量的目的。
JPEG使用的颜色是YUV格式。我们提到过,Y分量代表了亮度信息,UV分量代表了色差信息。相比而言,Y分量更重要一些。我们可以对Y采用细量化,对UV采用粗量化,可进一步提高压缩比。所以上面所说的量化表通常有两张,一张是针对Y的;一张是针对UV的。
上面讲了,经过DCT变换后,低频分量集中在左上角,其中F(0,0)(即第一行第一列元素)代表了直流(DC)系数,即8*8子块的平均值,要对它单独编码。由于两个相邻的8*8子块的DC系数相差很小,所以对它们采用差分编码DPCM,可以提高压缩比,也就是说对相邻的子块DC系数的差值进行编码。8*8的其它63个元素是交流(AC)系数,采用行程编码。这里出现一个问题:这63个系数应该按照怎么样的顺序排列? 为了保证低频分量先出现,高频分量后出现,以增加行程中连续"0"的个数,这63个元素采用了"之"字型(Zig-Zag)的排列方法,如下图所示:

图5. Zig-Zag
这63个AC系数行程编码的码字用两个字节表示,如下图

图6. 行程编码
上面,我们得到了DC码字和 AC行程码字。为了进一步提高压缩比,需要对其再进行熵编码,这里选用Huffman编码,分成两步:
(1) 熵编码的中间格式表示:
对于AC系数,有两个符号。符号1:行程和尺寸,即上面的(RunLength,Size)。(0,0)和(15,0)是两个比较特殊的情况。(0,0)表示块结束标志(EOB),(15,0)表示ZRL,当行程长度超过15时,用增加ZRL的个数来解决,所以最多有三个ZRL(3*16+15=63)。符号2为幅度值(Amplitude)。
对于DC系数,也有两个符号。符号1:尺寸(Size);符号2为幅度值(Amplitude)。
(2) 熵编码:
对于AC系数,符号1和符号2分别进行编码。零行程长度超过15个时,有一个符(15,0),块结束时只有一个符号(0,0)。 对符号1进行Hufffman编码(亮度,色差的Huffman码表不同)。对符号2:进行变长整数VLI编码,举例来说:Size=6时,Amplitude的范围是-63~-32,以及32~63,对绝对值相同,符号相反的码字之间为反码关系。所以AC系数为32的码字为100000,33的码字为100001,-32的码字为011111,-33的码字为011110。符号2的码字紧接于符号1的码字之后。
对于DC系数,Y和UV的Huffman码表也不同。掉了这么半天的书包,你可能已经晕了,呵呵。举个例子来说明上述过程就容易明白了。
下面为8*8的亮度(Y)图象子块经过量化后的系数。
15 0 -1 0 0 0 0 0
-2 -1 0 0 0 0 0 0
-1 -1 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
可见量化后只有左上角的几个点(低频分量)不为零,这样采用行程编码就很有效。
第一步,熵编码的中间格式表示:先看DC系数。假设前一个8*8子块DC系数的量化值为12,则本块DC系数与它的差为3,根据下表
Size Amplitude
0 0
1 -1,1
2 -3,-2,2,3
3 -7~-4,4~7
4 -15~-8,8~15
5 -31~-16,16~31
6 -63~-32,32~63
7 -127~-64,64~127
8 -255~-128,128~255
9 -511~-256,256~511
10 -1023~512,512~1023
11 -2047~-1024,1024~2047
查表得Size=2,Amplitude=3,所以DC中间格式为(2)(3).AC系数接着被编码,经过Zig-Zag扫描后,遇到的第一个非零系数为-2,其中遇到零的个数为1(即RunLength),根据下面这张AC系数表
Size Amplitude
1 -1,1
2 -3,-2,2,3
3 -7~-4,4~7
4 -15~-8,8~15
5 -31~-16,16~31
6 -63~-32,32~63
7 -127~-64,64~127
8 -255~-128,128~255
9 -511~-256,256~511
10 -1023~512,512~1023
查表得Size=2。所以RunLength=1,Size=2,Amplitude=3,所以AC中间格式为(1,2)(-2)。
其余的点类似,可以求得这个8*8子块熵编码的中间格式为
(DC)(2)(3),(1,2)(-2),(0,1)(-1),(0,1)(-1),(0,1)(-1),(2,1)(-1),(EOB)(0,0)
第二步:熵编码
对于(2)(3):2查DC亮度Huffman表得到11,3经过VLI编码为011
对于(1,2)(-2):(1,2)查AC亮度Huffman表得到11011,-2是2的反码,为01
对于(0,1)(-1):(0,1)查AC亮度Huffman表得到00,-1是1的反码,为0
……
最后这一8*8子块亮度信息压缩后的数据流为11011,1101101,000,000,000,111000,1010。总共31比特,其压缩比是64*8/31=16.5,大约每个像素用半个比特。
可以想见,压缩比和图象质量是呈反比的,以下是压缩效率与图象质量之间的大致关系,可以根据你的需要,选择合适 的压缩比。
压缩效率(单位:bits/pixel) 图象质量
0.25~0.50中~好,可满足某些应用
0.50~0.75好~很好,满足多数应用
0.75~1.5 极好,满足大多数应用
1.5~2.0与原始图象几乎一样

以上我们介绍了JPEG压缩的原理,其中DC系数使用了预测编码DPCM,AC系数使用了变换编码DCT,二者都使用了熵编码Huffman,可见几乎所有传统的压缩方法在这里都用到了。这几种方法的结合正是产生JPEG高压缩比的原因。顺便说一下,该标准是JPEG小组从很多种不同中方案中比较测试得到的,并非空穴来风。
上面介绍了JPEG压缩的基本原理,下面介绍一下JPEG的文件格式。

JPEG的文件格式
JPEG文件大体上可以分成以下两个部分:标记码(Tag)加压缩数据。先介绍标记码部分。
标记码部分给出了JPEG图象的所有信息(有点类似于BMP中的头信息,但要复杂的多),如图象的宽,高,Huffman表,量化表等等。标记码有很多,但绝大多数的JPEG文件只包含几种。标记码的结构为:
SOI
DQT
DRI
SOF0
DHT
SOS
…
EOI
标记码由两个字节组成,高字节为0XFF,每个标记码之前可以填上个数不限的填充字节0XFF。
下面介绍一些常用的标记码的结构及其含义。
SOI(Start of Image)
标记结构 字节数
0XFF1
0XD81
可作为JPEG格式的判据(JFIF还需要APP0的配合)
APP0(Application)
标记结构 字节数 意义
0XFF1
0XE01
Lp2 APP0标记码长度,不包括前两个字节0XFF,0XE0
Identifier5JFIF识别码 0X4A,0X46,0X49,0X46,0X00
Version 2JFIF版本号 可为0X0101或者0X0102
Units 1单位,等于零时表示未指定,为1表示英寸,为2表示厘米
Xdensity2水平分辨率
Ydensity2竖直分辨率
Xthumbnail1水平点数
Ythumbnail1竖直点数
RGB03RGB的值
RGB13RGB的值

RGBn 3 RGB的值,n=Xthumbnail*Ythumbnail
APP0是JPEG保留给Application所使用的标记码,而JFIF将文件的相关信息定义在此标记中。

DQT(Define Quantization Table)
标记结构 字节数 意义
0XFF1
0XDB1
Lq2DQT标记码长度,不包括前两个字节0XFF,0XDB
(Pq,Tq)1 高四位Pq为量化表的数据精确度,Pq=0时,Q0~Qn的值为8位,Pq=1时,Qt的值为16位,Tq表示量化表的编号,为0~3。在基本系统中,Pq=0,Tq=0~1,也就是说最多有两个量化表。
Q01或2 量化表的值,Pq=0时,为一个字节,Pq=1时,为两个字节
Q11或2 量化表的值,Pq=0时,为一个字节,Pq=1时,为两个字节

Qn1或2 量化表的值,Pq=0时,为一个字节,Pq=1时,为两个字节n的值为0~63,表示量化表中64个值(之字形排列)

DRI(Define Restart Interval)
此标记需要用到最小编码单元(MCU,Minimum Coding Unit)的概念。前面提到,Y分量数据重要,UV分量的数据相对不重要,所以可以只取UV的一部分,以增加压缩比。目前支持JPEG格式的软件通常提供两种取样方式YUV411和YUV422,其含义是YUV三个分量的数据取样比例。举例来说,如果Y取四个数据单元,即水平取样因子Hy乘以垂直取样因子Vy的值为4,而U和V各取一个数据单元,即Hu*Vu=1,Hv*Vv=1。那么这种部分取样就称为YUV411。如下图所示:

图7. YUV411的示意图
易知YUV411有50%的压缩比(原来有12个数据单元,现在有6个数据单元),YUV422
有33%的压缩比(原来有12个数据单元,现在有8个数据单元)。 那么你可能会想,YUV911,YUV1611压缩比不是更高嘛?但是要考虑到图象质量的因素。所以JPEG标准规定了最小编码单元MCU,要求Hy*Vy+Hu*Vu+Hv*Vv≤10。
MCU中块的排列方式与H,V的值有密切关系。如以下几幅图所示:

图8. YUV111的排列顺序

图9. YUV211的排列顺序

图10. YUV411的排列顺序
标记结构 字节数 意义
0XFF1
0XDD1
Lr2DRI标记码长度,不包括前两个字节0XFF,0XDD
Ri2重入间隔的MCU个数,Ri必须是一MCU行中MCU个数的整数,最后一个零头不一定刚好是Ri个MCU。每个重入间隔各自独立编码。

SOF(Start of Frame) 在基本系统中,只处理SOF0
标记结构 字节数 意义
0XFF1
0XC01
Lf2SOF标记码长度,不包括前两个字节0XFF,0XC0
P1 基本系统中,为0X08
Y2 图象高度
X2 图象宽度
Nf1Frame中的成分个数,一般为1或3,1代表灰度图,3代表真彩图
C11成分编号1
(H1,V1)1 第一个水平和垂直采样因子
Tq11该量化表编号
C21成分编号2
(H2,V2)1第二个水平和垂直采样因子
Tq21该量化表编号

Cn1 成分编号n
(Hn,Vn)1第n个水平和垂直采样因子
Tqn1该量化表编号

DHT(Define Huffman Table)
标记结构 字节数 意义
0XFF1
0XC41
Lh2DHT标记码长度,不包括前两个字节0XFF,0XC4
(Tc,Th)1
L11
L21

L161
V11
V21

Vt1
Tc为高4位,Th为低4位。在基本系统中,Tc为0或1,为0时,指DC所用的Huffman表,为1时,指AC所用的Huffman表。Th表示Huffman表的编号,在基本系统中,其值为0或1。
所以,在基本系统中,最多有4个Huffman表,如下所示:
Tc Th Huffman表编号(2*Tc+Th)
0 0 0
0 1 1
1 0 2
1 1 3
Ln表示每个n比特的Huffman码字的个数,n=1~16
Vt表示每个Huffman码字所对应的值,也就是我们前面所讲的符号1,对DC来说该值为(Size),对AC来说该值为(RunLength,Size)。 t=L1+L2+…L16

SOS(Start of Scan)
标记结构 字节数 意义
0XFF1
0XDA1
Ls2 DHT标记码长度,不包括前两个字节0XFF,0XDA
Ns1
Cs11
(Td1,Ta1)1
Cs21
(Td2,Ta2)1

CsNs1
(TdNs,TaNs) 1
Ss1
Se1
(Ah,Al)1
Ns为Scan中成分的个数,在基本系统中,Ns=Nf(Frame中成分个数)。CSNs为在Scan中成分的编号。TdNs为高4位,TaNs为低4位,分别表示DC和AC编码表的编号。在基本系统中Ss=0,Se=63,Ah=0,Al=0。

EOI(End of Image) 结束标志
标记结构 字节数 意义
0XFF1
0XD91

JPEG基本系统解码器的程序流程图。

图11. JPEG基本系统解码器的程序流程图
由于没有用到什么优化算法,该解码器的速度并不高,在用VC的性能评测工具Profile评测该程序时我发现最耗时的地方是反离散余弦变换(IDCT)那里,其实这是显然的,浮点数的指令条数要比整数的多得多,因此采用一种快速的IDCT算法能很大的提高性能,我这里采用是目前被认为比较好的一种快速IDCT算法,其主要思想是把二维IDCT分解成行和列两个一维IDCT。
Nov 11

Fvwm is a window manager for X11. It is designed to minimize memory
consumption, provide a 3D look to window frames, and a virtual desktop.


--- The FVWM(F? Virtual Window Manager) manual


    在看这个文档之前你最好对 Xwindow 的工作机制有一定了解。知道 X server 跟 WM
     有什么关系。我以后或许会增加这些内容,但是现在暂时还没有时间写这些。

  1. FVWM 是什么样子?
     

    这个问题是永远不会有答案的。问这个问题就像在问:“Xwindow
     是什么样子的?”也许勉强可以接受的回答是:“你想让它是什么样子,它就会成为什么样子。”


     

    FVWM 是一个完全可定制的窗口管理器。这是FVWM不同于很多WM的一个特点,它的一切行为方式都是由一个配置文件:
     .fvwm2rc 决定的。没有了这个配置文件,FVWM 就成了一个废物:
     鼠标和键盘几乎不起任何作用,没有菜单,没有窗口边框,没有按钮,甚至你根本不知道它其实正在运行!


     

    但是一旦有了配置文件,FVWM就会变得威力无比,简单的配置文件可以实现基本的功能,复杂的配置文件甚至可以模拟很多其它WM甚至 Windows
     XP。下面就是一个模拟 Windows XP 的例子,点击可以放大。很漂亮吧?什么时候 Windows XP 也能这么漂亮就好了 :)


     


     

    下面是一个模拟 CDE 的 dtwm 的例子:


     


     

    以后如果有人告诉你:“FVWM是那个样子。”你就可以对他说:“FVWM不一定是那个样子。” :)


     

    你可以在http://www.fvwm.org/screenshots/看到很多漂亮的配置。


     
  2. 配置文件和它的位置
     

    配置文件叫做 ~/.fvwm/.fvwm2rc, 在你的用户目录下。


     

    配置文件有点像一个脚本语言。不要怕,这种脚本语言比起 Perl, awk 简单多了。你不需要学会编程。


     

    写配置文件,一个很好的出发点就是随 FVWM 源码发行的 system.fvwm2rc 文件。它的位置现在在源码包的
     sample.fvwmrc/system.fvwm2rc。你也可以在这里下载一份 2.5.4 的system.fvwm2rc.
     把它拷贝到你的 ~/.fvwm/ 目录下面, 改名为 .fvwm2rc. 作为我们的起始点。


     

    注意sample.fvwmrc/ 这个目录下还有system.fvwm2rc-sample-95这样的配置文件,它们可以模拟 Windows 95
     的操作方式,但是这个配置文件太大了,不适合用来修改成为自己的配置文件,你有兴趣可以自己看看,然后把里面某些你觉得很cool的东西贴到你的配置文件里。


     

    现在我们就来分析一下这个简单的配置文件里到底在说些什么。


     
  3. 什么是FVWM命令
     

    一个配置文件里基本上是一些命令,与其它WM不同的是,FVWM并不区分样式命令和动作命令,你可以几乎在任何情况下使用任何命令。比如命令:

    Mouse 1 A CSM Style gvim TitleAtBottom

     

    让你在任何时候按住 Ctrl-Shift-Alt 再点击鼠标左键(编号1),名叫gvim的窗口的标题栏就会跑到下面去。是不是很好玩?呵呵。这里
     "Style" 是一个样式命令。

    Mouse 2 A CSM All (rxvt) MoveToDesk 0

     

    按住 Ctrl-Shift-Alt 再点击鼠标左键中键(编号2),所有的 rxvt 都会被移动到当前的桌面. 这里的 "All"
     是一个可以附加条件和操作的条件动作命令。


     
  4. 怎样实验新的FVWM命令
     

    实验一个命令的作用不需要重新启动FVWM,你可以先在 .fvwm2rc 里这样定义:

    Key F3 A A Module FvwmConsole 

     

    然后启动fvwm, 这样你在任何时候按下 <F3> 键,就会启动一个叫做 FvwmConsole
     的模块,你可以在里面输入Fvwm命令,回车它们就会执行,并且立即生效。这是直接与FVWM对话的方法。当然如果你想得到下面这么漂亮的 FvwmConsole,
     还需要对 xterm/rxvt 的参数作一些设定。其实我的定义是:

    Key F3 A A Module FvwmConsole -terminal rxvt -geometry 45x5-0+0 \
    -bg gold -fg midnightblue \
    -fn "-adobe-courier-medium-r-*-*-14-*-*-*-*-*-*-*"

     


     
  5. DeskTopSize 2x2 以及其它常用的命令

     

    FVWM
     可以有很多个虚拟桌面(desk)(几乎无穷多!),每个虚拟桌面可以被分成很多个页("page")。这些page相当于把你的屏幕扩大了很多倍。这一行就是设定每个desk包含多少page.
     


     

    DeskTopSize 这类语句指定了整个FVWM的某种行为方式,类似的语句还有很多。比如:


     
    • Read file. 插入另外一个文件file的内容。如果你会C语言,你就知道这个语句相当于 #include .
         当你的配置文件在某一方面有很长内容时,比如我的配置文件里有大量stroke,你就可以把这些都写到另一个文件里,这样使主配置文件容易修改。

         
    • Exec app. 启动一个shell,并且在里面执行"app"命令。这时用菜单和按钮来启动程序时经常用到的命令。
         

      如果你要启动一个X程序最好同时使用 exec, 比如

      Exec exec rxvt

         

      这样shell会执行"exec rxvt", 用rxvt替代自己的正文段,这样才不会出现很多shell在那里等待X程序返回。


         
    • Module FvwmXxx. 启动一个叫做 FvwmXxx 的模块。一个模块是一个程序,它直接通过管道与Fvwm通信,所以必须从Fvwm
         fork() 出来,而不能从一个 xterm 独立启动。模块可以无限制的扩展Fvwm的功能,只要 Xlib 允许。
         
    • ImagePath path. 指定一个路径,在配置文件里要用到的图标等文件就会到这个路径里去寻找。比如:
      ImagePath +:/usr/share/icons:/usr/share/pixmaps:
      $HOME/.fvwm/icons
      加号是表示以前定义过的那个 ImagePath. FVWM 可以使用 .xbm, .xpm 和 .png 格式的图标。
         
    • Move, Raise, Lower, Resize, ... 这些都是常用的操纵窗口的命令。
         
    • Close, Delete, Destroy, Iconify, Maximize, WindowShade.
         关闭窗口,图标化窗口,最大化窗口,shade 化窗口. 你会发现Xwindow关闭窗口的方式有很多种,其中 Close
         是最文明的一种,这会发给窗口一个消息让它收拾干净然后退出。Destroy 是立即杀死这个窗口,跟 xkill
         的功能一样。Delete介于两者之间,先礼后兵,如果窗口不知道怎么收拾干净,那么就强行杀死它。
         
    • OpaqueMoveSize x. 如果一个窗口移动时显示内容,那么它必需占屏幕面积的 x%.
         
    • MoveToDesk, MoveToPage. 可以把任何窗口移动到指定的桌面和页面。
         
    • SnapAttraction. 设定在什么距离以内,满足什么条件的窗口就被吸附在一起。biaji~~~~~
         
    • WarpToWindow x[p] y[p]. 让鼠标移动到窗口范围以内。x,y是在窗口内的坐标,用百分比表示。后面如果有后缀"p",
         就用像素来表示。
         
    • IgnoreModifiers. 你可以忽略某些键盘控制键。这将影响到你的鼠标和键盘热键定义。详细情况见鼠标和键盘一节。

         
    • DesktopName desk name. 定义第desk号桌面的名字叫 name.
         
    • Scroll. 移动你在桌面上的 viewport, 这样你可以把桌面当成一个整体来浏览。看到很大的范围。
         
    • Nop. 不操作,在有些时候需要用它来占位,下面我们会遇到这样的例子。
         
    • PipeRead. 从一个外部命令得到输入。这可以用来根据你的系统构造许多非常高级的控制方式。其中一种叫做“菜单式文件管理器”。我们在菜单一节会遇到这个用法。

         
    • SetEnv. 设置FVWM的环境变量。

     

    就举这些吧……我只是举出了我有时会用到的,其实还有很多很多,你看看 FVWM 的manpage就知道了。


     
  6. 窗口上下文
     

    Move, Close, WarpToWindow
     ...这些命令如何知道作用于那个窗口呢?如果你因为点击了窗口上的按钮,边框,……而激发了这些命令,那么这些命令就会作用于这个窗口。或者你也可以用条件选择命令确定一个或者一批窗口进行操作,见条件命令。否则,这些命令不知道应该作用于哪个窗口,比如你在
     FvwmConsole 里键入 "Close", Close
     命令就没有窗口上下文,它缺省会出现一个“+”状的选择器让你选择一个窗口。如果你不希望命令在没有窗口上下文的时候自动让你选择一个窗口,那么你可以在命令前面加上
     "Silent".


     
  7. 鼠标和键盘
     

    FVWM几乎可以以无穷的方式组合,来进行鼠标和键盘的操作。你还可以加入窗口上下文来进行更方便的动作。


     

    键盘操作的定义:

    Key Keyname Context Modifiers Function

     

    它表示:在名叫 Keyname 的键在 Context 上下文按下时,如果控制键 Modifiers 组合按下,那么执行 Function.
     键盘操作后面的部分跟鼠标一样的含义,我们下面只用鼠标操作来一起说明这些命令的用途。


     

    鼠标操作的定义:

    Mouse Button Context Modifiers Function

     

    它表示:在鼠标编号为 Button 的键在 Context 上下文按下时,如果键盘控制键 Modifiers 组合按下,那么执行 Function.
     


     

    鼠标键编号的方法是:1 左键,2 中键,3 右键。如果你的鼠标有轮子,那么一般4表示往上滚动,5表示往下滚动。


     

    Context是鼠标按下的位置,它可以是:


     
    • R(Root Window) 根窗口
         
    • n (n 是0...9 之间的一个数)。第 n 号窗口按钮。按钮是这样编号的:
      1 3 5 7 9     0 8 6
         4 2
      左边是奇数右边是偶数, 外面的大中间的小。
         
    • T(Title)标题栏
         
    • S(Sidebar)也就是边框. 也可以用 '[', ']', '-' , '_' 分别表示左,右,上,下的边框。
         
    • F(Frame)就是用来resize的那四个角落. 也可以用 '<', '^', '>' and 'v'
         分别表示左上,右上,右下,左下的角落。
         
    • W(Working Area) 应用程序窗口工作区域
         
    • I(Icon window) 图标化的窗口。

     

    这些上下文可以组合。比如 "FST" 表示在frame, sidebar, 或者 title.


     

    Modifiers 是鼠标操作时同时的键盘控制键。M 表示 "Meta",在PC上就是Alt,S: shift, C: ctrl. 还有 A:
     any, N: none. 也可以组合,比如"MS" 表示同时按下Alt-Shift.


     

    Function 就是任意的FVWM操作了,可以是一个直接的命令,也可以是一个 FVWM 函数。


     

    现在我们分析一下下面这个定义:

    Mouse 3 W       SC      CloseOrNot
    这个定义是说,在窗口上点击鼠标右键,并且先按下 Shift-Ctrl,那么调用 CloseOrNot
     这个FVWM函数。这个函数会作用与当前鼠标所在的上下文,也就是一个窗口。函数是这样定义的:
     
  8. 函数
    DestroyFunc CloseOrNot
    AddToFunc CloseOrNot
    + C Silent Close
    + M Nop

     

    你可以把一系列的操作有条件的加入到一个叫做“函数”的结构里,以后这个函数就可以像命令一样被使用了。


     

    AddToFunc 把动作附加到函数,
     如果函数不存在就先创建这个函数。除了第一行,后面的行都以一个"+"号开头,这说明以下是上一个命令(AddToFunc)的继续。DestroyFunc
     是为了消除以前有可能定义过的函数体。这个函数 CloseOrNot 表示:


     
    • 如果是一个鼠标点击(C), 那么关闭这个窗口(Close),
         但是如果现在不是在窗口上下文,也就是说,函数调用的时候没有一个确定的目标,那么不进行操作,而不是出现一个"+"字瞄准器让用户选择窗口。 这就是
         "Silent" 的含义。
         
    • 如果鼠标点下去之后移动了,也就是“拖动”(M),那么不进行操作。

     
  9. 启动函数和退出函数
     

    在 FVWM 启动和重新启动时都会调用 StartFunction, 而且在首次启动时会调用 InitFunction, 在重新启动时会调用
     RestartFunction, InitFunction 和 RestartFunction 都是在 StartFunction
     之后调用。每次重起和完全退出时都要执行 ExitFunction.


     

    如果你有什么程序需要在FVWM启动时启动,那么就把它加到合适的函数里面去。比如,我的配置文件有这些内容:

    DestroyFunc StartFunction
    AddToFunc StartFunction        
    + I Module FvwmButtons MainPanel
    + I Module FvwmAuto 500 Raise Nop
    + I Module FvwmAnimate
    + I Module FvwmTaskBar
    + I Exec exec xdaliclock
    + I Exec exec xloadimage -onroot -fullscreen ~/pic/cat_20.jpg
    + I Exec exec xsim

    DestroyFunc InitFunction
    AddToFunc InitFunction    
    + I Exec exec xscreensaver -no-splash

    DestroyFunc ExitFunction
    AddToFunc ExitFunction
    + I All (xdaliclock) Close
    + I All (xscreensaver) Close
    + I All (xsim) Close

     

    可见,我在第一次启动时会启动 xscreensaver 屏幕保护程序。-no-splash 是 xscreensaver
     的参数。在每次重新启动和第一次启动时都要运行 FvwmButtons, FvwmAuto, FvwmAnimate, FvwmTaskBar 几个模块和
     xdaliclock,一种 morph 数字的时钟,然后用 xloadimage 放一张漂亮的图片作为桌面背景,最后启动 xsim 中文输入法。


     

    退出和重起时,我特意关闭了那几个启动时打开的程序,因为如果不关闭他们,像 xwin32, Exceed 这样的 Windows X server 不会
     Reset.


     

    每个命令前的 "I" 表示 Imediately, 立即执行,联想上面提到的 "C" 和 "M", 这个操作不等待任何鼠标动作。


     
  10. 窗口样式
     

    Style 语句用于设定窗口的样式。你可以随心所欲的让不同的窗口有不同的样式。语法为:

    Style stylename options

     

    其中 stylename
     是你的窗口的名字,窗口的class名字,或者窗口的resource名字。如果你不知道这些 X window
     的术语,那现在就姑且当作窗口的名字好了,以后多看看 Xlib 的说明书你就会明白这些东西。窗口的名字有可能不同于程序的名字,你不知道它叫什么名字可以用
     xwininfo 程序或者 FvwmIdent 模块来查询。再次说明,FvwmIdent 是模块,不能从 xterm 的命令行运行。


     

    stylename 里可以有 "*" 作为通配符。比如你可以说

    Style *term TitleAtLeft
    让所有以 "term" 结尾的那些窗口的标题拦都在左边。比如
     "xterm", "cxterm", "qterm", ... 都会采用这种样式。
     

    options 是你想让满足条件的窗口以什么样的方式存在。options
     的种类非常之多。比如:BorderWidth, HandleWidth, FocusFollowsMouse, TileCascadePlacement,
     ... 它们有的需要参数,比如 BorderWidth 7, 指定边框宽度为7个像素。有些不需要参数,比如 FocusFollowsMouse/
     SloppyFocus/ NeverFocus/ ClickToFocus 指明了几种互相排斥的键盘聚焦方式。 先举几个例子,这些都是
     system.fvwm2rc 里的内容:

    Style *           FocusFollowsMouse
    Style *           TileCascadePlacement
    Style "Fvwm*"       NoTitle,  Sticky, WindowListSkip
    Style "Fvwm*"       BorderWidth 2, CirculateSkipIcon, CirculateSkip
    Style "FvwmPager"   StaysOnTop
    Style "FvwmBanner"  StaysOnTop
    Style "FvwmButtons" Icon toolbox.xpm, ClickToFocus

     

    开头的两行说明所有窗口,都是鼠标移进去的时候得到键盘聚焦,鼠标移出来就失去聚焦(FocusFollowsMouse),窗口出现的时候,先试图找一个可以放下它而不挡住其它窗口的地方,如果不行再采用层叠放置的方式(TileCascadePlacement)。
     


     

    下面是说明所有名字以 "Fvwm" 开头的窗口(在这里一般都是 FVWM
     内部的模块),它们都没有标题栏(NoTitle),而且是sticky,也就是说即使桌面切换,它们也一直显示在屏幕上,边框宽度为 2,
     CirculateSkip 说明当FVWM要求轮询窗口进行批量操作时,这些窗口不被计算在内。第3,4行说明 FvwmPager, FvwmBanner
     这两个模块一直显示在最上面。最后一行说明 FvwmButtons 模块使用 toolbox.xpm
     的图标,需要鼠标点击才能得到键盘聚焦(ClickToFocus)。


     

    总的说来,options指出了控制窗口的基本样式和政策,而不包括窗口各个部件具体的样式,它包括以下几个方面内容:


     
    • 窗口聚焦方式。是跟随鼠标(FocusFollowsMouse),还是需要点击才聚焦(ClickToFocus)...
         
    • 窗口标题栏。是否给窗口加上标题拦?如果加上,是放在左边,上边,还是下边?注意这里也不是设定具体标题样式的地方,参看 TitleStyle.
         
    • 窗口应该显示哪些按钮。FVWM可以为每个窗口设定最多10个按钮,但是你通常用不到10个,这样你可以设定对于某一个程序那些按钮应该出现。注意这里也不是设定按钮样式的地方,参看
         ButtonStyle.
         
    • 窗口边框样式。边框宽度,handle(就是边框角上那个用来resize的东东)的宽度,边框被鼠标按住的时候是否陷下去?...
         
    • 窗口图标。用那个图标作为窗口iconify时候的图标?
         
    • 窗口最大化,移动,改变大小操作时的样式。是显示窗口内容还是只显示一个“橡皮框”?还是让尺寸小于某个值的窗口才在拖动时显示内容?...
         
    • 窗口放置策略。窗口出现的时候,是层叠放置,最小遮挡放置,还是……?
         
    • 是否允许程序自己放置自己?这是一个政策问题,有些窗口程序启动时会自己选择一个位置出现,但是你可能会发现你不喜欢它那样做,你可以设定NoPPosition,
         不允许那个程序自作聪明。
         
    • 对瞬时窗口(transient window)的策略。transient window
         是指类似弹出菜单,对话框之类的窗口。当它们出现的时候,你是否想给它们也加上标准的边框?
         
    • 高级特性。还有很多很多选项比如是否允许窗口 backing store,这些如果你还不理解现在暂时不用管它。

     

    以上每项都包含许许多多可以设定的东西。具体还是请参考 fvwm 的manpage。


     
  11. 菜单

     

    一个窗口管理器怎么能没有菜单?FVWM的菜单是可以随意自己定义的,它在任何时候出现在你想让它出现的任何地方。一个菜单首先有一个定义,然后有一个激发这个菜单的条件,菜单的样式也可以随意定制。如果使用
     PipeRead 命令和一些 shell 命令组合,你就可以用菜单的方式遍历你的文件目录树,成为一个“菜单式file manager”。


     
    • 菜单的定义
         

      菜单是由AddToMenu命令定义的,比如这样一个菜单


         


         

      是这样定义的

      DestroyMenu RootMenu
      AddToMenu RootMenu "Root Menu" Title
      + "&xterm%mini.display.xpm%" Exec exec xterm
      + "&Rxvt%mini.monitor.xpm%" Exec exec rxvt
      + "&Big Rxvt" Exec exec rxvt -geometry  78x43
      + "" Nop
      +                       "&Programs"      Popup ProgramsMenu
      +                       "&Utilities"     Popup Utilities
      + "" Nop
      +                       "Re&fresh Screen"   Refresh
      +                       "Re&capture Screen" Recapture
      + "" Nop
      +                       "&Lock"         Exec exec xscreensaver-command -lock
      + "&Exit Fvwm%mini.exit.xpm%" Popup Quit-Verify

         

      除了第一行,后面的行都以一个+号开头,这说明以下是上一个命令的继续。这样我们定义了一个菜单,它的名字叫 "RootMenu",
         它有一个标题叫"Root Menu", 里面有一些程序。当我们选中 "XTerm" 时,会使用FVWM 的 Exec
         命令启动一个shell,这个shell马上会执行"exec xterm", 也就是启动一个 xterm。空字串"" 表示在菜单里画一条分隔线。Popup
         可以弹出子菜单,子菜单也是用同样的方法定义的。"&"后面的那个字母会变成键盘的热键而被加上下划线,"%"括起来的是图标文件的名字,你需要设置
         ImagePath 指向图标文件所在的目录。你还可以在菜单里加入侧面图标,等等等等。


         
    • 菜单的消灭
         

      随后的AddToMenu命令会把内容附加到菜单的末尾。所以如果你想重新定义一个菜单,就需要先把它销毁掉。用

      DestroyMenu RootMenu
      就可以把刚才那个 "RootMenu" 菜单消灭掉。
         
    • 菜单的激活
         

      光是定义了一个菜单你是不能马上使用它的。这个菜单在什么情况下出现?这个问题是需要你自己来决定,这也是显示FVWM的完全可定制性的地方。比如,我们可以这样定义一个激活菜单的方式:
         

      Mouse 1 R       A       Menu RootMenu Nop

         

      这句话的意思是:“当鼠标(Mouse)左键(1)在根窗口(R)上点击,同时有任何控制键(A)按下,这个时候显示叫做 RootMenu 的菜单。”
         


         

      但是有时候我们不容易在屏幕上找到一个可以看到根窗口的地方来点击鼠标。我们可以再加一个定义:

      Mouse 3 A       MC      Menu RootMenu Nop

         

      这样,当右键(3) 在任何地方(A)点击, 同时有Alt(M)和Ctrl(C)按下,那么弹出名叫 "RootMenu" 的菜单。


         

      上面的 "Nop" 表示的是鼠标在菜单上进行双击时的操作。我定义为不操作。另外 Menu 还可以随意定义菜单出现的位置,详细请看 fvwm
         manpage。


         
    • 菜单的样式
         

      菜单的样式是由 MenuStyle 定义的:

      MenuStyle * MWM
      MenuStyle * PopupDelayed, PopupDelay 160, Animation, TitleWarp
      MenuStyle * Foreground gold, Background gray40
      MenuStyle * ActiveFore White
      MenuStyle * Font  -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*
      MenuStyle * MenuFace VGradient 64 darkgray MidnightBlue

         

      这样我规定:所有的菜单,他们使用 mwm 的行为方式,弹出子菜单延时 160
         ms,子菜单弹出时如果靠近屏幕边沿放不下,那么菜单整体移动使得子菜单刚好能弹出,前景色gold,背景色 gray40,
         活动的项目(就是鼠标正在它上方的时候)前景色变为白色,菜单使用字体 -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*,
         背景是垂直的梯度颜色,一共64阶,从 darkgray 变化到 MidnightBlue.


         
    • 动态菜单定义
         

      前面我们说过了,可以用 PipeRead 来构造一个动态菜单。现在举一个简单的例子:

      AddToMenu HomeDirMenu
      PipeRead 'for i in $HOME/prog/*.c; \
      do echo "+ $i Exec xterm -e vi $i"; done'

         

      当你激发这个菜单 HomeDirMenu,
         就会出现你主目录/prog下的所有C程序文件的列表,当你点击其中一个就会启动vi来编辑这个C程序。是不是很方便呢?你想一想,可以用怎样无穷无尽的方式来构造一个菜单呢?
         


     
  12. 按钮
     

    窗口的标题栏上都有一些按钮。那不是窗口程序自己的,而是WM给它们加上的。


     

    FVWM 可以给窗口加上最多10个按钮,它们不光可以实现基本的最大化,最小化,关闭,等功能。FVWM的灵活性允许你赋予按钮几乎任意的功能!


     
    • 按钮编号
         

      按钮是这样编号的:


         

      1  3  5  7  9         
                       0  8  6
          4  2
      左边是奇数右边是偶数,
         外面的大中间的小。


         
    • 按钮功能定义
         

      下面看看按钮的功能是怎么定义的,在鼠标和键盘一节我们已经知道怎么定义鼠标了,按钮的功能只不过是把鼠标与按钮号码组合在一起。
         


         

      比如我的窗口上一般有三个按钮, 都在右上角,注意它们的编号:


         

           6 4 2


         


         

      他们的功能是这样定义的:

      Mouse 1 4       A       Iconify
      Mouse 1 6       A       Close
      Mouse 3 2       A       Maximize-Func2
      其中 Maximize-Func2 是用了 system.fvwm2rc 里一个函数:
      DestroyFunc Maximize-Func2	
      AddToFunc Maximize-Func2 "M" Maximize 100 0
      + "C" Maximize 80 0
      + "D" Maximize 100 100

         

      如果鼠标右键在“最大化”按钮上点击(C)那么高度增长为屏幕的 80%, 宽度不变。如果按下鼠标右键后有拖动(M),
         那么高度增长为屏幕高度(100%), 宽度不变。如果双击(D), 就是一般的最大化。


         

      为什么是右键?因为我为左键在这个按钮上定义了更高级的 stroke 来改变窗口大小。我们稍后介绍。


         
    • 按钮样式
         

      按钮的样式是用ButtonStyle定义的。比如我的那三个按钮实际上是如下几句话定义的。

      ButtonStyle All -- UseTitleStyle
      ButtonStyle All ActiveDown VGradient 8 palevioletred black
      ButtonStyle 6 16 20x20@1 30x20@1 50x40@1 70x20@1 80x20@1 80x30@0 \
      60x50@0 80x80@0 70x80@0 50x60@0 30x80@0 20x80@0 \
      20x70@0 40x50@1 20x30@0 20x20@1

         

      那个X形状的关闭按钮实际上是用很简单的语句画出来的。ButtonStyle
         之后的数字是按钮编号,后面一个数子表示一共有多少笔画。后面的XxY@C都是笔画的内容,XxY是坐标, 坐标都是用百分比表示的。@C 表示颜色,
         C是一个数字,0 表示阴影色,1 是高亮色,2 是背景色,3 是前景色,4 是移动光标而不画线。


         

      你可以画你自己的按钮,也可以去那别人设计好的来用 FVWM 的主页上有很多人提供这种按钮。


         

      第二个语句 "ActiveDown VGradient 8 palevioletred black"
         设定了所有按钮按下去还没有松开鼠标时候的样式,是一个颜色梯度。


     
  13. 其它样式
     

    我们已经知道 Style 可以决定窗口的样式,MenuStyle 可以决定菜单的样式,ButtonStyle 按钮的样式。其实还有
     CursorStyle, TitleStyle, BorderStyle. 他们决定了光标,标题栏,边框的样式。他们都有多样的语法,详细的就看
     magpage 吧。这里就不照抄了。


     
  14. 条件命令
     

    All, Any, Cond, Current, Direction, Next, None, Pick, WindowId, ...
     这些命令是条件选择窗口的办法,它们让你可以用非常多样的方法,来确定你的操作需要对哪一个或者哪些窗口进行。比如:

    All (Iconic) MoveToPage -1 -1
    把所有图标化的窗口都移动到桌面右下角的那一页。
    Key F5 A A Direction North Maximize True 0 growdown

     

    以后按 F5 就可以让当前聚焦窗口上面(North)那个窗口往下长大,直到被当前窗口挡住去路。你有时候想在VIM里抄 Acrobat Reader
     里的内容,安排窗口大小的时候就可以用这招。


     
  15. 手写操作 (Stroke)
     

    你用过 EDA 软件吗?用过的话,你就可以知道鼠标动作(stroke)是多么的方便!你是否想在你的窗口管理器里也使用鼠标动作?


     
    • 让 FVWM 支持 Stroke
         

      如果你的FVWM窗口管理器编译进了 libstroke, 你就可以使用鼠标动作操纵程序。libstroke 是一个免费使用的 stroke
         库,你可以在 http://www.etla.net/libstroke/得到 libstroke. 下载那个为 FVWM
         准备的版本,编译后安装,然后再编译 FVWM,它一般就会找到 libstoke,从而加入 stroke 的功能。


         

      比如我在屏幕上按住 ctrl, 用右键


         
      • 画一个 "r" 字就可以启动 rxvt
             
      • 画一个 "V" 就可以启动 vim
             
      • 画出 "D" 右边的弧线就可以启动 IBM 智能辞典
             
      • 画一个 "e" 启动 emacs ...
             
      • 鼠标左右一晃,就可以启动 xkill,再往某个窗口一点,就可以强制杀死不听话的窗口
             
      • 在窗口里右键往下一划,就可以最小化窗口
             
      • 在窗口边框上用右键……
             
      • 向上拖就可以使窗口往上一直长到被别的窗口挡住的地方
             
      • 向左拖就可以使窗口往左一直长到被别的窗口挡住的地方
             
      • 右……下……斜上…… 从边框开始画一个"L"形就可以回复窗口原来大小

         

      当然这些控制方式都是你自己决定的, 这一切只需要在 .fvwm2rc 里加入一些Stroke语句. 因为太多了,写在主配置文件影响编辑,
         这些语句被我写到了另一个文件里,然后在主文件用 Read 语句读入。你可以在这里下载我的fvwm.stroke文件作为参考。
         


         

      你还可以定义非常高级的操作,你甚至可以这样:按住 ctrl, 用鼠标中键画出一条射线箭头指向的那个窗口,
         不论它在那个桌面,就会被吸过来,并且随鼠标移动,你点击左键就可以放置它。


         
    • 轨迹
         

      stroke 的原理很简单,libstroke
         可以识别出你在屏幕上画出的轨迹,把它报告给FVWM,这样FVWM根据轨迹的不同采取不同的操作。轨迹是由一个电话拨号盘的方式确定的。也就是说,把你画出的东西分成9个区域,看你的鼠标依次经过那几个区域。
         

                          1  2  3

                         4  5  6

                         7  8  9
      轨迹也可以用你的小键盘上的数字键来确认。看看你的小键盘:
                          7  8  9

                         4  5  6

                         1  2  3

         
    • Stroke 项目的定义
         

      在你的配置文件里写入一些 Stroke 语句:

      Stroke Sequence Button Context Modifiers Function
      比如:
      Stroke N7414789 0 A C Exec exec rxvt
      Stroke N7414759 0 A C Exec exec rxvt
      Stroke N74147589 0 A C Exec exec rxvt
      Stroke N7414756 0 A C Exec exec rxvt
      Stroke N74156 0 A C Exec exec rxvt
      Stroke N74159 0 A C Exec exec rxvt

         

      Stroke 关键字之后跟上轨迹说明。轨迹是一系列数字,如果数字前面有一个"N",
         就表示我们采用小键盘的布局,而不是电话拨号盘。你看我的那几个轨迹,实际上是我们在写 "r" 字母的时候有可能出现的几种情况。


         


         

      比如,这个轨迹就是符合 "N7414589".


         

      轨迹之后是鼠标按键号码。如果号码不是0,那么一旦识别到这个轨迹,就会马上执行操作。但是如果号码是0,那么说明这个定义不是在任何时候识别到就马上进行的。而是当
         StrokeFunc 命令被调用的时候才进行。StrokeFunc 为你提供了更多的灵活性。


         

      号码之后是 Context Modifiers Function. 他们跟 Mouse, Key 的那两个同名参数是一个意思,参看 鼠标和键盘.
         


         
    • StrokeFunc
         

      如果你的鼠标号码是0. 那么当 StrokeFunc 被调用的时候,这个轨迹如果被识别,就会执行相应的操作。比如:

      #Drag mouse 1 on the maxmize button
      Mouse 1 2 N StrokeFunc DrawMotion
      现在看到了? 这就是我的最大化按钮上对鼠标左键的绑定。DrawMotion 是 StrokeFunc
         的一个可选参数,它可以让轨迹在屏幕上被画出来,这样你可以清楚的看到你到底写了什么。
         

      我有如下的一系列 stroke 定义:

      #grow horizontal and vertically
      Stroke N258 0 TSF2 N Maximize True 0 growup
      Stroke N852 0 TSF2 N Maximize True 0 growdown
      Stroke N456 0 TSF2 N Maximize True growright 0
      Stroke N654 0 TSF2 N Maximize True growleft 0

      #grow bidirectional
      Stroke N25852 0 TSF2 N Maximize True 0 grow
      Stroke N5852 0 TSF2 N Maximize True 0 grow

      ........

      #reverse to unmaximized
      Stroke N74123 0 TSF2 N Maximize False

         

      我的鼠标左键按下“最大化”按钮之后可以进行绘画,然后窗口会随着轨迹的不同而采取各种各样的改变大小的行动!


         

      我还有一个定义:

      Mouse 3 TSF N StrokeFunc DrawMotion
      这样鼠标右键在窗口标题栏,边框,frame 上绘画时也会触发 StrokeFunc
         函数,达到跟左键在“最大化”按钮上绘画同样的效果。发现了吧?StrokeFunc
         为我省去了重复的轨迹定义,否则我需要为“左键+最大化按钮”和“右键在边框”定义两套 stroke.
         
    • 实例分析
         

      我们来分析一种可能的执行情况:用鼠标左键按下“最大化”按钮(2),然后向右画。就像这个样子:


         


         

      当鼠标左键在“最大化”按钮(2)上按下之后,如果没有键盘控制键按下(N),而那么根据"Mouse 1 2 N StrokeFunc
         DrawMotion", FVWM就会发现应该调用 StrokeFunc.


         

      StrokeFunc 会马上记录鼠标按下的时候有哪些控制键按下了,现在是没有控制键(N).


         

      然后它发现鼠标随即向右画出了一条线,看看你的小键盘,这是N456。StrokeFunc 就会在已经定义的 Stroke
         里去找,是否存在这样的一个定义,它的前面部分是

      Stroke N456 0 2 N ...
      它发现有一个
      Stroke N456 0 TSF2 N Maximize True growright 0

         

      它的 Context: TSF2 包含了标题栏按钮2。鼠标动作开始时没有控制键按下,而这个项目的Modifiers里也是N.
         那么这是一个符合的项目。所以进行操作 "Maximize True growright 0":把窗口向右扩大,直到被另一个窗口或者屏幕边沿挡住。


         


         

      注意控制键都是在动作开始时就已经记录下来了。如果你在绘画的途中放开了或者按下了控制键是不会改变识别的效果的。


         
    • 怎样提高识别率
         

      通常不要定义太复杂的轨迹,因为变化太多了就不容易识别。左右晃一晃,上下摇一摇,转个圈儿,……已经可以完成你很多任务了。


         

      如果是复杂的 stroke, 比如写一个字母,你需要定义很多相似的 stroke,否则有时不能匹配。如果你不能确定会出现那些轨迹,你可以给
         StrokeFunc 一个参数,比如:

      Mouse 1 2 N StrokeFunc EchoSequence

         

      然后你在屏幕上多画几次你的那个字母,无论它是否匹配一个定义,FVWM
         会在启动它的那个终端输出你画出的轨迹号码。那些就是你写这个字母时有可能出现的轨迹,你把这些序列都加到你的配置文件,这样就提高了识别率。


         

      注意这个输出号码的终端很有可能是
         tty1,在Linux下你需要Ctrl-Alt-F1切换到tty1才能看到输出。如果你不喜欢这么麻烦,你可以在启动X的时候只启动一个 xterm,
         然后在这个 xterm 里面启动 fvwm.


         
    • 键盘触发 Stroke
         

      stroke 也可以由键盘来触发。比如:

      Key F6 A C StrokeFunc DrawMotion NotStayPressed

         

      按下 Ctrl-F6 之后,FVWM就会调用 StrokeFunc, 由于我们设定了 NotStayPressed
         参数,绘画一直会延续到一个鼠标键按下的时候才结束。这时你就可以用鼠标移动画出一个轨迹,然后按一下鼠标。


     
  16. 模块
     

    模块是FVWM可以扩展的奥秘。模块是通过管道跟FVWM通信的程序,它们必须由FVWM启动(fork). 也就是说,你可以从 FvwmConsole
     来启动这些模块,也可以用菜单,鼠标,热键……来启动。但是就是不能从 xterm 或者 rxvt 敲入命令来启动它们。


     
    • 你有没有发现。当你的鼠标移动到窗口后,如果它被别的窗口挡住了,它并不会跑到上面来。如果你想让它自动上来,你可以使用 FvwmAuto
         模块来实现一个简单的“自动提升”功能。我的 StartFunction 里有如下内容:
      AddToFunc StartFunction   	
      + I Module FvwmAuto 500 Raise Nop
      其实你还可以用 FvwmAuto 实现非常复杂的自动提升功能。
         
    • 你想让你的窗口图标化(Iconify) 和取消图标化(Deinconify) 的时候都有漂亮的动画吗?用以下设定来配置你的
         FvwmAnimate 模块,然后启动它,就可以有眼花缭乱的效果了 :)
      *FvwmAnimate: Delay 25
      *FvwmAnimate: Effect Random
      *FvwmAnimate: Width 3
      这些行是对 FvwmAnimate 的配置,模块的配置命令都是 "*" 号开始的。
         
    • 你想要一个 Windows 那样的任务栏吗?启动 FvwmTaskBar 模块就行了。
         
    • 想要一个 Pager? FvwmPager 可以提供你用不完的功能。参看FvwmPager.

         
    • Drag & Drop? 启动 FvwmDragWell, 就可以让支持 XDND 的程序工作。
         
    • 你想这样一种功能:每次当名叫 XXX 的程序出现时,就把它大小变为 400x300, 移动到屏幕右边,然后启动一个 rxvt 跟它作伴?用
         FvwmEvent 可以轻松达到你的目的。
         
    • 你想做一个简单的图形界面程序?用 FvwmScript 可以快速的达到你的目的。
         
    • 写配置文件太冗长了?用 FvwmM4 可以让你用 M4 宏处理语言来预处理配置文件。
         
    • 你想有更加超级的操纵方式?FvwmPerl 可以让你使用 Perl 脚本的方式来操纵 FVWM.
       
    模块的功能可能很复杂,它们都有自己分别的 manpage. 下面几节我们介绍一些常用的模块。
     
  17. FvwmPager
     

    既然 fvwm
     有很多工作区。能不能有一个东西可以方便的看到那些工作区上有哪些程序,而且可以方便的切换工作区呢?FvwmPager就是为这个目的设计的。
     我的Pager是这个样子:


     


     

    FvwmPager有很多可以设定的参数,现在你可以试试这个简单的配置,这就是上面这个 pager 的配置。

    *FvwmPager: Rows 4
    *FvwmPager: Columns 1
    *FvwmPagerBack #908090
    *FvwmPagerFore #484048
    *FvwmPager:Font  -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*
    *FvwmPagerHilight #cab3ca
    *FvwmPagerLabel 0 Main
    *FvwmPagerLabel 1 Internet
    *FvwmPagerLabel 2 Program
    *FvwmPagerLabel 3 Amusement
    *FvwmPager:SmallFont  -*-simsun-medium-r-*-*-12-*-*-*-*-*-*-*
    *FvwmPagerBalloons            All
    *FvwmPagerBalloonBack         Yellow
    *FvwmPagerBalloonFore         Black
    *FvwmPager:BalloonFont         -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*
    *FvwmPagerBalloonYOffset      +2
    *FvwmPagerBalloonBorderWidth  1
    *FvwmPagerBalloonBorderColor  Black
    这些行是对 FvwmPager 的配置,模块的配置命令都是 "*" 号开始的。 在 FVWM 里启动它:
    Module FvwmPager 0 3

     
  18. FvwmButtons
     

    上面的Pager不错吧?不过它总是在屏幕上占那么一块位置,有没有办法让它可以在需要的时候才伸出来呢?你可以用 FvwmButtons
     把FvwmPager包装起来实现这个功能。


     

    这里是我的一个简单的配置:

    *FvwmButtonsBack bisque3
    *MainPanel: Geometry 80x18+40+4
    *MainPanel: Back SeaGreen
    *MainPanel: (Panel(down, indicator, delay 0, steps 1) \
    PagerPanel "Module FvwmButtons PagerPanel")
    *MainPanel: Font  -*-simsun-medium-r-*-*-16-*-*-*-*-*-*-*
    *PagerPanel: Geometry 80x352
    *PagerPanel: (Swallow FvwmPager "Module FvwmPager 0 3")
    *PagerPanel: Font  -*-simsun-medium-r-*-*-16-*-*-*-*-*-*-*
    这个FvwmButtons设置了一个 button 叫做 "MainPanel". 你可以用:
    Module FvwmButtons MainPanel
    来启动它. 它启动时是这个样子:
     


     

    挂在屏幕左上偏右一点的地方,既没有挡住左边的按钮,又不会挡住窗口的下拉菜单。点一下就会展开,展开以后就是这个样子:


     

    再点就会缩回去。


     

    FvwmButtons 可以提供的功能远远不止这些。FvwmButtons 是一个非常强大的模块。你有兴趣可以看看它的 manpage.


     
  19. FAQ
     

    这一节来看看我遇到过的一些问题。


     
    1. 为什么 FVWM 不能用图片作为背景?
         

      不熟悉Xwindow的人经常问这种问题。答案是FVWM确实不能设置复杂的高清晰图片作为背景,但是你却可以用图片作为背景。原因是:设置背景根本不是WM的职责,你需要用其它程序,比如
         xloadimage, xv, ... 在根窗口上放置一幅图片,那就是所谓的“桌面背景”。你可以把它加入你的启动函数,一个 xloadimage
         的例子可以在上面看到
         


         
    2. FVWM怎么锁定屏幕呢?
         

      你又问到一个容易混淆的问题。锁定屏幕也不是WM必须有的功能。几乎所有WM都是调用另外一个程序,比如 xscreensaver
         来锁定屏幕和提供屏幕保护,然后在它们的菜单里加入对 xscreensaver 配置程序 xscreensaver-demo
         的调用。看起来好像是WM提供了屏幕保护功能,让很多用户模糊了WM的职责。


         

      你可以把 xsreensaver 加入到FVWM的启动函数里。参看启动函数和退出函数.
         


         
    3. 为什么 FVWM 的窗口标题不能显示汉字?
         

      FVWM当然能显示汉字了,它是一个国际化的程序。原因在于你没有设置好汉字字体。你可以在配置文件里加入汉字字体的设定:

      Style * Font  -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*
      simsun
         是我机器上一种同时可以支持汉字和英语编码的字体,如果你的字体只有汉字编码,那么你的英文全部都会“乱码”,这时你需要在后面再加一个英文字体。比如:
      Style * Font  -cjacker-magicsong-medium-r-*-*-14-*-*-*-*-*-gb2312.1980-0,*-r-*

         

      类似的,pager,windowlist 都有自己的字体设定,你需要把它们都设置为你喜欢的中文字体。


         
    4. FVWM 有工具条吗?
         

      有。启动 FvwmTaskBar 模块就行了。你还可以把它配置的非常漂亮。这里给出一个我的简陋的配置方案。

      Style FvwmTaskBar HandleWidth 0, BorderWidth 0
      *FvwmTaskBar: UseSkipList
      *FvwmTaskBar: AutoStick
      *FvwmTaskBar: DeskOnly
      *FvwmTaskBar: Action Click1 DeiconifyRaiseAndFocus
      *FvwmTaskBar: Action Click2 Iconify On
      *FvwmTaskBar: Action Click3 Lower
      *FvwmTaskBar: MailCommand Exec exec rxvt -e mutt
      *FvwmTaskBar: 3DFvwm
      *FvwmTaskBar: StartName FVWM
      *FvwmTaskBar: StartMenu RootMenu
      *FvwmTaskBar: Font  -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*
      *FvwmTaskBar: SelFont  -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*
      *FvwmTaskBar: ShowTips
      *FvwmTaskBar: ClockFormat
      *FvwmTaskBar: WindowButtonsRightMargin 20

      *FvwmTaskBar: Back seagreen
      *FvwmTaskBar: Fore gold2
      *FvwmTaskBar: FocusFore cornsilk
      *FvwmTaskBar: IconBack darkgreen
      *FvwmTaskBar: IconFore white

         

      另外,FvwmButtons
         模块提供了更加复杂的功能。你可以把很多小程序(xclock,biff...)和模块(FvwmIconMan)嵌入到它里面。形成一个复杂的工具条。详情请
         man FvwmButtons.


         
    5. FVWM 能不能像 Windows 那样用 Alt-Tab 切换窗口?
         

      能。把这行加入 .fvwm2rc:

      Key Tab A M WindowList Root c c NoDeskSort
      这个绑定不知道什么时候好像成了 FVWM 缺省的。如果你不喜欢,那么加入:
      Key Tab A M -
      取消这个定义。
         
    6. FVWM 能和KDE, Gnome 一起工作吗?
         

      KDE 和 Gnome 都是完整的桌面系统,包括了WM和其它很多东西。FVWM 只是一个WM。FVWM可以替代 KDE 缺省的 kwin,或者
         Gnome 缺省的 sawfish 成为它们的WM。


         
      • 只用KDE和Gnome的工具条
             

        很多时候 Gnome 和 KDE 的程序是跟他们的桌面系统可以分开使用的。其实你有可能只需要它们漂亮的panel。


             

        Gnome 的工具条叫做 gnome-panel, 在 xterm 启动一个就行了。


             

        KDE 的工具条叫做 kicker. 注意 KDE 有些程序需要 dcopserver, 你可以先启动 dcopserver。


             

        KDE 和 gnome 的panel上的pager和fvwm的FvwmPager都是相通的,所以你可以用它们任何一个来切换桌面 :)


             

        如果你在kde的任务条用右键选择“总在最前”可能不起作用,因为现在它们得完全听fvwm的话不过你可以给它们额外的权力,请参考fvwm
             manpage 的有关EWMH 的部分


             
      • 完全启动Gnome和KDE与FVWM一起工作
             

        还有些kde程序不知道用了什么通信方式,启动后就dump了。你可以用 startkde 来启动整个 KDE
             系统。一般来说它们都可以与fvwm一起很好的工作。


             

        Gnome 的启动命令叫做 gnome-session. 它也可以完全与 fvwm 一起工作。


             

        这样你就可以用 fvwm 的方式来控制所有桌面系统的窗口了。嘿嘿

      看看下面这幅图,KDE 正和 fvwm
         在一起。嘿嘿。点击可以放大。
         


         

      你甚至可以让 Gnome 和 KDE 同时出现。不过估计除了耍酷,没人会像这样做:


分页: 4/6 第一页 上页 1 2 3 4 5 6 下页 最后页 [ 显示模式: 摘要 | 列表 ]