Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1630768
  • 博文数量: 584
  • 博客积分: 13857
  • 博客等级: 上将
  • 技术积分: 11883
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-16 09:34

分类: LINUX

2010-06-25 14:56:07

Index:
Property & Atom 
   Atom 
   Property 
Cut Buffer 
Window Manager 
   WM_NAME 
   WM_ICON_NAME 
   WM_NORMAL_HINTS 
   WM_HINTS 
   WM_CALSS 
Selection 
   Owner & Requestor 
   例 1 
   传输大量资料 - INCR 
   例 2 
   Selection Atom 
   Functions of Selection 
   Client Message 



Property & Atom



在 X 的世界中, 每一个视窗都随附着一些资料, 称为 property. 每个 property 都有一个名称, 和 type. 每 个 property 的 type 指定了资料的资料形态 (type), 如 INTEGER, PIXMAP, CURSOR, ... etc. 而 名称则为存取 property 的途 径, client 透过名称以存取特定视窗 的某个 property. property 可以是由 client 自定, 或由 system 内 建. X 内建了许多 property , 用於视窗管理(window manager 管 理). 如: WM_CLASS, WM_NAME, WM_ICON_NAME, ... etc.

Atom
因为效率因素的考量, 这些 property 的名称和 type 以 atom 表示. 在 系统, 每一个 atom 以一个整数 (atom ID)表示, 代表着一个字串. 而且 每一个 atom 都是唯一的, 没有任何两个 atom 拥有相同的 ID. 当我 对 X Server 发出 request 而需要这些字串时为参数时, 我们就以对应的 atom ID 为参数, 这样可以降低字串在网路上传轮 的 overhead, 改进系统效率. Xlib 提供 一些 function, 让我们在 atom 和字串之间转换. 当 client 导入一 个新的 字串进入系统时, Xlib 也提供 function 以取得一个唯一,而且不重的 atom ID, 以对应新加入的字串. 因 此, 由 client 导入的字串, 在每一次 执行时, 不一定会得到同一个 atom ID. 但, 由系统内建的 atom 则有固 定 的 ID, 这些 atom 定义在 (XA_prefix 形式, 如 XA_WM_CLASS).这 些 atom 可以 hard code 在程式碥, 不需再经过 Xlib 所提供的 function 加以转换.

atom 除了用於 property 名称和 property type 之外, 还用 於 selection , Font property, type of client message 等等.

下面是 Xlib 提供的 function, XInterAtom 可从 string 转换 成 atom ID, XInterAtoms 则一次可以转换多个字串. XGetAtomNames 则是由 atom 取得字串. 
--------------------------------------------------------------------------------

  Atom XInternAtom(display, atom_name, only_if_exists)
Display *display;
char *atom_name;
Bool only_if_exists;


--------------------------------------------------------------------------------
由 atom_name 指定要转换的字串, XInternAtom 传回对应 的 atom ID. 当 only_if_exists 为 True, 若字串原本不存在系统, 则会为其分配 一个不重 的 ID. 若 only_if_exists 为 False 时, 只有在 atom 早己 存在时才会传回 atom ID, 否则会传 回 None.


--------------------------------------------------------------------------------

  Status XInternAtoms(display, names, count, only_if_exists,
  atoms_return)
Display *display;
char **names;
int count;
Bool only_if_exists;
Atom *atoms_return;


--------------------------------------------------------------------------------
XInternAtoms 和 XInternAtom 功能相同, 但一次转换多个 atom, 由 names 传入每个字 串, count 是字串的数目, 由 atoms_return 传回 atom ID 阵列. only_if_exists 为 False, 只 有己存在的 atom 会 传回 atom ID, 不存在的 atom 会传回 None. only_if_exists 为 True 时, 则会 为不存在的 atom 配置一个 atom ID. 这个函数只有在所有的字串都 传回 atom ID 时, 才传回不为 0 的数字, 否则传 为 0.


--------------------------------------------------------------------------------

  char *XGetAtomName(display, atom)
Display *display;
Atom atom;


--------------------------------------------------------------------------------
XGetAtomName 可从 atom ID 取得对应字串.


--------------------------------------------------------------------------------

  Status XGetAtomNames(display, atoms, count, names_return)
