From 3dd2f80128844dfe0d7ce09ced9b974093dd69b1 Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Mon, 25 Aug 2025 11:57:23 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=A3=81=E7=BA=B8=E7=BB=98?= =?UTF-8?q?=E5=88=B6=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/include/xcb.h | 4 +++ src/main.c | 67 +++++++++++++++++++++++++++++++----------- src/xcb/window.c | 5 ---- src/xcb/window.h | 7 +++++ src/xcb/wm-extension.c | 2 ++ src/xcb/xcb.c | 47 +++++++++++++++++++++++++++++ 6 files changed, 110 insertions(+), 22 deletions(-) diff --git a/src/include/xcb.h b/src/include/xcb.h index 3adf3d6..5c6cd84 100644 --- a/src/include/xcb.h +++ b/src/include/xcb.h @@ -82,6 +82,8 @@ typedef struct rect_size_t { uint32_t height; } rect_size_t; rect_size_t *get_screen_size(void); +bar_cairo_params_t *prepare_wallpaper_surface_params(void); +void refresh_root_window(void); void set_wallpaper(uint32_t *wallpaper_data); typedef struct window_list_t { @@ -105,6 +107,8 @@ typedef enum atom_t { atom_wm_delete, atom_wm_take_focus, atom_net_wm_name, + atom__xrootpmap_id, + atom_esetroot_pmap_id, } atom_t; xcb_atom_t get_xcb_atom(atom_t atom); bool send_event(xcb_window_t window, atom_t atom); diff --git a/src/main.c b/src/main.c index 017151a..db1fd1c 100644 --- a/src/main.c +++ b/src/main.c @@ -25,7 +25,8 @@ static void init_monitors(void); static char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index); static void init_wallpaper(void); static gboolean update_wallpaper(gpointer user_data); -static void set_wallpaper_by_index(uint32_t index, wallpaper_config_t *config); +static void set_wallpaper_by_index(uint32_t index, wallpaper_config_t *config, + cairo_t *cr); static wallpaper_config_t *parse_wallpaper_config(void); static void free_wallpaper_config(wallpaper_config_t *wallpaper_config); static void init_color_set(void); @@ -70,6 +71,7 @@ static void cleanup(void); static monitor_t *monitors = NULL; static monitor_t *current_monitor = NULL; +static cairo_t *wallpaper_cr = NULL; static wallpaper_config_t *wallpaper_config = NULL; static color_set_t *color_set = NULL; static GMainLoop *loop = NULL; @@ -253,6 +255,28 @@ void init_wallpaper(void) { wallpaper_config = parse_wallpaper_config(); if (!wallpaper_config) return; + bar_cairo_params_t *p = prepare_wallpaper_surface_params(); + rect_size_t *screen_size = get_screen_size(); + if (wallpaper_cr) cairo_destroy(wallpaper_cr); + + cairo_surface_t *surface = cairo_xcb_surface_create( + p->conn, p->window, p->visual, screen_size->width, screen_size->height); + free(p); + free(screen_size); + + if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { + cairo_surface_destroy(surface); + return; + } + + cairo_t *cr = cairo_create(surface); + if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) { + cairo_destroy(cr); + return; + } + wallpaper_cr = cr; + cairo_surface_destroy(surface); + update_wallpaper(wallpaper_config); if (!wallpaper_interval) return; g_timeout_add_seconds(wallpaper_interval, update_wallpaper, wallpaper_config); @@ -260,10 +284,10 @@ void init_wallpaper(void) { gboolean update_wallpaper(gpointer user_data) { wallpaper_config_t *wc = user_data; - if (!wc) return false; + if (!wc || !wallpaper_cr) return false; static uint32_t index = 0; - set_wallpaper_by_index(index, wc); + set_wallpaper_by_index(index, wc, wallpaper_cr); uint32_t monitor_count = 0; for (monitor_t *m = monitors; m; m = m->next) monitor_count++; @@ -278,22 +302,29 @@ gboolean update_wallpaper(gpointer user_data) { return true; } -void set_wallpaper_by_index(uint32_t index, wallpaper_config_t *config) { - if (!config) return; - +void set_wallpaper_by_index(uint32_t index, wallpaper_config_t *config, + cairo_t *cr) { rect_size_t *screen_size = get_screen_size(); - uint32_t *wallpaper = generate_wallpaper( - config, monitors, index, screen_size->width, screen_size->height); - - if (wallpaper) { - double start = get_time(); - set_wallpaper(wallpaper); - double end = get_time(); - free(wallpaper); - logger("set wallpaper cost: %fs\n", end - start); - } - + uint32_t width = screen_size->width; + uint32_t height = screen_size->height; free(screen_size); + + uint32_t *wallpaper = + generate_wallpaper(config, monitors, index, width, height); + + if (!wallpaper) return; + + double start = get_time(); + uint8_t *data = (uint8_t *)wallpaper; + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); + cairo_surface_t *s = cairo_image_surface_create_for_data( + data, CAIRO_FORMAT_ARGB32, width, height, stride); + cairo_set_source_surface(cr, s, 0, 0); + cairo_paint(cr); + refresh_root_window(); + free(wallpaper); + double end = get_time(); + logger("set wallpaper cost: %fs\n", end - start); } wallpaper_config_t *parse_wallpaper_config(void) { @@ -926,7 +957,9 @@ void cleanup(void) { clean_pango_context(); free_wallpaper_config(wallpaper_config); + cairo_destroy(wallpaper_cr); wallpaper_config = NULL; + wallpaper_cr = NULL; free(color_set); color_set = NULL; diff --git a/src/xcb/window.c b/src/xcb/window.c index 9371750..b72c4b3 100644 --- a/src/xcb/window.c +++ b/src/xcb/window.c @@ -57,11 +57,6 @@ void get_window_class_instance(xcb_window_t window, xcb_icccm_get_wm_class_reply_wipe(&prop); } -typedef struct visual_t { - uint8_t depth; - xcb_visualtype_t *visual; -} visual_t; - static visual_t *find_alpha_visual() { xcb_depth_iterator_t depth_iter; depth_iter = xcb_screen_allowed_depths_iterator(screen); diff --git a/src/xcb/window.h b/src/xcb/window.h index 7bc0311..ee82bd6 100644 --- a/src/xcb/window.h +++ b/src/xcb/window.h @@ -1,6 +1,13 @@ #pragma once +#include #include void set_window_class_instance(xcb_window_t window, const char *class, const char *instance); + +typedef struct visual_t { + uint8_t depth; + xcb_visualtype_t *visual; +} visual_t; +visual_t *get_xcb_visual(bool prefer_alpha); diff --git a/src/xcb/wm-extension.c b/src/xcb/wm-extension.c index 95d8d2c..ace5a6d 100644 --- a/src/xcb/wm-extension.c +++ b/src/xcb/wm-extension.c @@ -26,6 +26,8 @@ static atom_map_t atom_map[] = { {.atom = atom_wm_delete, .name = "WM_DELETE_WINDOW"}, {.atom = atom_wm_take_focus, .name = "WM_TAKE_FOCUS"}, {.atom = atom_net_wm_name, .name = "_NET_WM_NAME"}, + {.atom = atom__xrootpmap_id, .name = "_XROOTPMAP_ID"}, + {.atom = atom_esetroot_pmap_id, .name = "ESETROOT_PMAP_ID"}, }; void init_icccm_extension(void) { diff --git a/src/xcb/xcb.c b/src/xcb/xcb.c index 462bdfd..7913483 100644 --- a/src/xcb/xcb.c +++ b/src/xcb/xcb.c @@ -15,6 +15,7 @@ #include "app.h" #include "utils.h" +#include "window.h" #include "xcb-private.h" xcb_connection_t *conn = NULL; @@ -150,6 +151,52 @@ rect_size_t *get_screen_size(void) { return size; } +bar_cairo_params_t *prepare_wallpaper_surface_params(void) { + uint32_t width = screen->width_in_pixels; + uint32_t height = screen->height_in_pixels; + xcb_window_t root = screen->root; + + visual_t *v = get_xcb_visual(false); + + static xcb_pixmap_t pixmap = XCB_PIXMAP_NONE; + if (pixmap != XCB_PIXMAP_NONE) { + xcb_kill_client(conn, pixmap); + xcb_free_pixmap(conn, pixmap); + } + + pixmap = xcb_generate_id(conn); + xcb_create_pixmap(conn, v->depth, pixmap, root, width, height); + xcb_gcontext_t gc = xcb_generate_id(conn); + xcb_create_gc(conn, gc, pixmap, 0, NULL); + 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); + + /* 兼容合成器,不设置若开启合成器壁纸会不显示 */ + uint8_t mode = XCB_PROP_MODE_REPLACE; + xcb_atom_t atom = get_xcb_atom(atom__xrootpmap_id); + xcb_change_property(conn, mode, root, atom, XCB_ATOM_PIXMAP, 32, 1, &pixmap); + atom = get_xcb_atom(atom_esetroot_pmap_id); + xcb_change_property(conn, mode, root, atom, XCB_ATOM_PIXMAP, 32, 1, &pixmap); + + xcb_clear_area(conn, 0, root, 0, 0, width, height); + xcb_free_gc(conn, gc); + xcb_flush(conn); + + bar_cairo_params_t *p = ecalloc(1, sizeof(bar_cairo_params_t)); + p->conn = conn; + p->visual = v->visual; + p->window = pixmap; + free(v); + return p; +} + +void refresh_root_window(void) { + xcb_clear_area(conn, 0, screen->root, 0, 0, 0, 0); + xcb_flush(conn); +} + void set_wallpaper(uint32_t *wallpaper_data) { uint32_t width = screen->width_in_pixels; uint32_t height = screen->height_in_pixels;