44、Xlib 扩展开发指南

Xlib 扩展开发指南

1. 扩展概述

在 X 系统里,核心协议能够借助扩展来实现功能的演进。所以,扩展不应被视为二等公民,在未来,你喜爱的扩展或许会成为 X 标准的一部分。为了让扩展的使用与核心协议的使用几乎没有差别,扩展应采用惰性评估机制,在首次被调用时自动完成初始化,避免在应用程序里显式地对其进行初始化。

同时要注意,一个 X 扩展通常由多个请求构成,把 10 个新特性定义成 10 个独立的扩展并非好做法,而应该将它们封装成一个扩展,利用次要操作码来区分不同的请求。编写 Xlib 存根所需的符号和宏在 <X11/Xlibint.h> 中列出。

2. 基本协议支持例程

扩展的基本协议请求主要有 XQueryExtension XListExtensions 这两个函数。

2.1 XQueryExtension 函数

Bool XQueryExtension(Display *display, const char *name, int *major_opcode_return, int *first_event_return, int *first_error_return);
  • display :指定与 X 服务器的连接。
  • name :指定扩展的名称。
  • major_opcode_return :返回主操作码。
  • first_event_return :若存在,返回第一个事件代码。
  • first_error_return :若存在,返回第一个错误代码。

该函数用于判断指定名称的扩展是否存在。若扩展不存在,返回 False ;若存在,则返回 True 。若扩展存在,会将扩展的主操作码返回给 major_opcode_return ;若不存在,则返回 0。次要操作码和请求格式因扩展而异。若扩展涉及额外的事件类型,会将基本事件类型代码返回给 first_event_return ;若不涉及,则返回 0。事件的格式由扩展决定。若扩展涉及额外的错误代码,会将基本错误代码返回给 first_error_return ;若不涉及,则返回 0。错误中额外数据的格式也由扩展决定。

需要注意的是,如果扩展名称不是以主机可移植字符编码表示,结果将取决于具体实现。并且,大小写是有区别的,像 “thing”、”Thing” 和 “thinG” 会被视为不同的名称。

2.2 XListExtensions 函数

char **XListExtensions(Display *display, int *nextensions_return);
  • display :指定与 X 服务器的连接。
  • nextensions_return :返回列出的扩展数量。

此函数会返回服务器支持的所有扩展的列表。若服务器返回的数据采用拉丁可移植字符编码,那么返回的字符串将采用主机可移植字符编码;否则,结果取决于具体实现。

2.3 XFreeExtensionList 函数

void XFreeExtensionList(char **list);
  • list :指定扩展名称列表。

该函数用于释放 XListExtensions 分配的内存。

下面是这些函数的调用流程 mermaid 流程图:

graph TD;
    A[开始] --> B[调用 XQueryExtension];
    B --> C{扩展是否存在};
    C -- 是 --> D[获取主操作码、事件代码、错误代码];
    C -- 否 --> E[返回 False];
    D --> F[调用 XListExtensions];
    F --> G[获取扩展列表];
    G --> H[调用 XFreeExtensionList 释放内存];
    H --> I[结束];
    E --> I;
3. 挂钩到 Xlib

这些函数可让你挂钩到库中,通常不是应用程序程序员使用,而是由需要扩展核心 X 协议和 X 库接口的人员使用。生成 X 协议请求的函数一般被称为存根。

在扩展中,存根首先要检查自身是否已在某个连接上完成初始化,若未初始化,则应调用 XInitExtension 尝试在该连接上进行初始化。

3.1 XExtCodes 结构体

typedef struct _XExtCodes { /* public to extension, cannot be changed */
    int extension;  /* extension number */
    int major_opcode; /* major op-code assigned by server */
    int first_event; /* first event number for the extension */
    int first_error; /* first error number for the extension */
} XExtCodes;

该结构体用于返回 XInitExtension 的信息,在 <X11/Xlib.h> 中定义。

3.2 XInitExtension 函数

XExtCodes *XInitExtension(Display *display, const char *name);
  • display :指定与 X 服务器的连接。
  • name :指定扩展的名称。

