linux 使用X11监听窗口
·
前言
在 Linux 桌面环境中,窗口管理是 GUI 应用开发中的重要组成部分。X Window System(X11)作为 Linux 桌面环境的显示服务器协议,提供了丰富的窗口管理功能。
今天,我们将深入探讨如何使用 X11 监听窗口事件,实现窗口状态监控、自动化操作等高级功能。
X11 基础概念
1.1 X Window System 架构
X11 采用客户端-服务器架构:
- X Server: 管理显示硬件和输入设备
- X Client: 应用程序,通过 X 协议与服务器通信
- Xlib/XCB: 客户端库,提供编程接口
1.2 窗口与事件模型
X11 中所有GUI元素都是窗口,采用树状结构组织。事件驱动机制是 X11 的核心,包括:
- 键盘/鼠标输入事件
- 窗口状态变更事件
- 属性更改事件等
X11 窗口监听实现
2.1 建立连接
int main()
{
Display *display = XOpenDisplay(NULL);
if (!display) {
fprintf(stderr, "无法打开 X 显示\n");
return -1;
}
Window root = DefaultRootWindow(display);
printf("成功连接到 X Server\n");
printf("根窗口 ID: %lu\n", root_window);
// ...
XCloseDisplay(display);
return 0;
}
2.2 监听窗口事件
// 监听窗口属性和子窗口结构变化
XSelectInput(display, root, PropertyChangeMask | SubstructureNotifyMask);
// 等待请求完成
XSync(display, False);
XEvent event;
while (1) {
XNextEvent(display, &event);
switch (event.type) {
case PropertyNotify:
break;
case ConfigureNotify:
break;
default:
break;
}
}
2.3 获取窗口属性信息
void print_window_info(Display *display, Window window) {
Atom atom_type;
int format;
unsigned long nitems, bytes_after;
unsigned char *data = NULL;
// 获取窗口标题
Atom atom_name = XInternAtom(display, "_NET_WM_NAME", False);
if (XGetWindowProperty(display, window, atom_name, 0, 1024,
False, AnyPropertyType, &atom_type,
&format, &nitems, &bytes_after,
&data) == Success && data) {
printf("窗口标题: %s\n", data);
XFree(data);
}
// 获取窗口进程
Atom atom_pid = XInternAtom(display, "_NET_WM_PID", False);
if (XGetWindowProperty(display, window, atom_pid, 0, 1024,
False, XA_CARDINAL, &atom_type,
&format, &nitems, &bytes_after,
&data) == Success && data) {
printf("所属进程: %d\n", *((pid_t*)data););
XFree(data);
}
// 获取窗口几何属性
XWindowAttributes attr;
if (XGetWindowAttributes(display, window, &attr)) {
int x_abs, y_abs;
Window child_return;
// 将相对坐标转换为绝对坐标
if (XTranslateCoordinates(
display, window, DefaultRootWindow(display), 0, 0,
&x_abs, &y_abs, &child_return)) {
printf("位置: %dx%d 大小: %dx%d\n",
x_abs, y_abs, attr.width, attr.height);
}
}
}
高级监听功能
3.1 监听活动窗口
XSelectInput(display, root, PropertyChangeMask);
// 监听活动窗口ID
Atom active_window_atom =
XInternAtom(display, "_NET_ACTIVE_WINDOW", False);
XEvent event;
while (1) {
XNextEvent(display, &event);
if (event.type == PropertyNotify &&
event.xproperty.atom == active_window_atom) {
// 获取当前活动窗口
Atom type;
int format;
unsigned long nitems, bytes_after;
unsigned char* data = NULL;
// 从根窗口获取活动窗口属性
int status =
XGetWindowProperty(display, root, active_window_atom,
0, // long_offset
1, // long_length
False, // delete
XA_WINDOW, // req_type
&type, &format, &nitems, &bytes_after, &data);
if (status == Success && data) {
Window active_window = *((Window*)data);
printf("活动窗口变更: %lu\n", active_window);
}
if (data) XFree(data);
}
}
3.2 监听窗口属性变化
XSelectInput(display, root, SubstructureNotifyMask);
XEvent event;
while (1) {
XNextEvent(display, &event);
if (event.type == ConfigureNotify ) {
// 这里event.xconfigure.window中的窗口并不指向当前活动窗口.
// 因此,想要实时获取窗口大小需要调用print_window_info()
printf("窗口大小/位置变化: ID=%lu, %dx%d @ %d,%d\n",
event.xconfigure.window,
event.xconfigure.width,
event.xconfigure.height,
event.xconfigure.x,
event.xconfigure.y);
}
}
更多推荐




所有评论(0)