gpt4 book ai didi

linux - 直接打开到 Xserver 的套接字

转载 作者:太空狗 更新时间:2023-10-29 11:38:58 26 4
gpt4 key购买 nike

我想了解 Linux 桌面环境如何与 Xserver 一起工作。我读到大多数窗口管理器不直接打开套接字,而是使用 Xlib 绑定(bind)​​ WM 正在编写的任何语言,或者您可以使用更高级别的绑定(bind) XCB;但我想知道直接向 Xserver 打开套接字有什么好处?

最佳答案

我不会告诉你优点,但我会告诉你怎么做。

前段时间我找到了这个人的一个例子,现在找不到了,但这里或多或少是他的代码。了解 XCB 等客户端库的幕后情况非常有趣。

为了向 X 服务器发送请求,您需要:

  1. 到 X 服务器的套接字连接
  2. 请求的操作码
  3. 与请求相关的数据

打开套接字、创建图形上下文、创建窗口和映射窗口的 API 类似于:

x11_connection_t connection = {0};
x11_init_connection(&connection);

x11_state_t state;
state.socket_fd = connection.socket_fd;
state.id_base = connection.setup->id_base;
state.root_window = connection.root[0].window_id;
state.root_visual = connection.root[0].visual_id;
state.root_depth = connection.root[0].depth;

state.gcontext = x11_init_gc(&state, X11_GC_GRAPHICS_EXPOSURES, (u32[]){X11_EXPOSURES_NOT_ALLOWED});

state.window = x11_init_window(&state, 0,0, WIDTH,HEIGHT, state.root_window, state.root_visual,
X11_CW_BACK_PIXEL | X11_CW_EVENT_MASK,
(u32[]){XCB_RGB_BLUE, X11_EVENT_MASK_KEY_PRESS | X11_EVENT_MASK_POINTER_MOTION}); // X11_EVENT_MASK_KEY_PRESS | X11_EVENT_MASK_POINTER_MOTION | X11_EVENT_MASK_STRUCTURE_NOTIFY | X11_EVENT_MASK_EXPOSURE
x11_map_window(&state, state.window);

但首先我们需要实现它。


为了说明,这里是前 13 个 X 协议(protocol)操作码:

#define X11_OPCODE_CREATE_WINDOW                1
#define X11_OPCODE_CHANGE_WINDOW_ATTRIBUTES 2
#define X11_OPCODE_GET_WINDOW_ATTRIBUTES 3
#define X11_OPCODE_DESTROY_WINDOW 4
#define X11_OPCODE_DESTROY_SUBWINDOWS 5
#define X11_OPCODE_CHANGE_SAVE_SET 6
#define X11_OPCODE_REPARENT_WINDOW 7
#define X11_OPCODE_MAP_WINDOW 8
#define X11_OPCODE_MAP_SUBWINDOWS 9
#define X11_OPCODE_UNMAP_WINDOW 10
#define X11_OPCODE_UNMAP_SUBWINDOWS 11
#define X11_OPCODE_CONFIGURE_WINDOW 12
#define X11_OPCODE_CIRCULATE_WINDOW 13

您可以使用如下函数打开套接字,

int x11_init_socket(){
int socket_fd = socket(AF_UNIX, SOCK_STREAM, 0); // Create the socket!
struct sockaddr_un serv_addr = {0};
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, "/tmp/.X11-unix/X0");
int srv_len = sizeof(struct sockaddr_un);
connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
return socket_fd;
}

然后你需要握手,