Display *display;
Atom *atoms;
int count;
char **names_return;


--------------------------------------------------------------------------------
和 XGetAtomName 相同, 但可一次转换多个 atom.

Property

--------------------------------------------------------------------------------

  int XGetWindowProperty(display, w, property, long_offset,
  long_length, delete, req_type, actual_type_return,
  actual_format_return, nitems_return, bytes_after_return,
  prop_return)
Display *display;
Window w;
Atom property;
long long_offset, long_length;
Bool delete;
Atom req_type;
Atom *actual_type_return;
int *actual_format_return;
unsigned long *nitems_return;
unsigned long *bytes_after_return;
unsigned char **prop_return;


--------------------------------------------------------------------------------
XGetWindowProperty 为我们传回 property 的内容, client 指定 display, 视窗 (w), property, 从资料那个位置(long_offset)开始读取和 读取长度 (long_length). delete 为 True or False, 指定是否在读取之後, 将 property 删 除. long_length 是以 4 bytes 为单位, 也就是你实际指定 的长度是 long_length * 4. 另 外 req_type 指定 property 资料的 type, 若你不计较 property 资料的 type, 那麽你可以指 定 AnyPropertyType. 而此 function 则传回资料的实际 type(actual_type_return), 资料 的 format(单位长度 8, 16, 32;actual_format_return), 传回多少个单位 的资料(实际长度 /format;nitems_return), 结尾还有多少资料 (bytes_after_return)和 property 内容 (prop_return).注意: 改变 property 或 delete property 会产 生 PropertyNotify event.

若我们所要读取的 property 并不存在, 那麽 XGetWindowProperty 会 传回 None 实际资 料 type(actual_type_return). 
--------------------------------------------------------------------------------

  int XGetWindowProperty(display, w, property, long_offset,
  long_length, delete, req_type, actual_type_return,
  actual_format_return, nitems_return, bytes_after_return,
  prop_return)
Display *display;
Window w;
Atom property;
        long long_offset, long_length;
        Bool delete;
        Atom req_type;
        Atom *actual_type_return;
        int *actual_format_return;
        unsigned long *nitems_return;
        unsigned long *bytes_after_return;
        unsigned char **prop_return;


--------------------------------------------------------------------------------
XGetWindowProperty 为我们传回 property 的内容, client 指定 display, 视窗 (w), property, 从资料那个位置(long_offset)开始读取和 读取长度 (long_length). delete 为 True or False, 指定是否在读取之後, 将 property 删 除. long_length 是以 4 bytes 为单位, 也就是你实际指定 的长度是 long_length * 4. 另 外 req_type 指定 property 资料的 type, 若你不计较 property 资料的 type, 那麽你可以指 定 AnyPropertyType. 而此 function 则传回资料的实际 type(actual_type_return), 资料 的 format(单位长度 8 bits, 16 bits, 32 bits;actual_format_return), 传回多少个单位的资料 (实际长度/format;nitems_return), 结尾还有多 少资料(bytes_after_return)和 property 内容 (prop_return).

因为 X 的网路特性, 让我们不得注意 byte order 的问题. 资料在网路 上传送, 我们无法知道在网对面的接收端电脑的资料表示 形式是否和我们 相同. 如一个 32 bits - 4bytes 的整数, 低位元和高位元的存放次序在 不同的电脑上就不太相同. 也许在 A 机 器的储放方式是先最低位的 byte 然後次低位,然後次高位,最後最高位. 然 B 机器却可能相反. 因此, 每 个 property 都必需指 定 format, 以确定资料单位的单位长度, 这样 Xlib 才能自动进行 byte order 的转换, 确保资料 的 byte order 不会 错乱.

若我们所要读取的 property 并不存在, 那麽 XGetWindowProperty 会 传回 None 实际资 料 type(actual_type_return). actual_format_return 和 bytes_after_return 也皆 为 0. nitem_return 则传回 0(empty).

若 property 存在, 但是 req_type(request type) 和 property 的实际 type 不合(不相 同), 那麽 XGetWindowProperty 在 actual_type_return 传回实 际 的 type, 在 actual_format_return 传回 property 资料 的 format, bytes_after_return 则以 byte 为单位, 传回 property 的实际长度. 这 时, nitem_return 则为 0, 也就是不传回任何资料(空的;empty).

