Annimated cat on the screen that relaxes your eyes and mind.
But Why?
About 2 years ago, I found this awesome Firefox theme, I’m astonished, because who doesn’t like a cat wagging his tail on their screen? But the extension is somewhat outdated, cat looks blurry on hidpi screens, and I also want it on my emacs! So why not?
Then I extracted the images from the extension, converted to png and svg (didn’t remember how, should have taken notes). And dragged them into Xcode since I was using a macbook back then.
Then time passed, I mainly use my desktop running Linux (I use Arch Gentoo BTW), I totally forgot this cat (sorry) for almost 2 years, until I opened it again on my macbook last Monday, I was thinking, damn, I needed it on my desktop too.
Choose a stack
It’s a rather simple application, which, just rendering images, change it every 1/10 seconds, in another word, a frame animation. But in order to display nicely on the desktop, it needs some unordinary features.
- window needs to be transparent, so it looks nice.
- better if we can click through it so it won’t block the mouse events for the application underneath.
These two requirements sounds easy enough, and can simply implemented with the cocoa version, but I find them very challenging for its cross platform implementation.
First come to mind is to use electron, I tried that 2 years ago but had some issue about transparency and I don’t really like electron that much. So I decide to try other frameworks.
Rust
I’m not a fan of rust, but I do like its toolchain, cargo
and rustup
is simple to run and setup, save me some time to worry about Makefile or gcc. And also for this simple app, I don’t need to learn much about rust to get it done.
sdl2
First I wanted to try some “light” frameworks, Simple DirectMedia Layer is a light-weight, cross-platform library mostly used for game development, but it should display a image quite easily.
BUT, I can’t get it to draw a transparent pixel and the top window, either macos nor linux(i3). I have tried to set BlendMode
and set window opacity, remove the hint for not using compositor on linux, none of them works, and I don’t want to waste 4 more hours on it, so pass.
gtk3
Rust has a nicely maintained gtk binding, as a “living on the edge” type of guy, I tried the gtk4 version first, but it seems lack a lot nice API gtk3 have, so I settled with gtk3.
Implementation
Creating an animation is really easy with the PixbufSimpleAnim
API, and it handles svg out of box.
let anime = PixbufSimpleAnim::new(WIDTH, HEIGHT, 10.0); for i in 1..22 { let data = Cats::get(&format!("svg_cat{}.svg", i)).unwrap(); let buffer = ByteBuffer::from_bytes(&data); let pixbuf = Pixbuf::from_read(buffer).unwrap(); anime.add_frame(&pixbuf); } anime.set_loop(true);
I wanted the images bundled in the binary, so rust-embed comes to help.
#[derive(RustEmbed)] #[folder = "cats"] struct Cats;
And we need gtk to use the compositor so it can show transparent pixels.
let screen = win.screen().unwrap(); win.set_visual(screen.rgba_visual().as_ref());
The rest of the code is just passing some params to create and display the window, that’s it.
The repo is at Gitlab, please try it out!
All credits goes to the author of the Firefox theme!