int x11_init_connection(x11_connection_t* connection){
connection->socket_fd = x11_init_socket();

x11_connection_request_t request = {0};
request.order = 'l'; // Little endian!
request.major = 11;
request.minor = 0; // Version 11.0
write(connection->socket_fd, &request, sizeof(x11_connection_request_t)); // Send request
read(connection->socket_fd, &connection->header, sizeof(x11_connection_reply_t)); // Read reply header
if(connection->header.success == 0) return connection->header.success; // Error handling!

connection->setup = sbrk(connection->header.length * 4); // Allocate memory for remainder of data
read(connection->socket_fd, connection->setup, connection->header.length * 4); // Read remainder of data

void* p = ((void*)connection->setup);
p += sizeof(x11_connection_setup_t) + connection->setup->vendor_length; // Ignore the vendor
connection->format = p; p += sizeof(x11_pixmap_format_t) * connection->setup->formats; // Align struct with format sections. Move pointer to end of section
connection->root = p; p += sizeof(x11_root_t) * connection->setup->roots; // Align struct with root section(s). Move pointer to end of section
connection->depth = p; p += sizeof(x11_depth_t); // Align depth struct with first depth section. Move pointer to end of section
connection->visual = p; // Align visual with first visual for first depth

return connection->header.success;
}

以及X服务器喜欢的一堆数据结构:

typedef struct{
u8 order;
u8 pad1;
u16 major, minor;
u16 auth_proto, auth_data;
u16 pad2;
}x11_connection_request_t;

typedef struct{
u8 success;
u8 pad1;
u16 major, minor;
u16 length;
}x11_connection_reply_t;

typedef struct{
u32 release;
u32 id_base, id_mask;
u32 motion_buffer_size;
u16 vendor_length;
u16 request_max;
u8 roots;
u8 formats;
u8 image_order;
u8 bitmap_order;
u8 scanline_unit, scanline_pad;
u8 keycode_min, keycode_max;
u32 pad;
}x11_connection_setup_t;

typedef struct{
u8 depth;
u8 bpp;
u8 scanline_pad;
u8 pad1;
u32 pad2;
}x11_pixmap_format_t;

typedef struct{
u32 window_id;
u32 colormap;
u32 white, black;
u32 input_mask;
u16 width, height;
u16 width_mm, height_mm;
u16 maps_min, maps_max;
u32 visual_id;
u8 backing_store;
u8 save_unders;
u8 depth;
u8 depths;
}x11_root_t;

typedef struct{
u8 depth;
u8 pad1;
u16 visuals;
u32 pad2;
}x11_depth_t;

typedef struct{
u8 group;
u8 bits;
u16 colormap_entries;
u32 mask_red, mask_green, mask_blue;
u32 pad;
}x11_visual_t;

typedef struct{
u8 response_type; /**< Type of the response */
u8 pad0; /**< Padding */
u16 sequence; /**< Sequence number */
u32 pad[7]; /**< Padding */
u32 full_sequence; /**< full sequence */
}x11_generic_event_t;

typedef struct{
u8 success;
u8 code;
u16 seq;
u32 id;
u16 op_major;
u8 op_minor;
u8 pad[21];
}x11_error_t;

typedef struct{
int socket_fd;
x11_connection_reply_t header;
x11_connection_setup_t* setup;
x11_pixmap_format_t* format;
x11_root_t* root;
x11_depth_t* depth;
x11_visual_t* visual;
}x11_connection_t;

typedef struct{
int socket_fd;
u32 id_base; // We'll use this to generate 32-bit identifiers!

u32 root_window;
u32 root_visual;
u8 root_depth;

u32 window;
u32 gcontext;
}x11_state_t;

您还需要一个函数来生成 32 位标识符:

u32 x11_generate_id(x11_connection_t* connection){
static u32 id = 0;
return (id++ | connection->setup->id_base);
}

最后,您需要将数据包与请求组合在一起的实际函数。以下是用于发送 X11_OPCODE_CREATE_GCX11_OPCODE_CREATE_WINDOWX11_OPCODE_MAP_WINDOWX11_OPCODE_PUT_IMAGE 的辅助函数。

#define X11_NONE             0x00000000L  // X11_NONE is the universal null resource or null atom parameter value for many core X requests
#define X11_COPY_FROM_PARENT 0x00000000L // X11_COPY_FROM_PARENT can be used for many xcb_create_window parameters
#define X11_CURRENT_TIME 0x00000000L // X11_CURRENT_TIME can be used in most requests that take an xcb_timestamp_t
#define X11_NO_SYMBOL 0x00000000L // X11_NO_SYMBOL fills in unused entries in xcb_keysym_t tables