若 property 存在, 且指定 AnyPropertyType 或 property type 和指定 的 type 吻 合, 则 XGetWindowProperty prop_return 传回 property 的内容. 
--------------------------------------------------------------------------------

N = property 的实际长度(以 byte 为单位)
I = 4 * long_offset
T = N - T
L = MINIMUM(T, 4 * long_length)
A = N - (I + L)


--------------------------------------------------------------------------------
prop_return 传回的资料长度为 L, 但 XGetWindowProperty 总是会多配置 一个 byte 的空间, 在这个 多馀的 byte 填上 0, 这样方便字串的使用, 不需进行 null terminate, 增加 copy 的动 作. bytes_after_return 则 传回 A, 告知 client 在传回这些资料後, 还有多少资料在後 面. prop_return 的内容是从 property 的第 I 个 byte 开始, 一直 到 (I + L - 1) byte, prop_return 的空间是於 Xlib 自动配置, client 程式最後必需透 过 XFree() 将之释放.


--------------------------------------------------------------------------------

  Atom *XListProperties(display, w, num_prop_return)
Display *display;
Window w;
int *num_prop_return;


--------------------------------------------------------------------------------
XListProperties 可传回随附在视窗(w)的所有 property 名称 (名称字串 的 atom). num_prop_return 是实际 property 的个数, 名称 atom 直接从 return value 传 回 atom list. 若视窗(w)没有任有 property, 则 function 传回 null pointer. 传回 的 atom list 最後必需以 XFree() 释放.


--------------------------------------------------------------------------------

  XChangeProperty(display, w, property, type, format, mode,
  data, nelements)
Display *display;
Window w;
Atom property, type;
int format;
int mode;
unsigned char *data;
int nelements;


--------------------------------------------------------------------------------
透过 XChangeProperty 可以修改增加 property 的内容. property 和 type 分别传 入 property 的名称 atom 和 type atom, format 可以指定 8, 16, 32. nelements 则是传入资料 的单位个数, data 则为资料内容. mode 则指 定修改方 式, PropModeReplace, PropModePrepend, 或 PropModeAppend. 
PropModeReplace 
以新的资料完全取代旧内容. 
PropModePrepend 
新资料插入到旧资料之前 
PropModeAppend 
新资料插入到旧资料之後 
PropModePrepend 和 PropModeAppend mode, 新资料的 type 和 format 必需和旧资料相同.


--------------------------------------------------------------------------------

  XDeleteProperty(display, w, property)
Display *display;
Window w;
Atom property;


--------------------------------------------------------------------------------
删除 property.

Cut Buffer
Cut Buffer 是一种简单, 但是功能、效果较不好的 peer-to-peer 讯通架构. Cut Buffer 是属於一种被动的 形式, 资料提供者直接将资料放在 cut buffer。 当其它 client 有需要时,直接从 cut buffer 将资取出,资料的要求者和 资 料的提供者之间没有直接的互动。

Cut buffer 机制包含 8 个在 screen 0 的 root window 的 property, 分别 以 atoms CUT_BUFFER0 ... CUT_BUFFER7 命名。存在 cut buffer property 的资料,必 需 是 STRING type 并且 format 8。资料提供者在储存资料之前,必需先确定这些 property 是否存在。确定的方式是透 过 XChangeProperty() 函数, append 长度 为 0 的资料至 CUT_BUFFER0 ... CUT_BUFFER7。

资料提供者在每次储存资料至 CUT_BUFFER0 ... CUT_BUFFER7 之前,必需先 做 rotate property 的 顺序。透过 XRotateWindowProperties 函数,将 CUT_BUFFER0 改名 为 CUT_BUFFER1, CUT_BUFFER1 改为 CUT_BUFFER2 ...... CUT_BUFFER7 改名 为 CUT_BUFFER0。 写入 Cut buffer 的机制如下: 
资料提供者确定 CUT_BUFFER0 ... CUT_BUFFER7 存在.(XChangeProperty) 
Rotate Properties 
将资料存入 CUT_BUFFER0 

