Set images as wallpaper
- Hard-coded image path
This commit is contained in:
parent
eb3c45bf91
commit
432ddc5ca6
74
src/main.rs
74
src/main.rs
@ -1,4 +1,4 @@
|
|||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use x11rb::wrapper::ConnectionExt as _;
|
use x11rb::wrapper::ConnectionExt as _;
|
||||||
@ -6,12 +6,16 @@ use x11rb::{
|
|||||||
connection::Connection,
|
connection::Connection,
|
||||||
protocol::xproto::{
|
protocol::xproto::{
|
||||||
AtomEnum, ChangeWindowAttributesAux, CloseDown, ConnectionExt, CreateGCAux, EventMask,
|
AtomEnum, ChangeWindowAttributesAux, CloseDown, ConnectionExt, CreateGCAux, EventMask,
|
||||||
PropMode, Rectangle,
|
ImageFormat, PropMode,
|
||||||
},
|
},
|
||||||
rust_connection::RustConnection,
|
rust_connection::RustConnection,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
// Path to wallpaper image.
|
||||||
|
// This is hardcoded for now and will later be replaced by config loading.
|
||||||
|
let image_path = "/path/to/image";
|
||||||
|
|
||||||
// Connect to the running graphical session, the X11 server.
|
// Connect to the running graphical session, the X11 server.
|
||||||
let (conn, screen_num) = RustConnection::connect(None)?;
|
let (conn, screen_num) = RustConnection::connect(None)?;
|
||||||
// Select the current screen.
|
// Select the current screen.
|
||||||
@ -54,30 +58,54 @@ fn main() -> Result<()> {
|
|||||||
let pixmap = conn.generate_id()?;
|
let pixmap = conn.generate_id()?;
|
||||||
conn.create_pixmap(depth, pixmap, root, width, height)?;
|
conn.create_pixmap(depth, pixmap, root, width, height)?;
|
||||||
|
|
||||||
// Fill the pixmap with the pixels to be set as the background.
|
// Load the wallpaper image from disk.
|
||||||
// For now, allocate a solid color (RGB 26,132,74 scaled to X11 16-bit format).
|
let img =
|
||||||
let color = conn
|
image::open(image_path).with_context(|| format!("Failed to open image: {image_path}"))?;
|
||||||
.alloc_color(screen.default_colormap, 26 * 257, 132 * 257, 74 * 257)?
|
|
||||||
.reply()?
|
|
||||||
.pixel;
|
|
||||||
|
|
||||||
// Create a Graphics Context (GC), which defines how drawing is done.
|
// Convert the image into RGBA8 (4 bytes per pixel).
|
||||||
// It stores drawing parameters such as color, fill style, etc.
|
// Predictable, CPU-friendly format to work on.
|
||||||
|
let img = img.to_rgba8();
|
||||||
|
|
||||||
|
// Resize the image to exactly match the screen size.
|
||||||
|
// This uses a simple "fill" strategy (no aspect ratio preservation).
|
||||||
|
let img = image::imageops::resize(
|
||||||
|
&img,
|
||||||
|
width.into(),
|
||||||
|
height.into(),
|
||||||
|
image::imageops::FilterType::Lanczos3,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Extract raw pixel bytes from the image buffer.
|
||||||
|
let mut pixel_data = img.into_raw();
|
||||||
|
|
||||||
|
// Image libraries produce RGBA, but X11 TrueColor visuals typically use
|
||||||
|
// BGRX/BGRA byte order on little-endian systems.
|
||||||
|
// Swap red and blue channels to match the server’s native pixel layout.
|
||||||
|
// Without this conversion, colors appear incorrect.
|
||||||
|
for pixel in pixel_data.chunks_exact_mut(4) {
|
||||||
|
pixel.swap(0, 2); // Swap Red and Blue channels
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a Graphics Context (GC).
|
||||||
|
// A GC is required by X11 for image uploads, even though most of its
|
||||||
|
// drawing settings are unused when using put_image.
|
||||||
let gc = conn.generate_id()?;
|
let gc = conn.generate_id()?;
|
||||||
// Associate the GC with the pixmap and configure its foreground color.
|
conn.create_gc(gc, pixmap, &CreateGCAux::new())?;
|
||||||
conn.create_gc(gc, pixmap, &CreateGCAux::new().foreground(color))?;
|
|
||||||
|
|
||||||
// Paint a solid-color rectangle onto the pixmap using the GC.
|
// Upload the image pixels into the pixmap.
|
||||||
// This is only for the solid-color case and will be replaced when using real images.
|
// This writes the final wallpaper image into server memory.
|
||||||
conn.poly_fill_rectangle(
|
// No scaling or color conversion happens here; the data must already be correct.
|
||||||
pixmap, // BG Image (pixmap)
|
conn.put_image(
|
||||||
gc, // The Graphics Context to paint on
|
ImageFormat::Z_PIXMAP,
|
||||||
&[Rectangle {
|
pixmap, // drawable: Destination pixmap (wallpaper image)
|
||||||
x: 0,
|
gc, // Graphics Context (required by X11)
|
||||||
y: 0, // Start from top-left corner
|
|
||||||
width,
|
width,
|
||||||
height, // Set rectangle dimensions = screen width, height
|
height, // width/height: size of the uploaded image region in pixels
|
||||||
}],
|
0,
|
||||||
|
0, // dst_x/dst_y: Destination offset inside the pixmap (top-left corner)
|
||||||
|
0, // left_pad: legacy bitmap padding, always 0 for modern images
|
||||||
|
depth, // depth: must match the root window’s depth (usually 24 or 32)
|
||||||
|
&pixel_data, // data: raw BGRA/BGRX pixel buffer
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Grab and lock the X server to prevent other clients from observing or reacting to intermediate state.
|
// Grab and lock the X server to prevent other clients from observing or reacting to intermediate state.
|
||||||
@ -113,7 +141,7 @@ fn main() -> Result<()> {
|
|||||||
let atom_root = conn.intern_atom(false, b"_XROOTPMAP_ID")?.reply()?.atom;
|
let atom_root = conn.intern_atom(false, b"_XROOTPMAP_ID")?.reply()?.atom;
|
||||||
let atom_setroot = conn.intern_atom(false, b"_XSETROOT_ID")?.reply()?.atom;
|
let atom_setroot = conn.intern_atom(false, b"_XSETROOT_ID")?.reply()?.atom;
|
||||||
|
|
||||||
// Set root window properties that publish the wallpaper pixmap location to consumers.
|
// Set root window properties that publish the wallpaper pixmap location to other clients.
|
||||||
conn.change_property32(
|
conn.change_property32(
|
||||||
PropMode::REPLACE,
|
PropMode::REPLACE,
|
||||||
root,
|
root,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user