enum x11_exposures_t{
X11_EXPOSURES_NOT_ALLOWED = 0,
X11_EXPOSURES_ALLOWED = 1,
X11_EXPOSURES_DEFAULT = 2
};

enum x11_gc_t{
X11_GC_FUNCTION = 1<<0,
X11_GC_PLANE_MASK = 1<<1,
X11_GC_FOREGROUND = 1<<2,
X11_GC_BACKGROUND = 1<<3,
X11_GC_LINE_WIDTH = 1<<4,
X11_GC_LINE_STYLE = 1<<5,
X11_GC_CAP_STYLE = 1<<6,
X11_GC_JOIN_STYLE = 1<<7,
X11_GC_FILL_STYLE = 1<<8,
X11_GC_FILL_RULE = 1<<9,
X11_GC_TILE = 1<<10,
X11_GC_STIPPLE = 1<<11,
X11_GC_TILE_STIPPLE_ORIGIN_X = 1<<12,
X11_GC_TILE_STIPPLE_ORIGIN_Y = 1<<13,
X11_GC_FONT = 1<<14,
X11_GC_SUBWINDOW_MODE = 1<<15,
X11_GC_GRAPHICS_EXPOSURES = 1<<16,
X11_GC_CLIP_ORIGIN_X = 1<<17,
X11_GC_CLIP_ORIGIN_Y = 1<<18,
X11_GC_CLIP_MASK = 1<<19,
X11_GC_DASH_OFFSET = 1<<20,
X11_GC_DASH_LIST = 1<<21,
X11_GC_ARC_MODE = 1<<22,
};

u32 x11_init_gc(x11_state_t* state, u32 value_mask, u32* value_list){
u32 gcontext_id = x11_generate_id(state);

u16 flag_count = popcnt(value_mask);
u16 length = 4 + flag_count;
u32* packet = sbrk(length * 4);

packet[0] = X11_OPCODE_CREATE_GC | (length<<16); // The first `u32` in the packet is always the opcode and the length of the packet!
packet[1] = gcontext_id;
packet[2] = state->root_window;
packet[3] = value_mask;
for(int i=0; i < flag_count; ++i)
packet[4 + i] = value_list[i];

write(state->socket_fd, packet, length * 4);
sbrk(-(length * 4));

return gcontext_id;
}

enum x11_cw_t{
X11_CW_BACK_PIXMAP = 1<<0,
X11_CW_BACK_PIXEL = 1<<1,
X11_CW_BORDER_PIXMAP = 1<<2,
X11_CW_BORDER_PIXEL = 1<<3,
X11_CW_BIT_GRAVITY = 1<<4,
X11_CW_WIN_GRAVITY = 1<<5,
X11_CW_BACKING_STORE = 1<<6,
X11_CW_BACKING_PLANES = 1<<7,
X11_CW_BACKING_PIXEL = 1<<8,
X11_CW_OVERRIDE_REDIRECT = 1<<9,
X11_CW_SAVE_UNDER = 1<<10,
X11_CW_EVENT_MASK = 1<<11,
X11_CW_DONT_PROPAGATE = 1<<12,
X11_CW_COLORMAP = 1<<13,
X11_CW_CURSOR = 1<<14
};