Client 在读取资料时,也会希望输替读取 CUT_BUFFER0 ... CUT_BUFFER7 的 内容,那麽需要在读取资料之後, 透过 XRotateWindowProperties 函数,将 CUT_BUFFER0 ... CUT_BUFFER7 改 名,CUT_BUFFER7 变 成 CUT_BUFFER6 ,CUT_BUFFER6 变 CUT_BUFFER5, ......, CUT_BUFFER0 变 成 CUT_BUFFER7。 读取 cut buffer 的机制如下: 
读取 CUT_BUFFER0 
Rotate Properties 

Window Manager
当 client 执行时, 除了要处理视窗的内容外, 还需要和 Window Manager 配合, 提 供 Window Manager 必要的资讯, 如视窗的名称(WM_NAME),icon 等等, 让 Window Manager 进行装饰工作 (如显示 title, 提供视窗的外框). 这 些由 client 提供给 Window Manager 的资讯称为 hint, 是透 过 property 的机制附属於 top window.我们可以直设定 property, 或经由 Xlib 提供的 function, 提 供 Window Manager Hint

以 client 的观点而言, top window 可分为三种状态 
Normal 
Iconic 
Withdrawn 
视窗刚被建立时, top window 初始在 Withdrawn, 此时视窗尚未 map. 一旦 map 之 後, top window 即进入 Normal 或 Iconic state. 之後, 因 map 和 unmap 而 在 Normal 和 Iconic 之间转换. Normal state 即一般的视窗模式, 相对於 Iconic state, 视窗只以一个 小 icon 表示.

WM_NAME
通常 Window Manager 会在 Window 的上方放置一个 title bar, 用以 显示 Window 的名 称. Window Manager 透过 Client 设定 WM_NAME property, 取得 Client 希望设定的讯 息. WM_NAME 是一个经过编码的 字串, 而字串的 encoding 则由 property 的 type 决定. 例如 以 STRING 为 property type, 则字串的内容为 ISO Latin-1 character 再加上一些控制字 元; COMPOUND_TEXT 则为 Compound Text interchange format 字串, 为一种可以包含 Multi- language 的字串格式(此格式内 容烦长, 需另写文章介绍). 
--------------------------------------------------------------------------------

                                                
  void XSetWMName(display, w, text_prop)
Display *display;
Window w;
XTextProperty *text_prop;

  typedef struct {
      unsigned char *value;/* property data */
       Atom encoding;      /* type of property */
       int format;         /* 8, 16, or 32 */
       unsigned long nitems;/* number of items in value */
  } XTextProperty;


--------------------------------------------------------------------------------
Xlib 提供 XSetWMName 做为方便函数, 但使用起来似乎没有比直接 使用 XChangeProperty 方便到那去. 使 用 XChangeProperty 修改 WM_NAME property 时, type 参数即 和 XTextProperty::encoding 相当, 可以 为 STRING, COMPOUND_TEXT 或 C_STRING 等 type.

WM_ICON_NANE
WM_ICON_NAME 指定 window 的 icon 名称. Window Manager 将一个 视窗变成 icon 形式 时, 通常会在 icon 下方显示字串, 以提醒使用 者该 icon 和代表的内容. 当 window 进入 icon 状态时, 由 於 icon 的面积往往较小, title bar 上的讯息通常太长, 以致於不适合做为 icon 名称. 所以 WM_ICON_NAME 需要 由 Client 设定一较精简的讯息, 以反应其内容.

WM_NORMAL_HINTS
WM_NORMAL_HINTS property 的 type 为 WM_SIZE_HINTS, 设定和 window 大小相关的资 料, 如视窗的最大宽度和高度. 当使用者欲 改变视窗大小时(如将视窗拉大), Window Manager 会参 考 WM_NORMAL_HINTS, 以控制 window 的行为.

WM_NORMAL_HINTS 的内容如下: 
--------------------------------------------------------------------------------
 
Field Type Comments 

--------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------
 
flags CARD32 见下表 
pad 4*CARD32 For backward compatibility 
min_width INT32 宽度最小值 
min_height INT32 高度最小值 
max_width INT32 宽度最大值 
max_height INT32 高度最大值 
width_inc INT32 视窗宽度的变化值 
height_inc INT32 视窗高度的变化值 
min_aspect (INT32,INT32)  
max_aspect (INT32,INT32)  
base_width INT32 初始的宽 
base_height INT32 初始的高 
win_gravity INT32 default=NorthWest 

