Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Animated GIF support #1903

Open
psychon opened this issue Jul 3, 2017 · 8 comments
Open

Animated GIF support #1903

psychon opened this issue Jul 3, 2017 · 8 comments

Comments

@psychon
Copy link
Member

psychon commented Jul 3, 2017

Is anyone interested in wibox.widget.imagebox being able to show animated GIFs?

diff --git a/lib/wibox/widget/imagebox.lua b/lib/wibox/widget/imagebox.lua
index e973fc0..a684f03 100644
--- a/lib/wibox/widget/imagebox.lua
+++ b/lib/wibox/widget/imagebox.lua
@@ -6,19 +6,27 @@
 -- @classmod wibox.widget.imagebox
 ---------------------------------------------------------------------------
 
+local pixbuf = require("lgi").GdkPixbuf
 local base = require("wibox.widget.base")
 local surface = require("gears.surface")
 local gtable = require("gears.table")
+local timer = require("gears.timer")
 local setmetatable = setmetatable
 local type = type
 local print = print
 local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
 
+do
+    -- For set_source_pixbuf on a cairo context
+    local _ = require("lgi").Gdk
+end
+
 local imagebox = { mt = {} }
 
 -- Draw an imagebox with the given cairo context in the given geometry.
 function imagebox:draw(_, cr, width, height)
-    if not self._private.image then return end
+    local image, iter = self._private.image, self._private.iter
+    if not image then return end
     if width == 0 or height == 0 then return end
 
     if not self._private.resize_forbidden then
@@ -37,7 +45,20 @@ function imagebox:draw(_, cr, width, height)
         cr:clip(self._private.clip_shape(cr, width, height, unpack(self._private.clip_args)))
     end
 
-    cr:set_source_surface(self._private.image, 0, 0)
+    if not iter then
+        cr:set_source_surface(self._private.image, 0, 0)
+    else
+        iter:advance(nil)
+        cr:set_source_pixbuf(iter:get_pixbuf(), 0, 0)
+        local delay = iter:get_delay_time()
+        -- Todo: centralise this and have only one timer
+        if delay ~= -1 then
+            timer.start_new(delay / 1000, function()
+                self:emit_signal("widget::redraw_needed")
+                return false
+            end)
+        end
+    end
     cr:paint()
 end
 
@@ -84,30 +105,44 @@ end
 
 function imagebox:set_image(image)
     if type(image) == "string" then
-        image = surface.load(image)
+        local err
+        image, err = pixbuf.PixbufAnimation.new_from_file(image)
         if not image then
+            print(tostring(err))
             print(debug.traceback())
             return false
         end
     end
 
-    image = image and surface.load(image)
+    local anim, iter
+    if image and pixbuf.PixbufAnimation:is_type_of(image) then
+        if not image:is_static_image() then
+            anim = image
+            iter = image:get_iter(nil)
+        else
+            image = image:get_static_image()
+        end
+    else
+        image = image and surface.load(image)
+    end
 
     if image then
-        local w = image.width
-        local h = image.height
+        local w = image:get_width()
+        local h = image:get_height()
         if w <= 0 or h <= 0 then
             return false
         end
     end
 
-    if self._private.image == image then
+    if self._private.image == image and self._private.anim == anim then
         -- The image could have been modified, so better redraw
         self:emit_signal("widget::redraw_needed")
         return true
     end
 
     self._private.image = image
+    self._private.anim = anim
+    self._private.iter = iter
 
     self:emit_signal("widget::redraw_needed")
     self:emit_signal("widget::layout_changed")
@r3lgar
Copy link

r3lgar commented Jul 8, 2017

-- Todo: centralise this and have only one timer

How will you do merge iterations to one timer were images loads not synchronised?

@psychon
Copy link
Member Author

psychon commented Jul 9, 2017

@r3lgar I mean that comment as "one timer per imagebox", not "one timer across all imageboxes". Right now this starts a timer inside of :draw. That's wrong. This assumes that the timer is the only thing that causes redraws. If there is ever a redraw for any other reason (e.g.: Some other widget changes its size and this pushes the imagebox to a new position), this code would wrongly start a second timer and now the GIF plays at double speed. If that happens again, the GIF plays at triple speed, etc.

@r3lgar
Copy link

r3lgar commented Jul 9, 2017

@psychon

I have no idea how to move the timer from :draw but if images are objects (there're should be), you can use something like self.timer_started and don't start another timer if it's not nil.

Animated GIFs is good idea, but animated SVG is even better. (=

@psychon
Copy link
Member Author

psychon commented Jul 9, 2017

Yup, I can. I was just too lazy and hence just left a comment.

Animated GIFs is good idea, but animated SVG is even better. (=

Does GdkPixbuf support animated SVGs? I did not even know that animated SVGs are a thing.

@r3lgar
Copy link

r3lgar commented Jul 9, 2017

Does GdkPixbuf support animated SVGs?

I strongly doubt it.

I did not even know that animated SVGs are a thing.

In fact, it's a rare thing. XML animations is a crap, but smooth and eye candy crap. (=

@Elv13
Copy link
Member

Elv13 commented Jul 16, 2017

Does GdkPixbuf support animated SVGs?

Supporting that would require a full JavaScript interpreter in GDK. I also looked if it existed a while back, but was not surprised it didn't. I don't think it is feasible to implement them. However maybe a separate Lua context + XML parser + librsvg could be used to implement SVG elements animation in Lua itself. It would require a very determined individual to make it work and it wont ever be me.

@psychon
Copy link
Member Author

psychon commented Jul 16, 2017

Supporting that would require a full JavaScript interpreter in GDK.

Really? First Google result doesn't sound like. It mentions that JavaScript is an option, but also explains lots of CSS animations. https://css-tricks.com/guide-svg-animations-smil/

Anyway, support for this would be something for GDK and not directly awesome-related anyway.

@hewcaw
Copy link

hewcaw commented Sep 2, 2021

Hello guys, just stumbled on this, so I want to use the below GIF but as SVG Animation for my small widget inside wibar, can anyone provide me a roadmap how can I implement this feature inside AwesomeWM? And also is there any other to do something like this instead of SVG Animation with AwesomeWM? And really I have zero knowledge of how to develop Awesome.

kapture_2019-03-12_at_6 41 19

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants