diff --git a/CMakeLists.txt b/CMakeLists.txt index 8eddaac..881522e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ project(${APP_NAME} add_executable(${APP_NAME} ${SOURCE_DIR}/backend/output_utils.c ${SOURCE_DIR}/backend/x11/backend.c + ${SOURCE_DIR}/backend/x11/cursor.c ${SOURCE_DIR}/backend/x11/event.c ${SOURCE_DIR}/backend/x11/window.c @@ -76,6 +77,7 @@ find_package(PkgConfig REQUIRED) pkg_check_modules(deps REQUIRED xcb xcb-aux + xcb-cursor xcb-icccm xcb-keysyms xcb-randr diff --git a/src/backend/x11/backend.c b/src/backend/x11/backend.c index b8b9247..b7b590e 100644 --- a/src/backend/x11/backend.c +++ b/src/backend/x11/backend.c @@ -18,6 +18,7 @@ #include #include "backend/output_utils.h" +#include "backend/x11/cursor.h" #include "backend/x11/window.h" #include "base/app.h" #include "base/array.h" @@ -184,10 +185,13 @@ backend_t *backend_create(const char *display_name) { backend->key_symbols = xcb_key_symbols_alloc(conn); + cursor_init(backend); atoms_init(backend); create_wm_check_window(backend); create_no_focus_window(backend); + window_change_cursor(backend, root, ZDWM_CURSOR_NORMAL); + return backend; } @@ -204,6 +208,8 @@ void backend_destroy(backend_t *backend) { xcb_key_symbols_free(backend->key_symbols); backend->key_symbols = nullptr; + cursor_cleanup(backend); + xcb_disconnect(backend->conn); backend->conn = nullptr; free(backend); diff --git a/src/backend/x11/cursor.c b/src/backend/x11/cursor.c new file mode 100644 index 0000000..bb2d4b0 --- /dev/null +++ b/src/backend/x11/cursor.c @@ -0,0 +1,51 @@ +#include +#include +#include + +#include "base/macros.h" +#include "base/memory.h" +#include "internal.h" + +static const char *const cursor_name_map[] = { + [ZDWM_CURSOR_NORMAL] = "left_ptr", + [ZDWM_CURSOR_MOVE] = "fleur", + [ZDWM_CURSOR_RESIZE] = "bottom_right_corner", +}; + +static xcb_cursor_context_t *get_xcb_cursor_context(backend_t *backend) { + if (backend->cursor_context) return backend->cursor_context; + + auto conn = backend->conn; + auto screen = backend->screen; + if (xcb_cursor_context_new(conn, screen, &backend->cursor_context) == 0) { + return backend->cursor_context; + } + + return nullptr; +} + +void cursor_init(backend_t *backend) { + auto ctx = get_xcb_cursor_context(backend); + if (!ctx) return; + + for (size_t i = 0; i < countof(backend->cursors); ++i) { + auto cursor_name = cursor_name_map[i]; + backend->cursors[i] = xcb_cursor_load_cursor(ctx, cursor_name); + } +} + +void cursor_cleanup(backend_t *backend) { + constexpr size_t count = countof(backend->cursors); + for (size_t i = 0; i < count; ++i) { + xcb_free_cursor(backend->conn, backend->cursors[i]); + } + p_clear(backend->cursors, count); + xcb_cursor_context_free(backend->cursor_context); + backend->cursor_context = nullptr; +} + +xcb_cursor_t cursor_get_xcb_cursor(backend_t *backend, cursor_t cursor) { + if (backend->cursor_context == nullptr) return XCB_CURSOR_NONE; + + return backend->cursors[cursor]; +} diff --git a/src/backend/x11/cursor.h b/src/backend/x11/cursor.h new file mode 100644 index 0000000..ed6f977 --- /dev/null +++ b/src/backend/x11/cursor.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +#include "internal.h" + +void cursor_init(backend_t *backend); +void cursor_cleanup(backend_t *backend); +xcb_cursor_t cursor_get_xcb_cursor(backend_t *backend, cursor_t cursor); diff --git a/src/backend/x11/internal.h b/src/backend/x11/internal.h index 524c89c..bad8a50 100644 --- a/src/backend/x11/internal.h +++ b/src/backend/x11/internal.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -78,7 +79,14 @@ typedef struct window_configure_list_t { size_t capacity; } window_configure_list_t; -struct backend_t { +typedef enum cursor_t { + ZDWM_CURSOR_NORMAL, + ZDWM_CURSOR_MOVE, + ZDWM_CURSOR_RESIZE, + ZDWM_CURSOR_COUNT, +} cursor_t; + +typedef struct backend_t { xcb_key_symbols_t *key_symbols; xcb_connection_t *conn; xcb_screen_t *screen; @@ -94,11 +102,14 @@ struct backend_t { xcb_window_t focus_window; bool update_focus; + xcb_cursor_t cursors[ZDWM_CURSOR_COUNT]; + xcb_cursor_context_t *cursor_context; + window_configure_list_t config_list; window_list_t unmap; window_list_t map; window_list_t kill; -}; +} backend_t; bool populate_window_event( struct backend_t *backend, diff --git a/src/backend/x11/window.c b/src/backend/x11/window.c index 8284ba9..660c9f6 100644 --- a/src/backend/x11/window.c +++ b/src/backend/x11/window.c @@ -3,10 +3,12 @@ #include #include #include +#include #include #include #include +#include "backend/x11/cursor.h" #include "base/macros.h" #include "base/memory.h" #include "core/backend.h" @@ -451,3 +453,13 @@ visual_t *window_get_visual(backend_t *backend, bool prefer_alpha) { return visual; } + +void window_change_cursor( + backend_t *backend, + xcb_window_t window, + cursor_t cursor +) { + auto conn = backend->conn; + xcb_params_cw_t params = {.cursor = cursor_get_xcb_cursor(backend, cursor)}; + xcb_aux_change_window_attributes(conn, window, XCB_CW_CURSOR, ¶ms); +} diff --git a/src/backend/x11/window.h b/src/backend/x11/window.h index 5df4223..ae8e47e 100644 --- a/src/backend/x11/window.h +++ b/src/backend/x11/window.h @@ -118,3 +118,9 @@ typedef struct visual_t { * @returns 返回的信息使用后记得使用 free 释放 */ visual_t *window_get_visual(backend_t *backend, bool prefer_alpha); + +void window_change_cursor( + backend_t *backend, + xcb_window_t window, + cursor_t cursor +);