--------------------------------------------------------------------------------
 
下面定义 WM_SIZE_HINTS.flags bits: 
--------------------------------------------------------------------------------
 
Name Value Field 

--------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------
 
USPosition 1 User-specified x, y 
USSize 2 User-specified width, height 
PPosition 4 Program-specified position 
PSize 8 Program-specified size 
PMinSize 16 Program-specified minimum size 
PMaxSize 32 Program-specified maximum size 
PResizeInc 64 Program-specified resize increments 
PAspect 128 Program-specified min and max aspect ratios 
PBaseSize 256 Program-specified base size 
PWinGravity 512 Program-specified window gravity 

--------------------------------------------------------------------------------
 
WM_SIZE_HINTS.flags 用以告知 Window Manager, Client 设定 WM_SIZE_HINTS 那些栏 位. 但 USPosition 和 USSize 则是例外, 告知 Window Manager 视窗第一次 map 时, 可由使用者指定视 窗 位置和大小. PPosition 和 PSize 则是另一个另外, 告知 Window Manager 视窗第一次 map 时, 位置和大小 全由 client 自行控制, 不需经过使用者指定.

PMinSize 和 PMaxSize 所指定的栏 位 min_width, min_height, max_width, max_height 告知 Window Manager, 当使用调整视 窗 的大小时, 希望视窗大小不超过这几个极限值.

PResizeInc 和 PBaseSize 的栏 位 width_inc, height_inc, base_width 和 base_height 形成下面两修公式: 
width = base_width + (i * width_inc)
height = base_height + (j * height_inc)

i 和 j 是大於零的整数. 当使用者调整视窗大小时, client 希望 Window Manager 只让 user 将视窗调整为符 合上列公式所得的宽和高, 成为 perferred window size. 若 base_width 和 base_height 没有指 定, 则 Window Manager 以 min_width 和 min_height 做为 base.

PAspect 和 PBaseSize 的栏位形成下面公式: 
min_aspect[0] / min_aspect[1] <
(width - base_width) / (height - base_height) <
max_aspect[0] / max_aspect[1]

在每次改变视窗大小时, Window Manager 会检查上面的不等式是否成立, width 和 height 为视窗的宽和 高. 若 client 没有指定 base size, 那麽 width 和 height 就不 需减去 base size, 也就是使用下面 的 式子: 
min_aspect[0] / min_aspect[1] <
width / height <
max_aspect[0] / max_aspect[1]

这些不等式, 更进一步限制 preferred window size 的比例.

PWinGravity 指定 client window 要如何移位(shift), 以维 持 window manager frame 和 client window 的位置 关. PWinGravity 可以 是 Static, NorthWest, NorthEast, SouthWest, SouthEast, North, South, East, West 和 Center. 若 指定 Static, 则 client window 保位置, window manager frame 临接在 client window 的 外缘; window manager frame 的内缘和 client window 的 border 位在相同位置. 其 它 win_gravity 指定的值, 指定了一个参考 点 (referrence point). North, South, East, West 指定参考点於 於相对应的外围边缘 (outer border; 视窗的外框线)的中心 点. NorthWest, NorthEast, SouthWest 和 SouthEast 指定对应的角落为 参考点 (referrence point). Center 则指定视窗之中央为 referrence point. 若是指定 Static 以外 的 PWinGravity 值, 则 window manager frame 的 referrence point 将会位 於 client window 从 Withdrawn state 变成其 它 state 时, client window 的 referrence point 的 位置. 即 client window 的位置会适当 的位移(shift), 以使的 frame 的 referrence point 能置於原 本 client window referrence point 的位置.

WM_HINTS
WM_HINTS property 的 type 为 WM_HINTS, 提供 window manager 除了位置大小和名称以外的资 讯, 让 client 能向 window manager 进行一些视窗行为的建议. 
--------------------------------------------------------------------------------
 
Field Type Comment 

--------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------
 