此函数用于判断指定名称的扩展是否存在。若存在,会为维护该连接上的扩展信息分配存储空间,将其链接到该连接的扩展列表中,然后返回存根实现者访问该扩展所需的信息;若扩展不存在,则返回 NULL 。同样,若扩展名称不是以主机可移植字符编码表示,结果将取决于具体实现,且大小写有别。 XExtCodes 结构体中的扩展编号在后续调用中是必需的,该编号仅在单个连接中是唯一的。

3.3 XAddExtension 函数

XExtCodes *XAddExtension(Display *display);
  • display :指定与 X 服务器的连接。

对于本地 Xlib 扩展,该函数会分配 XExtCodes 结构体,增加扩展编号计数,并将扩展链接到扩展列表中,这样就可以在不要求服务器扩展的情况下对 Xlib 进行扩展。

下面是挂钩到 Xlib 的操作步骤列表:
1. 存根检查是否在连接上初始化。
2. 若未初始化,调用 XInitExtension 进行初始化。
3. 根据需要使用 XAddExtension 进行本地扩展。

Xlib 扩展开发指南

4. 库的钩子函数

这些函数允许你定义在各种情况下被调用的过程,包括图形上下文(GC)的创建、复制、释放,字体的创建和释放,扩展定义的事件在网络格式和主机格式之间的转换,以及错误处理等。所有这些函数都会返回之前为该扩展定义的过程。

4.1 XESetCloseDisplay 函数

int XESetCloseDisplay(Display *display, int extension, int (*proc)());
  • display :指定与 X 服务器的连接。
  • extension :指定扩展编号。
  • proc :指定在关闭显示时调用的过程。

该函数定义了在调用 XCloseDisplay 时要调用的过程,返回之前定义的过程,通常为 NULL 。当 XCloseDisplay 被调用时,你的过程会以如下参数被调用:

int (*proc)(Display *display, XExtCodes *codes);

4.2 XESetCreateGC 函数

int *XESetCreateGC(Display *display, int extension, int (*proc)());
  • display :指定与 X 服务器的连接。
  • extension :指定扩展编号。
  • proc :指定在创建新 GC 时调用的过程。

此函数定义了在创建新 GC 时要调用的过程,返回之前定义的过程,通常为 NULL 。当创建 GC 时,你的过程会以如下参数被调用:

int (*proc)(Display *display, GC gc, XExtCodes *codes);

4.3 XESetCopyGC 函数

int *XESetCopyGC(Display *display, int extension, int (*proc)());
  • display :指定与 X 服务器的连接。
  • extension :指定扩展编号。
  • proc :指定在复制 GC 组件时调用的过程。

该函数定义了在复制 GC 时要调用的过程,返回之前定义的过程,通常为 NULL 。当复制 GC 时,你的过程会以如下参数被调用:

int (*proc)(Display *display, GC gc, XExtCodes *codes);

4.4 XESetFreeGC 函数

int *XESetFreeGC(Display *display, int extension, int (*proc)());
  • display :指定与 X 服务器的连接。
  • extension :指定扩展编号。
  • proc :指定在释放 GC 时调用的过程。

此函数定义了在释放 GC 时要调用的过程,返回之前定义的过程,通常为 NULL 。当释放 GC 时,你的过程会以如下参数被调用:

int (*proc)(Display *display, GC gc, XExtCodes *codes);

4.5 XESetCreateFont 函数

int *XESetCreateFont(Display *display, int extension, int (*proc)());
  • display :指定与 X 服务器的连接。
  • extension :指定扩展编号。
  • proc :指定在创建字体时调用的过程。

该函数定义了在调用 XLoadQueryFont XQueryFont 时要调用的过程,返回之前定义的过程,通常为 NULL 。当调用 XLoadQueryFont XQueryFont 时,你的过程会以如下参数被调用:

int (*proc)(Display *display, XFontStruct *fs, XExtCodes *codes);

4.6 XESetFreeFont 函数

int *XESetFreeFont(Display *display, int extension, int (*proc)());
  • display :指定与 X 服务器的连接。
  • extension :指定扩展编号。
  • proc :指定在释放字体时调用的过程。

此函数定义了在调用 XFreeFont 时要调用的过程,返回之前定义的过程,通常为 NULL 。当调用 XFreeFont 时,你的过程会以如下参数被调用:

int (*proc)(Display *display, XFontStruct *fs, XExtCodes *codes);

4.7 XESetWireToEvent 函数

int *XESetWireToEvent(Display *display, int event_number, int (*proc)());
  • display :指定与 X 服务器的连接。
  • event_number :指定事件代码。
  • proc :指定在转换事件时调用的过程。

该函数定义了在将事件从网络格式( xEvent )转换为主机格式( XEvent )时要调用的过程。事件编号定义了要为哪个协议事件编号安装转换过程。 XESetWireToEvent 返回之前定义的过程。你可以用自己的函数替换核心事件转换函数,但不建议这样做。当 Xlib 需要将事件从网络格式转换为主机格式时,你的过程会以如下参数被调用:

int (*proc)(Display *display, XEvent *re, xEvent *event);

你的过程必须返回状态以指示转换是否成功。 re 参数是指向应存储主机格式事件的位置的指针, event 参数是 32 字节的网络事件结构。在你创建的 XEvent 结构中,必须填充事件结构的五个必需成员。你应该用为 xEvent 结构指定的类型填充 type 成员,并将所有其他成员从 xEvent 结构(网络格式)复制到 XEvent 结构(主机格式)。如果事件应放入队列,则转换过程应返回 True ;否则返回 False 。要初始化事件的序列号组件,请调用 _XSetLastRequestRead 并使用返回值。

4.8 _XSetLastRequestRead 函数

unsigned long _XSetLastRequestRead(Display *display, xEvent *rep);
  • display :指定与 X 服务器的连接。
  • rep :指定网络事件结构。

该函数从事件中的部分序列号计算并返回完整的序列号。

4.9 XESetEventToWire 函数

unsigned long *XESetEventToWire(Display *display, int event_number, unsigned long (*proc)());
  • display :指定与 X 服务器的连接。
  • event_number :指定事件代码。
  • proc :指定在转换事件时调用的过程。

此函数定义了在将事件从主机格式( XEvent )转换为网络格式( xEvent )时要调用的过程。事件编号定义了要为哪个协议事件编号安装转换过程。 XESetEventToWire 返回之前定义的过程。当 Xlib 需要将事件从主机格式转换为网络格式时,你的过程会以如下参数被调用:

unsigned long (*proc)(Display *display, XEvent *re, xEvent *event);

re 参数是指向主机格式事件的指针, event 参数是指向应存储 32 字节网络事件结构的位置的指针。你应该用 XEvent 结构中的类型填充 type ,然后将所有其他成员从主机格式复制到 xEvent 结构。

4.10 XESetWireToError 函数

Bool *XESetWireToError(Display *display, int error_number, Bool (*proc)());
  • display :指定与 X 服务器的连接。
  • error_number :指定错误代码。
  • proc :指定在收到错误时调用的过程。

该函数定义了在将扩展错误从网络格式转换为主机格式时要调用的过程。错误编号定义了要为哪个协议错误代码安装转换过程。 XESetWireToError 返回之前定义的过程。当 Xlib 需要将错误从网络格式转换为主机格式时,过程会以如下参数被调用:

int (*proc)(Display *display, XErrorEvent *he, xError *we);

he 参数是指向应存储主机格式错误的位置的指针。 he 指向的结构保证与 XEvent 结构一样大,因此可以转换为比 XErrorEvent 更大的类型以存储额外的值。如果 Xlib 要完全忽略该错误(例如,几个协议错误结构将合并为一个 Xlib 错误),则函数应返回 False ;否则应返回 True

4.11 XESetError 函数

int *XESetError(Display *display, int extension, int (*proc)());
  • display :指定与 X 服务器的连接。
  • extension :指定扩展编号。
  • proc :指定在收到错误时调用的过程。

在 Xlib 内部,有时你可能希望在发生错误时抑制外部错误处理的调用。这允许在调用时返回状态,但代价是调用变为同步(不过大多数此类函数是查询操作,无论如何通常都会编程为同步)。当 Xlib 在 _XReply 中检测到协议错误时,你的过程会以如下参数被调用:

int (*proc)(Display *display, xError *err, XExtCodes *codes, int ret_code);