enum x11_event_mask_t{
X11_EVENT_MASK_NO_EVENT = 0,
X11_EVENT_MASK_KEY_PRESS = 1<<0, // 0x00000001
X11_EVENT_MASK_KEY_RELEASE = 1<<1, // 0x00000002
X11_EVENT_MASK_BUTTON_PRESS = 1<<2, // 0x00000004
X11_EVENT_MASK_BUTTON_RELEASE = 1<<3, // 0x00000008
X11_EVENT_MASK_ENTER_WINDOW = 1<<4, // 0x00000010
X11_EVENT_MASK_LEAVE_WINDOW = 1<<5, // 0x00000020
X11_EVENT_MASK_POINTER_MOTION = 1<<6, // 0x00000040
X11_EVENT_MASK_POINTER_MOTION_HINT = 1<<7, // 0x00000080
X11_EVENT_MASK_BUTTON_1_MOTION = 1<<8, // 0x00000100
X11_EVENT_MASK_BUTTON_2_MOTION = 1<<9, // 0x00000200
X11_EVENT_MASK_BUTTON_3_MOTION = 1<<10, // 0x00000400
X11_EVENT_MASK_BUTTON_4_MOTION = 1<<11, // 0x00000800
X11_EVENT_MASK_BUTTON_5_MOTION = 1<<12, // 0x00001000
X11_EVENT_MASK_BUTTON_MOTION = 1<<13, // 0x00002000
X11_EVENT_MASK_KEYMAP_STATE = 1<<14, // 0x00004000
X11_EVENT_MASK_EXPOSURE = 1<<15, // 0x00008000
X11_EVENT_MASK_VISIBILITY_CHANGE = 1<<16, // 0x00010000
X11_EVENT_MASK_STRUCTURE_NOTIFY = 1<<17, // 0x00020000
X11_EVENT_MASK_RESIZE_REDIRECT = 1<<18, // 0x00040000
X11_EVENT_MASK_SUBSTRUCTURE_NOTIFY = 1<<19, // 0x00080000
X11_EVENT_MASK_SUBSTRUCTURE_REDIRECT = 1<<20, // 0x00100000
X11_EVENT_MASK_FOCUS_CHANGE = 1<<21, // 0x00200000
X11_EVENT_MASK_PROPERTY_CHANGE = 1<<22, // 0x00400000
X11_EVENT_MASK_COLOR_MAP_CHANGE = 1<<23, // 0x00800000
X11_EVENT_MASK_OWNER_GRAB_BUTTON = 1<<24 // 0x01000000
};

#define X11_DEFAULT_BORDER 0
#define X11_DEFAULT_GROUP 0

u32 x11_init_window(x11_state_t* state, u16 x, u16 y, u16 w, u16 h, u32 window_parent, u32 visual, u32 value_mask, u32* value_list){
u32 window_id = x11_generate_id(state);

u16 flag_count = popcnt(value_mask);
u16 length = 8 + flag_count;
u32* packet = sbrk(length * 4);

packet[0] = X11_OPCODE_CREATE_WINDOW | length<<16; // The first `u32` in the packet is always the opcode and the length of the packet!
packet[1] = window_id;
packet[2] = window_parent;
packet[3] = x | (y<<16);
packet[4] = w | (h<<16);
packet[5] = (X11_DEFAULT_BORDER<<16) | X11_DEFAULT_GROUP;
packet[6] = visual;
packet[7] = value_mask;
for(int i=0;i < flag_count; ++i)
packet[8 + i] = value_list[i];

write(state->socket_fd, packet, length * 4);
sbrk(-(length * 4));

return window_id;
}

void x11_map_window(x11_state_t* state, u32 window_id){
int const length = 2;
u32 packet[length];
packet[0] = X11_OPCODE_MAP_WINDOW | (length<<16); // The first `u32` in the packet is always the opcode and the length of the packet!
packet[1] = window_id;
write(state->socket_fd, packet, 8);
}

enum x11_image_format_t{
X11_IMAGE_FORMAT_XY_BITMAP = 0,
X11_IMAGE_FORMAT_XY_PIXMAP = 1,
X11_IMAGE_FORMAT_Z_PIXMAP = 2
};

void x11_put_img(x11_state_t* state, u16 x, u16 y, u32* data){
u32 packet[6];
u16 const length = ((state->tile_width * state->tile_height)) + 6;

packet[0] = X11_OPCODE_PUT_IMAGE | (X11_IMAGE_FORMAT_Z_PIXMAP<<8) | (length<<16); // The first `u32` in the packet is always the opcode and the length of the packet!
packet[1] = state->window;
packet[2] = state->gcontext;
packet[3] = state->tile_width | (state->tile_height<<16);
packet[4] = x | (y<<16);
packet[5] = state->root_depth<<8;

write(state->socket_fd, packet, 24);
write(state->socket_fd, data, state->tile_width * state->tile_height * 4);
}

关于linux - 直接打开到 Xserver 的套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12111861/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com