flags CARD32 请见下表 
input CARD32 The client's input model 
initial_state CARD32 第一次 map 时的状态 
icon_pixmap PIXMAP icon 的图形 
icon_window WINDOW 显示 icon 图形的视窗 
icon_x INT32 icon 位置的 x 座标 
icon_y INT32 icon 位置的 y 座标 
icon_mask PIXMAP icon 形状的 mask 
window_group WINDOW group leader 的 window ID 

--------------------------------------------------------------------------------
 
下表定义 WM_HINTS.flags bits: 
--------------------------------------------------------------------------------
 
Name Value Field 

--------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------
 
InputHint 1 input 
StateHint 2 initial_state, 参考下表 
IconPixmapHint 4 icon_pixmap 
IconWindowHint 8 icon_window 
IconPositionHint 16 icon_x & icon_y 
IconMaskHint 32 icon_mask 
WindowGroupHint 64 window_group 
MessageHint 128 (obsolete) 
UrgencyHint 256 urgency 

--------------------------------------------------------------------------------
 
initial_state: 
--------------------------------------------------------------------------------
 
State Value Comment 

--------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------
 
NormalState 1 视窗内容可见 
IconicState 3 视窗在 icon 状态 

--------------------------------------------------------------------------------
 
WM_HINTS.flags 指定 client 设定的 WM_HINTS property 栏 位. 上面第二表定义各栏位的对 应 flag bit.

input 栏位的值为 True or False. 当使用者点选视窗时, 通常 window manager 会将 Focus 转移 至 user 点选的视窗, 以供使 用者在该视窗进行输入资料的动作. input 栏位若为 True, window manager 就会主动 将 focus 设定在 user 指定的 top window. 若 input 栏位为 False, 则 window manager 将不会 设定 focus 至 该 top window. 因此, 一些 input only 的视窗, 例如小时钟之类的 程式, 就不需 要 focus, 可以将 input 栏位设为 False. 虽然 window manager 不主动转移 focus 至 input 栏位 为 False 的 top window, 但是 client 还是可以自行主动进行 focus 的转移, 取得 focus.

initial_state 可 为 NormalState 或 IconicState. 为 NormalState 时, top window 第一次 map 会进 入 normal state. 为 IconicState 时, 则会进入 iconic state.

icon_pixmap 指定该视窗的 icon 图形. 关於 icon pixmap 有几个规定: 
若有 WM_ICON_SIZE property 存在於 root 视窗, 则 pixmap 必需是 WM_ICON_SIZE 所指的其 中一个大小. 
pixmap 的 deep 必需为 1 bit. 
icon_mask 用来指定 icon 的形状, 去除不必要的陪份, 让 icon 不只是 矩形, 也可以是不规则形.

也许你希望使用自己指定的视窗做为 icon, 那麽你就必需将 window id 设定於 icon_window. 如 此, client 可以自行控制 icon 行, 做一些不同 的变化.

flags bit, UrgencyHint 告知 window manager 视窗的内容是属於紧急 性的, 如 此 window manager 可以做特别的处理, 以提醒 user. UrgencyHint 状态可以随时改便, 随 时 set or unset. 当一 top window 离开 Withdrawn state 後, window manager 就必需随时 注意 UrgencyHint 的变化, 以及时做出反应.

WM_CLASS
WM_CLASS property 的 type 为 STRING, 包含两个连续, null-terminated 的字串, 分别 为 application 的 instance name 和 class name. 这两个 name 用 於 window manager 或 client 存取 application 的 resource 时使用, 做为识别名称 (identify). 关於 resource 在往後 的章节另有说明.

Selection
在 X 环境, 两个 client 之间要如何交换讯息呢? client 之间不能 像一般的程式一样, 开个共同存取的档案, 而 且 client 可能各自使用 不同的协定和 X Server 通讯, 因此不能假定能透过一般的方式和其它 client 沟 通. X client 之间主要的通讯方式是透过 selection 机制. Atom 在这也扮演 selection 的名称, 做为存取的媒 介.

