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
阅读(1544) | 评论(0) | 转发(1) |