添加壁纸功能

This commit is contained in:
2025-08-10 02:07:57 +08:00
parent 751fce23c1
commit fc58edca2d
8 changed files with 241 additions and 21 deletions

View File

@@ -28,14 +28,17 @@ pkg_check_modules(XCB REQUIRED
xcb-cursor xcb-cursor
xcb-ewmh xcb-ewmh
xcb-icccm xcb-icccm
xcb-image
xcb-keysyms xcb-keysyms
xcb-util xcb-util
xcb-xfixes xcb-xfixes
xcb-xinerama xcb-xinerama
xcb-xrm xcb-xrm
) )
pkg_check_modules(RENDERER REQUIRED imlib2)
add_subdirectory(xcb) add_subdirectory(xcb)
add_subdirectory(renderer)
configure_file( configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/app.h.in" "${CMAKE_CURRENT_SOURCE_DIR}/app.h.in"
@@ -54,4 +57,5 @@ target_include_directories(${APP_NAME}
target_link_libraries(${APP_NAME} target_link_libraries(${APP_NAME}
PRIVATE ${GLIB_LIBRARIES} PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${LIB_XCB_NAME} PRIVATE ${LIB_XCB_NAME}
PRIVATE ${LIB_RENDERER_NAME}
) )

10
src/include/renderer.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include <stdint.h>
#include "types.h"
uint32_t *generate_wallpaper(const wallpaper_config_t *wallpaper_config,
const monitor_t *monitors, const uint32_t index,
const uint32_t screen_width,
const uint32_t screen_height);

View File

@@ -5,6 +5,9 @@
#define LENGTH(X) (sizeof(X) / sizeof(X)[0]) #define LENGTH(X) (sizeof(X) / sizeof(X)[0])
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
void die(const char *format, ...); void die(const char *format, ...);
void *ecalloc(size_t number_of_member, size_t member_size); void *ecalloc(size_t number_of_member, size_t member_size);

View File

@@ -16,6 +16,13 @@ struct monitor_rect_t {
}; };
monitor_rect_t *detect_monitor_rect(void); monitor_rect_t *detect_monitor_rect(void);
typedef struct rect_size_t {
uint32_t width;
uint32_t height;
} rect_size_t;
rect_size_t *get_screen_size(void);
void set_wallpaper(uint32_t *wallpaper_data);
typedef struct window_list_t { typedef struct window_list_t {
uint32_t count; uint32_t count;
xcb_window_t *list; xcb_window_t *list;

View File

@@ -1,4 +1,5 @@
#include <glib.h> #include <glib.h>
#include <glibconfig.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@@ -7,11 +8,14 @@
#include <wordexp.h> #include <wordexp.h>
#include "config.h" #include "config.h"
#include "renderer.h"
#include "types.h" #include "types.h"
#include "utils.h" #include "utils.h"
#include "xcb.h" #include "xcb.h"
static void init_monitors(void); static void init_monitors(void);
static void init_wallpaper(void);
static void set_wallpaper_by_index(uint32_t index);
static wallpaper_config_t *parse_wallpaper_config(const char **wallpapers); static wallpaper_config_t *parse_wallpaper_config(const char **wallpapers);
static void free_wallpaper_config(wallpaper_config_t *wallpaper_config); static void free_wallpaper_config(wallpaper_config_t *wallpaper_config);
static void cleanup(void); static void cleanup(void);
@@ -19,9 +23,40 @@ static void cleanup(void);
static monitor_t *monitors = NULL; static monitor_t *monitors = NULL;
static wallpaper_config_t *wallpaper_config = NULL; static wallpaper_config_t *wallpaper_config = NULL;
/* 调试函数,开发完成后删除 */
static void print_monitor_list_info(monitor_t *monitor_list) {
for (monitor_t *m = monitor_list; m; m = m->next) {
printf("mon[%u]: x: %d, y: %d, width: %u, height: %u\n", m->index,
m->monitor_x, m->monitor_y, m->monitor_width, m->monitor_height);
}
}
static void print_wallpaper_config(wallpaper_config_t *config) {
if (!config) {
printf("no wallpaper\n");
return;
}
printf("wallpaper count: %u\n", config->count);
for (uint32_t i = 0; i < config->count; i++) {
printf("wallpaper[%02u]: %s\n", i, config->path_list[i]);
}
}
static void print_window_list(window_list_t *window_list) {
if (!window_list) {
printf("no window\n");
return;
}
for (uint32_t i = 0; i < window_list->count; i++) {
printf("window[%u]: 0x%x\n", i, window_list->list[i]);
}
}
/* 调试函数结束 */
void init_monitors(void) { void init_monitors(void) {
monitor_rect_t *mr = detect_monitor_rect(); monitor_rect_t *mr = detect_monitor_rect();
uint32_t i = 0; uint32_t i = 0;
monitor_t *prev_monitor = NULL;
while (mr) { while (mr) {
monitor_t *m = ecalloc(1, sizeof(monitor_t)); monitor_t *m = ecalloc(1, sizeof(monitor_t));
m->monitor_x = mr->x; m->monitor_x = mr->x;
@@ -30,10 +65,12 @@ void init_monitors(void) {
m->monitor_height = mr->height; m->monitor_height = mr->height;
m->index = i; m->index = i;
printf("mon[%u]: x: %d, y: %d, w: %u, h: %u\n", i, mr->x, mr->y, mr->width, if (prev_monitor) {
mr->height); prev_monitor->next = m;
} else {
if (!i) monitors = m; monitors = m;
}
prev_monitor = m;
i++; i++;
monitor_rect_t *next_mr = mr->next; monitor_rect_t *next_mr = mr->next;
@@ -42,6 +79,25 @@ void init_monitors(void) {
} }
} }
void init_wallpaper(void) {
wallpaper_config = parse_wallpaper_config(wallpager_list);
if (!wallpaper_config) return;
set_wallpaper_by_index(0);
}
void set_wallpaper_by_index(uint32_t index) {
if (!wallpaper_config) return;
rect_size_t *screen_size = get_screen_size();
uint32_t *wallpaper = generate_wallpaper(
wallpaper_config, monitors, index, screen_size->width, screen_size->height);
set_wallpaper(wallpaper);
free(screen_size);
free(wallpaper);
}
wallpaper_config_t *parse_wallpaper_config(const char **wallpapers) { wallpaper_config_t *parse_wallpaper_config(const char **wallpapers) {
if (!wallpapers) return NULL; if (!wallpapers) return NULL;
@@ -105,26 +161,20 @@ int main(int argc, char *argv[]) {
die("another window manager is already running"); die("another window manager is already running");
} }
wallpaper_config = parse_wallpaper_config(wallpager_list);
if (wallpaper_config) {
printf("wallpaper count: %u\n", wallpaper_config->count);
for (uint32_t i = 0; i < wallpaper_config->count; i++) {
printf("wallpaper[%02u]: %s\n", i, wallpaper_config->path_list[i]);
}
}
init_monitors(); init_monitors();
init_wallpaper();
window_list_t *window_list = scan_window_list(); window_list_t *window_list = scan_window_list();
if (window_list) {
for (uint32_t i = 0; i < window_list->count; i++) { print_monitor_list_info(monitors);
printf("window[%u]: 0x%x\n", i, window_list->list[i]); print_wallpaper_config(wallpaper_config);
} print_window_list(window_list);
} else {
printf("no window\n");
}
free_window_list(window_list); free_window_list(window_list);
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
cleanup(); cleanup();
return 0; return 0;

View File

@@ -0,0 +1,14 @@
set(LIB_RENDERER "zswm-renderer")
set(LIB_RENDERER_NAME ${LIB_RENDERER} PARENT_SCOPE)
add_library(${LIB_RENDERER} STATIC image.c)
target_include_directories(${LIB_RENDERER} SYSTEM
PRIVATE ${RENDERER_INCLUDE_DIRS}
)
target_include_directories(${LIB_RENDERER}
PRIVATE "${CMAKE_SOURCE_DIR}/include"
)
target_link_libraries(${LIB_RENDERER}
PRIVATE ${RENDERER_LIBRARIES}
)

95
src/renderer/image.c Normal file
View File

@@ -0,0 +1,95 @@
#include <Imlib2.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "renderer.h"
#include "types.h"
#include "utils.h"
/**
* @brief 生成需要由 xcb 绘制的壁纸数据
* @returns 壁纸数据,使用后记得释放
*/
uint32_t *generate_wallpaper(const wallpaper_config_t *wallpaper_config,
const monitor_t *monitors, const uint32_t index,
const uint32_t screen_width,
const uint32_t screen_height) {
if (!wallpaper_config || !monitors) return NULL;
Imlib_Image final_image = imlib_create_image(screen_width, screen_height);
if (!final_image) return NULL;
imlib_context_set_image(final_image);
imlib_image_set_has_alpha(false);
/* 填充背景色 */
imlib_context_set_color(0, 0, 0, 255);
imlib_image_fill_rectangle(0, 0, screen_width, screen_height);
const monitor_t *monitor = monitors;
uint32_t monitor_index = 0;
while (monitor) {
uint32_t img_index = (index + monitor_index) % wallpaper_config->count;
Imlib_Image wallpaper_img =
imlib_load_image(wallpaper_config->path_list[img_index]);
if (!wallpaper_img) {
monitor = monitor->next;
monitor_index++;
continue;
}
uint32_t dst_width = monitor->monitor_width;
uint32_t dst_height = monitor->monitor_height;
/* 获取图片原始尺寸 */
imlib_context_set_image(wallpaper_img);
uint32_t img_width = imlib_image_get_width();
uint32_t img_height = imlib_image_get_height();
/* 计算缩放比例,保持原始宽高比 */
float width_ratio = (float)dst_width / img_width;
float height_ratio = (float)dst_height / img_height;
float scale = MAX(width_ratio, height_ratio);
uint32_t scaled_width = img_width * scale;
uint32_t scaled_height = img_height * scale;
/* 图片居中显示,计算原图绘制区域 */
int src_x = (scaled_width - dst_width) / (2 * scale);
int src_y = (scaled_height - dst_height) / (2 * scale);
int src_width = dst_width / scale;
int src_height = dst_height / scale;
/* 绘制图片到最终图像上 */
imlib_context_set_image(final_image);
imlib_blend_image_onto_image(wallpaper_img, 1, src_x, src_y, src_width,
src_height, monitor->monitor_x,
monitor->monitor_y, dst_width, dst_height);
/* 释放图片资源 */
imlib_context_set_image(wallpaper_img);
imlib_free_image();
monitor = monitor->next;
monitor_index++;
}
/* 获取最终图像数据 */
imlib_context_set_image(final_image);
uint32_t *data = imlib_image_get_data_for_reading_only();
/* 复制数据到自己分配的内存中(原数据会在图像释放后无效) */
size_t data_size = screen_width * screen_height * sizeof(uint32_t);
uint32_t *result = malloc(data_size);
if (result) memcpy(result, data, data_size);
/* 释放图像 */
imlib_context_set_image(final_image);
imlib_free_image();
return result;
}

View File

@@ -2,13 +2,13 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include <xcb/xcb_aux.h> #include <xcb/xcb_aux.h>
#include <xcb/xcb_ewmh.h> #include <xcb/xcb_ewmh.h>
#include <xcb/xcb_icccm.h> #include <xcb/xcb_icccm.h>
#include <xcb/xcb_image.h>
#include <xcb/xinerama.h> #include <xcb/xinerama.h>
#include <xcb/xinput.h> #include <xcb/xinput.h>
#include <xcb/xproto.h> #include <xcb/xproto.h>
@@ -30,7 +30,6 @@ bool has_other_wm_running(void) {
const xcb_setup_t *setup = xcb_get_setup(conn); const xcb_setup_t *setup = xcb_get_setup(conn);
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
screen = iter.data; screen = iter.data;
printf("screen number: %d\n", iter.rem);
uint32_t mask = XCB_CW_EVENT_MASK; uint32_t mask = XCB_CW_EVENT_MASK;
xcb_params_cw_t params = { xcb_params_cw_t params = {
.event_mask = XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_ENTER_WINDOW | .event_mask = XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_ENTER_WINDOW |
@@ -124,6 +123,44 @@ monitor_rect_t *detect_monitor_rect(void) {
return rect; return rect;
} }
/**
* @brief 获取整个屏幕的宽高
* @returns 屏幕大小数据的指针,使用完后记得释放对应内存
*/
rect_size_t *get_screen_size(void) {
rect_size_t *size = ecalloc(1, sizeof(rect_size_t));
size->width = screen->width_in_pixels;
size->height = screen->height_in_pixels;
return size;
}
void set_wallpaper(uint32_t *wallpaper_data) {
uint32_t width = screen->width_in_pixels;
uint32_t height = screen->height_in_pixels;
uint8_t depth = screen->root_depth;
xcb_window_t root = screen->root;
uint32_t data_size = width * height * sizeof(uint32_t);
uint8_t *data = (uint8_t *)wallpaper_data;
xcb_image_t *xcb_img =
xcb_image_create_native(conn, width, height, XCB_IMAGE_FORMAT_Z_PIXMAP,
depth, NULL, data_size, data);
xcb_pixmap_t pixmap = xcb_generate_id(conn);
xcb_create_pixmap(conn, depth, pixmap, root, width, height);
xcb_gcontext_t gc = xcb_generate_id(conn);
xcb_create_gc(conn, gc, pixmap, 0, NULL);
xcb_image_put(conn, pixmap, gc, xcb_img, 0, 0, 0);
xcb_change_window_attributes_value_list_t value_list = {
.background_pixmap = pixmap,
};
xcb_change_window_attributes_aux(conn, root, XCB_CW_BACK_PIXMAP, &value_list);
xcb_clear_area(conn, 0, root, 0, 0, width, height);
xcb_image_destroy(xcb_img);
xcb_free_gc(conn, gc);
xcb_flush(conn);
}
static xcb_ewmh_connection_t *ewmh = NULL; static xcb_ewmh_connection_t *ewmh = NULL;
static bool ewmh_init_failed = false; static bool ewmh_init_failed = false;
static xcb_window_t wm_check_window = XCB_NONE; static xcb_window_t wm_check_window = XCB_NONE;