selection 主要是用於 client 之间传输资料, 如: 常用於视窗之间的 copy & paste 动作. 我们先 在 A 视窗 mark 要 copy 的资料, 然於 再於 B 视窗 paste, 於是 A 视窗成了资料的拥有者, B 视窗成了资 料的要求 者. 当在 A 视窗完 mark 资料的动作之後, A 视 窗取得一个 selection S 的拥有权, 成为 S 的拥有者, 等待资料要求者 的要求. 然後我们在 B 视窗进行 paste 动作时, B 视窗就向 S 进行要求(SelectionRequest), 这个 对 selection S 的要会转送到 S 的拥有者 A 视窗. A 视窗 收到要求後就将资料传送给 B 视窗. 接我们又在 C 视窗进 行 paste 动作, 同样的 C 视窗也对 S 进行要求, 而 A 视窗则继续服务 对 S 提出的要求, 直到其它视窗夺走(取得) S 的拥有 权, 或着 A 视 窗自动放弃 S 的拥有权.

Owner & Requestor
系统内可以有多个 selection 存在, 每个 selection 有自已的名称. 这些 selection 是整 个 display 共用的, 除了系统预定的 selection , client 之也可以定义自己的 selection. 每 个 selection 可以有一 个拥有者(owner)视窗, 但 selection 不一有拥有者. 当视窗准备好 资料, 视窗的拥有 者 client 透过 XSetSelectionOwner() 函数宣告视窗 成为 selection 的新拥有 者. 若 selection 原本就有一个拥有者, 在改变拥有者时, 原拥有者会得 SelectionClear event, 得知不再拥 有 该 selection.

Selection 的要求者(requestor)则透过 XConvertSelection() 函数对 selection 进 行要 求, 这时拥有者会收到 SelectionRequest event. SelectionRequest 包含几个参 数, selection, target, property, 和 requestor. target 指定要求的资料形态, 例 如 INTEGER, PIXMAP, AnyPropertyType. 拥有者 将资料转换成 target 指定的 type, 然後才传送 给 requstor 指定的视窗. 传送流程 中, 若拥有者有能力提供 target 指定的资料 type, 则拥有者将资料写 入 SelectionRequest 指定的 property, 然後拥 有者传送 SelectionNotify 给 requestor, 告 知资料己经备妥. 拥有者必需设定 SelectionNotify 的 selection, target, property 和 time 等参 数. 这些参数必需和 SelectionRequest 得到的对应参 数相同. 若拥有者无法提供 target 指定的资料 type, 或者无法 顺利写入 property, 则 SelectionNotify 的 property 参数需设为 None, 以示无法提供资料.

要求者在收到 SelectionNotify 之後, requestor 就从 SelectionNotify 指定 的 property(!= None) 读取资料, 最後将 property delete (透 过 XGetWindowProperty, delete=True). property 被 delete 之後, 拥有者会得 到 PropertyNotify, 以得知 requestor 己传完资料. 拥有者在得知资料 己传送完毕前, 必需保持资料的完整性, 直到传送 完成之後, 才可以 对使用者做回馈反应. 拥有者(owner)为了要在最後能收到 PropertyNotify 必需在传 送 SelectionNotify 之前, 对 requestor 视窗的 PropertyNotify 表示兴趣 (XSelectInput), 才能正确的收到 event.

要求者若要求一个没有拥有者(owner)的 selection 时, 这明显的得不到 任何资料, X Server 会自动产生一 个 property=None 的 SelectionNotify. 

Request selection 的流程: 
要求者: XConvertSelection() 
拥有者: 
收到 SelectionRequest 
将资料转换成 target 指定的 type 
然後将资料 replace property 的资料, 传送 SelectionNotify 要求者. 
要求者: 
收到 SelectionNotify 
读取 property 并 delete property. 
要求者完成所有步骤. 
拥有者: 
收到 PropertyNotify(state=Deleted). 
拥有者完成 request 的 service. 
下面是本章各 event 的结构: 
--------------------------------------------------------------------------------

typedef struct {
    int type;
    unsigned long serial;   /* # of last request processed by server */ 
    Bool send_event;    /* true if this came from a SendEvent request */
    Display *display;   /* Display the event was read from */
    Window owner;
    Window requestor;
    Atom selection;
    Atom target;  
    Atom property;
    Time time;
} XSelectionRequestEvent;


--------------------------------------------------------------------------------


Structure of SelectionNotify: 
--------------------------------------------------------------------------------

