feat(backend): 添加创建 bar 窗口接口
This commit is contained in:
@@ -76,6 +76,9 @@ pkg_check_modules(deps REQUIRED
|
||||
xcb-xfixes
|
||||
xcb-xinerama
|
||||
xkbcommon
|
||||
|
||||
cairo
|
||||
cairo-xcb
|
||||
)
|
||||
|
||||
target_include_directories(${APP_NAME} SYSTEM
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "core/backend.h"
|
||||
|
||||
#include <cairo-xcb.h>
|
||||
#include <cairo.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@@ -678,3 +680,70 @@ void backend_scan_result_destroy(backend_scan_result_t *result) {
|
||||
p_delete(&result->windows);
|
||||
p_delete(&result);
|
||||
}
|
||||
|
||||
backend_bar_window_t backend_create_bar_window(
|
||||
backend_t *backend,
|
||||
rect_t geometry,
|
||||
uint32_t bg_pixel
|
||||
) {
|
||||
auto conn = backend->conn;
|
||||
auto root = backend->screen->root;
|
||||
auto visual = window_get_visual(backend, true);
|
||||
|
||||
xcb_grab_server(conn);
|
||||
window_clean_event_mask(conn, root);
|
||||
|
||||
auto window_id = xcb_generate_id(conn);
|
||||
uint16_t _class = XCB_WINDOW_CLASS_INPUT_OUTPUT;
|
||||
uint32_t event_mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_BACK_PIXEL |
|
||||
XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK;
|
||||
|
||||
const xcb_create_window_value_list_t value_list = {
|
||||
.override_redirect = true,
|
||||
.background_pixel = bg_pixel,
|
||||
.border_pixel = 0,
|
||||
.event_mask = XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_EXPOSURE,
|
||||
};
|
||||
auto cookie = xcb_create_window_aux_checked(
|
||||
conn,
|
||||
visual->depth,
|
||||
window_id,
|
||||
root,
|
||||
geometry.x,
|
||||
geometry.y,
|
||||
geometry.width,
|
||||
geometry.height,
|
||||
0,
|
||||
_class,
|
||||
visual->visual->visual_id,
|
||||
event_mask,
|
||||
&value_list
|
||||
);
|
||||
if (xcb_request_check(conn, cookie)) fatal("cannot create bar window");
|
||||
|
||||
cookie = xcb_map_window_checked(conn, window_id);
|
||||
if (xcb_request_check(conn, cookie)) fatal("cannot map bar window");
|
||||
|
||||
window_set_class_instance(conn, window_id);
|
||||
window_set_name_static(conn, window_id, APP_NAME "_bar");
|
||||
|
||||
root_set_event_mask(backend);
|
||||
xcb_ungrab_server(conn);
|
||||
xcb_aux_sync(conn);
|
||||
|
||||
auto width = geometry.width;
|
||||
auto height = geometry.height;
|
||||
auto vid = visual->visual;
|
||||
auto surface = cairo_xcb_surface_create(conn, window_id, vid, width, height);
|
||||
auto cr = cairo_create(surface);
|
||||
|
||||
cairo_surface_destroy(surface);
|
||||
p_delete(&visual);
|
||||
|
||||
auto statue = cairo_status(cr);
|
||||
if (statue != CAIRO_STATUS_SUCCESS) {
|
||||
fatal("cannot create cairo context: %s", cairo_status_to_string(statue));
|
||||
}
|
||||
|
||||
return (backend_bar_window_t){.window_id = window_id, .cr = cr};
|
||||
}
|
||||
|
||||
@@ -405,3 +405,49 @@ void window_grab_keys(
|
||||
p_delete(&keycodes);
|
||||
}
|
||||
}
|
||||
|
||||
static visual_t *get_alpha_visual(backend_t *backend) {
|
||||
auto depth_iter = xcb_screen_allowed_depths_iterator(backend->screen);
|
||||
for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
|
||||
if (depth_iter.data->depth != 32) continue;
|
||||
|
||||
auto visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
|
||||
for (; visual_iter.rem; xcb_visualtype_next(&visual_iter)) {
|
||||
if (visual_iter.data->_class == XCB_VISUAL_CLASS_TRUE_COLOR) {
|
||||
auto visual = p_new(visual_t, 1);
|
||||
visual->visual = visual_iter.data;
|
||||
visual->depth = depth_iter.data->depth;
|
||||
return visual;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static visual_t *get_root_visual(backend_t *backend) {
|
||||
auto depth_iter = xcb_screen_allowed_depths_iterator(backend->screen);
|
||||
auto visual_id = backend->screen->root_visual;
|
||||
for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
|
||||
auto visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
|
||||
for (; visual_iter.rem; xcb_visualtype_next(&visual_iter)) {
|
||||
if (visual_iter.data->visual_id == visual_id) {
|
||||
auto visual = p_new(visual_t, 1);
|
||||
visual->visual = visual_iter.data;
|
||||
visual->depth = depth_iter.data->depth;
|
||||
return visual;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
visual_t *window_get_visual(backend_t *backend, bool prefer_alpha) {
|
||||
if (!prefer_alpha) return get_root_visual(backend);
|
||||
|
||||
auto visual = get_alpha_visual(backend);
|
||||
if (!visual) visual = get_root_visual(backend);
|
||||
|
||||
return visual;
|
||||
}
|
||||
|
||||
@@ -104,3 +104,17 @@ void window_grab_keys(
|
||||
const key_bind_t *keys,
|
||||
size_t count
|
||||
);
|
||||
|
||||
typedef struct visual_t {
|
||||
uint8_t depth;
|
||||
xcb_visualtype_t *visual;
|
||||
} visual_t;
|
||||
|
||||
/**
|
||||
* @brief 获取 xcb 的 visual 及其对应的 depth
|
||||
*
|
||||
* @param prefer_alpha 支持 alpha 的 visual 优先
|
||||
*
|
||||
* @returns 返回的信息使用后记得使用 free 释放
|
||||
*/
|
||||
visual_t *window_get_visual(backend_t *backend, bool prefer_alpha);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cairo.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "core/event.h"
|
||||
@@ -51,3 +52,14 @@ typedef struct backend_scan_result_t {
|
||||
*/
|
||||
backend_scan_result_t *backend_scan_windows(backend_t *backend);
|
||||
void backend_scan_result_destroy(backend_scan_result_t *result);
|
||||
|
||||
typedef struct backend_bar_window_t {
|
||||
window_id_t window_id;
|
||||
cairo_t *cr;
|
||||
} backend_bar_window_t;
|
||||
|
||||
backend_bar_window_t backend_create_bar_window(
|
||||
backend_t *backend,
|
||||
rect_t geometry,
|
||||
uint32_t bg_pixel
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user