@@ -53,12 +53,7 @@ static gboolean bus_callback(GstBus *bus, GstMessage *msg, gpointer data) {
5353 return TRUE;
5454}
5555
56- static int run_wallpaper(const char *path, int force_cpu) {
57- int argc = 0;
58- gtk_init(&argc, NULL);
59- gst_init(&argc, NULL);
60-
61- // Create window on the background layer
56+ static void init_layer_window(void) {
6257 window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
6358 gtk_window_set_decorated(window, FALSE);
6459 gtk_layer_init_for_window(window);
@@ -68,6 +63,37 @@ static int run_wallpaper(const char *path, int force_cpu) {
6863 gtk_layer_set_anchor(window, GTK_LAYER_SHELL_EDGE_LEFT, TRUE);
6964 gtk_layer_set_anchor(window, GTK_LAYER_SHELL_EDGE_RIGHT, TRUE);
7065 gtk_layer_set_exclusive_zone(window, -1);
66+ }
67+
68+ static int run_gif(const char *path) {
69+ int argc = 0;
70+ gtk_init(&argc, NULL);
71+
72+ init_layer_window();
73+
74+ GdkPixbufAnimation *anim = gdk_pixbuf_animation_new_from_file(path, NULL);
75+ if (!anim) {
76+ g_printerr("aether-wp: failed to load GIF: %s\n", path);
77+ return 1;
78+ }
79+
80+ GtkWidget *image = gtk_image_new_from_animation(anim);
81+ g_object_unref(anim);
82+ gtk_container_add(GTK_CONTAINER(window), image);
83+
84+ g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
85+ gtk_widget_show_all(GTK_WIDGET(window));
86+ gtk_main();
87+
88+ return 0;
89+ }
90+
91+ static int run_wallpaper(const char *path, int force_cpu) {
92+ int argc = 0;
93+ gtk_init(&argc, NULL);
94+ gst_init(&argc, NULL);
95+
96+ init_layer_window();
7197
7298 // GStreamer pipeline: playbin + gtkglsink (GPU-accelerated)
7399 pipeline = gst_element_factory_make("playbin", "player");
@@ -116,10 +142,12 @@ static int run_wallpaper(const char *path, int force_cpu) {
116142 // Enable hardware decoding flags (video + native-video + deinterlace, no audio)
117143 g_object_set(pipeline, "flags", 0x61, NULL);
118144
119- // Cap frame rate to 30fps to reduce GPU load
145+ // Cap frame rate to 24fps to reduce GPU load.
146+ // Note: videoscale can't be used here because hardware decode (native-video)
147+ // outputs frames in GPU memory which CPU-based filters can't handle.
120148 GstElement *rate = gst_element_factory_make("videorate", "rate");
121149 if (rate) {
122- g_object_set(rate, "max-rate", 30 , NULL);
150+ g_object_set(rate, "max-rate", 24 , NULL);
123151 g_object_set(pipeline, "video-filter", rate, NULL);
124152 }
125153
@@ -279,13 +307,19 @@ func main() {
279307 C .request_shutdown ()
280308 }()
281309
282- cpu := C .int (0 )
283- if forceCPU {
284- cpu = 1
285- }
286310 cpath := C .CString (path )
287311 defer C .free (unsafe .Pointer (cpath ))
288- rc := C .run_wallpaper (cpath , cpu )
312+
313+ var rc C.int
314+ if strings .ToLower (filepath .Ext (path )) == ".gif" {
315+ rc = C .run_gif (cpath )
316+ } else {
317+ cpu := C .int (0 )
318+ if forceCPU {
319+ cpu = 1
320+ }
321+ rc = C .run_wallpaper (cpath , cpu )
322+ }
289323 removePidFile ()
290324 os .Exit (int (rc ))
291325}
0 commit comments