typedef struct {
    int type;   
    unsigned long serial;   /* # of last request processed by server */
    Bool send_event;    /* true if this came from a SendEvent request */
    Display *display;   /* Display the event was read from */
    Window requestor;
    Atom selection;  
    Atom target;     
    Atom property;      /* ATOM or None */
    Time time;
} XSelectionEvent;


--------------------------------------------------------------------------------



--------------------------------------------------------------------------------

typedef struct {
    int type;
    unsigned long serial;   /* # of last request processed by server */
    Bool send_event;    /* true if this came from a SendEvent request */
    Display *display;   /* Display the event was read from */
    Window window;
    Atom selection;
    Time time;
} XSelectionClearEvent;


--------------------------------------------------------------------------------


Structure of PropertyNotify: 
--------------------------------------------------------------------------------

typedef struct {
    int type;
    unsigned long serial;   /* # of last request processed by server */
    Bool send_event;    /* true if this came from a SendEvent request */
    Display *display;   /* Display the event was read from */
    Window window;
    Atom atom;
    Time time;
    int state;      /* NewValue, Deleted */
} XPropertyEvent;


--------------------------------------------------------------------------------


例 1
程式
signature

传输大量资料 - INCR
利用 property 做为传输媒介时, 由於 property 是属於系统资源, 当 资料量大时, 耗用系统大量的资源, 因此实在不适 合一次塞进这麽多资 料, 造成系统资源的使用效率低落. 因此 selection 在 ICCCM 提供 了一个传送大量资料时的成规.

当 selection 传送大量资料的完整流程如下: 
拥有者传送 property type 为 INCR 的 SelectionNotify 给拥 有 者, type INCR (incrementally) 是一种整数, 记录整个 selection 的资料大小. 
要求者收到 SelectionNotify, property 的 type 为 INCR, 这时 要求者可以从 property 取得 整个 selection 的资料量(integer) ; 以byte 为单位计 算. 并 delete property. delete property 会造 生 PropertyNotify(state=Deleted). 
拥有者收到 PropertyNotify(state=Deleted), 将一小部分还未传输 的资料附加(append) 到 property. 这个 property 和前面的 SelectionNotify 的 property 相同. 由 於 property 改变, 这导致 PropertyNotify(state=NewValue) event. 
要求者收到 PropertyNotify(state=NewValue) event, 从 property 读取资 料, 并 delete property 产生 PropertyNotify(state= Deleted). 
goto step 3 until 没有未传资料. 
拥有者收到 PropertyNotify(state=Deleted)对 property append 长度 0 的资料. 
要求者收到 PropertyNotif(state=NewValue), 从 property 读取 资料长 度 0, 并 delete property 产生 PropertyNotify(state= Deleted). 要求者完 成 selection request. 
拥有者收到 PropertyNotify(state=Deleted), 完成 对 selection request 的 service. 
Selection Atom
前面说过, selection 可以由 client 自行定义, 每一个 selection 都以 atom 命名. X 环境定义三 个 selection atom, 让各种 client 可以遵循, 让各种不特定的 client 能够相互沟通. 
PRIMARY 
主要用於当作 command 的第一个 selection 参数 
SECONDARY 
当作需要两个 selection 参数的 command 的第二个参数, 或其它原因不愿使 用 PRIMARY 时使用. 
CLIPBOARD 
做为一般 copy & paste 动作使用. 
在 ICCCM 说道, 习惯上, 一般的 client 只也支援上面三个 selection, 反过来说, client 至少要能支援上 面三个 selection. 否则很难 和其它 client 做 inter-client 的通讯.

例 2
程式
signature

DELETE INSERT_SELECTION INSERT_PROPERTY 
Functions of Selection

--------------------------------------------------------------------------------

  XSetSelectionOwner(display, selection, owner, time)
Display *display;
Atom selection;
Window owner;
Time time;


--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

  Window XGetSelectionOwner(display, selection)
Display *display;
Atom selection;


--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

  XConvertSelection(display, selection, target, property,
  requestor, time)
Display *display;
Atom selection, target;
Atom property;
Window requestor;
Time time;


--------------------------------------------------------------------------------

Client Message
阅读(1477) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~