err 参数是指向 32 字节网络格式错误的指针。 codes 参数是指向扩展代码结构的指针。 ret_code 参数是你可能希望 _XReply 返回的值。如果你的过程返回 0 值,则不抑制错误,调用客户端的错误处理程序;如果返回非零值,则抑制错误, _XReply 返回 ret_code 的值。

4.12 XESetErrorString 函数

char *XESetErrorString(Display *display, int extension, char (*proc)());
  • display :指定与 X 服务器的连接。
  • extension :指定扩展编号。
  • proc :指定获取错误字符串时调用的过程。

XGetErrorText 函数为用户返回错误的字符串。 XESetErrorString 允许你定义一个过程,该过程应返回指向错误消息的指针。例如:

int (*proc)(Display *display, int code, XExtCodes *codes, char *buffer, int nbytes);

对于检测到的每个错误,你的过程会以错误代码作为参数被调用。你应该将包含错误消息的以空字符结尾的字符串的 nbytes 个字符复制到 buffer 中。

4.13 XESetPrintErrorValues 函数

void *XESetPrintErrorValues(Display *display, int extension, void (*proc)());
  • display :指定与 X 服务器的连接。
  • extension :指定扩展编号。
  • proc :指定在打印错误时调用的过程。

该函数定义了在打印扩展错误时要调用的过程,用于打印错误值。用于包含超出核心 X 错误的额外错误值的扩展错误。返回之前定义的过程。当 Xlib 需要打印错误时,过程会以如下参数被调用:

void (*proc)(Display *display, XErrorEvent *ev, FILE *fp);

ev 指向的结构保证与 XEvent 结构一样大,因此可以转换为比 XErrorEvent 更大的类型以获取使用 XESetWireToError 设置的额外值。 fp 参数的底层类型取决于系统;在符合 POSIX 的系统上, fp 应转换为 FILE* 类型。

4.14 XESetFlushGC 函数

int *XESetFlushGC(Display *display, int extension, int (*proc)());
  • display :指定与 X 服务器的连接。
  • extension :指定扩展编号。
  • proc :指定在刷新 GC 时调用的过程。

该函数设置的过程与 XESetCopyGC 函数设置的过程具有相同的接口,但在服务器中需要更新 GC 缓存时调用。

4.15 XESetBeforeFlush 函数

int *XESetBeforeFlush(Display *display, int extension, void (*proc)());
  • display :指定与 X 服务器的连接。
  • extension :指定扩展编号。
  • proc :指定在数据即将发送到服务器时调用的过程。

当数据即将发送时,你的过程会以如下参数被调用一次或多次:

void (*proc)(Display *display, XExtCodes *codes, char *data, int len);

data 参数指定传出数据缓冲区的一部分,其长度(以字节为单位)由 len 参数指定。你的过程不能更改数据的内容,也不能对同一显示进行额外的协议请求。

下面是这些钩子函数的使用场景表格:
| 函数名 | 使用场景 |
| ---- | ---- |
| XESetCloseDisplay | 关闭显示时 |
| XESetCreateGC | 创建新 GC 时 |
| XESetCopyGC | 复制 GC 时 |
| XESetFreeGC | 释放 GC 时 |
| XESetCreateFont | 创建字体时 |
| XESetFreeFont | 释放字体时 |
| XESetWireToEvent | 事件从网络格式转换为主机格式时 |
| XESetEventToWire | 事件从主机格式转换为网络格式时 |
| XESetWireToError | 错误从网络格式转换为主机格式时 |
| XESetError | 检测到协议错误时 |
| XESetErrorString | 获取错误字符串时 |
| XESetPrintErrorValues | 打印扩展错误时 |
| XESetFlushGC | 刷新 GC 时 |
| XESetBeforeFlush | 数据即将发送到服务器时 |

5. 挂钩到 Xlib 数据结构

各种 Xlib 数据结构提供了扩展过程将扩展提供的数据链接到列表的机制。这些结构包括 GC Visual Screen ScreenFormat Display XFontStruct 。由于列表指针总是结构中的第一个成员,因此可以使用一组单一的过程来操作这些列表上的数据。

5.1 XExtData 结构体

