diff --git a/CMakeLists.txt b/CMakeLists.txt index e8bbfed..37a0bda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,9 @@ pkg_check_modules(deps REQUIRED xcb-xfixes xcb-xinerama xkbcommon + + cairo + cairo-xcb ) target_include_directories(${APP_NAME} SYSTEM diff --git a/src/backend/x11/backend.c b/src/backend/x11/backend.c index fbf44ba..8fe9cd8 100644 --- a/src/backend/x11/backend.c +++ b/src/backend/x11/backend.c @@ -1,5 +1,7 @@ #include "core/backend.h" +#include +#include #include #include #include @@ -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}; +} diff --git a/src/backend/x11/window.c b/src/backend/x11/window.c index 67c3572..8284ba9 100644 --- a/src/backend/x11/window.c +++ b/src/backend/x11/window.c @@ -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; +} diff --git a/src/backend/x11/window.h b/src/backend/x11/window.h index 1227f88..5df4223 100644 --- a/src/backend/x11/window.h +++ b/src/backend/x11/window.h @@ -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); diff --git a/src/core/backend.h b/src/core/backend.h index 9b5b571..71e3c45 100644 --- a/src/core/backend.h +++ b/src/core/backend.h @@ -1,5 +1,6 @@ #pragma once +#include #include #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 +);