typedef struct _XExtData {
    int number; /* number returned by XInitExtension */
    struct _XExtData *next; /* next item on list of data for structure */
    int (*free_private)(); /* if defined,  called to free private */
    XPointer private_data; /* data private to this extension. */
} XExtData;

当上述任何数据结构被释放时,会遍历列表并调用结构的释放过程(如果有)。如果 free NULL ,则库会释放 private_data 成员指向的数据和结构本身。

5.2 XEDataObject 联合体

union {
    Display *display;
    GC gc;
    Visual *visual;
    Screen *screen;
    ScreenFormat *pixmap_format;
    XFontStruct *font
} XEDataObject;

5.3 XEHeadOfExtensionList 函数

XExtData **XEHeadOfExtensionList(XEDataObject object);
  • object :指定对象。

该函数返回指向附加到指定对象的扩展结构列表的指针。与 XAddToExtensionList 配合使用, XEHeadOfExtensionList 允许扩展将任意数据附加到 XEDataObject 包含的任何类型的结构中。

5.4 XAddToExtensionList 函数

void XAddToExtensionList(void *structure, XExtData *ext_data);
  • structure :指定扩展列表。
  • ext_data :指定要添加的扩展数据结构。

structure 参数是指向上述枚举的数据结构之一的指针。在调用此函数之前,必须用扩展编号初始化 ext_data->number

5.5 XFindOnExtensionList 函数

XExtData *XFindOnExtensionList(void *structure, int number);
  • structure :指定扩展列表。
  • number :指定扩展编号。

该函数用于在扩展列表中查找具有指定扩展编号的扩展数据结构。

下面是操作这些数据结构的步骤列表:
1. 定义 XExtData 结构体并初始化 number 成员。
2. 使用 XEHeadOfExtensionList 获取扩展列表的头指针。
3. 使用 XAddToExtensionList 将扩展数据结构添加到列表中。
4. 使用 XFindOnExtensionList 在列表中查找特定的扩展数据结构。

通过以上这些函数和数据结构,你可以灵活地扩展 Xlib 的功能,满足不同的应用需求。

一、 内容概要 本资源提供了一个完整的“金属板材压弯成型”非线性仿真案例,基于ABAQUS/Explicit或Standard求解器完成。案例精确模拟了模具(凸模、凹模)与金属板材之间的接触、压合过程,直至板材发生塑性弯曲成型。 模型特点:包含完整的模具-工件装配体,定义了刚体约束、通用接触(或面面接触)及摩擦系数。 材料定义:金属板材采用弹塑性材料模型,定义了完整的屈服强度、塑性应变等真实应力-应变数据。 关键结果:提供了成型过程中的板材应力(Mises应力)、塑性应变(PE)、厚度变化​ 云图,以及模具受力(接触力)曲线,完整再现了压弯工艺的力学状态。 二、 适用人群 CAE工程师/工艺工程师:从事钣金冲压、模具设计、金属成型工艺分析与优化的专业人员。 高校师生:学习ABAQUS非线性分析、金属塑性成形理论,或从事相关课题研究的硕士/博士生。 结构设计工程师:需要评估钣金件可制造性(DFM)或预测成型回弹的设计人员。 三、 使用场景及目标 学习目标: 掌握在ABAQUS中设置金属塑性成形仿真的全流程,包括材料定义、复杂接触设置、边界条件与载荷步。 学习如何调试和分析大变形、非线性接触问题的收敛性技巧。 理解如何通过仿真预测成型缺陷(如减薄、破裂、回弹),并与理论或实验进行对比验证。 应用价值:本案例的建模方法与分析思路可直接应用于汽车覆盖件、电器外壳、结构件等钣金产品的冲压工艺开发与模具设计优化,减少试模成本。 四、 其他说明 资源包内包含参数化的INP文件、CAE模型文件、材料数据参考及一份简要的操作要点说明文档。INP文件便于用户直接修改关键参数(如压边力、摩擦系数、行程)进行自主研究。 建议使用ABAQUS 2022或更高版本打开。显式动力学分析(如用Explicit)对计算资源有一定要求。 本案例为教学与工程参考目的提供,用户可基于此框架进行拓展,应用于V型弯曲
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值