Skip to content

Instantly share code, notes, and snippets.

@SkyyySi
Last active January 25, 2022 17:40
Show Gist options
  • Save SkyyySi/b3da2d5ca46c6a8e4a2cb81a99543929 to your computer and use it in GitHub Desktop.
Save SkyyySi/b3da2d5ca46c6a8e4a2cb81a99543929 to your computer and use it in GitHub Desktop.
Redraw an awesome wm imagebox widget

Redraw an awesome wm imagebox widget

Description

This code snippet allows you to force a wibox.widget.imagebox to be re-draw itself without pointing it to a new file path.

Important: the solution given here only works with PNG files. If your file is either not a PNG or you are not sure about its type, you can convert it using ffmpeg, shown at the end.

The problem

Let's assume you have a bit of code where you want to update your imagebox whenever the global signal imagebox_update_signal is emitted. The signal passes a string to a file path that's always the same. Note that this would be the same if image would be a constant.

-- This code is broken. It does not work.
local wibox = require("wibox")

local my_imagebox = wibox.widget {
	resize = true,
	widget = wibox.widget.imagebox,
}

awesome.connect_signal("imagebox_update_signal", function(image)
	my_imagebox:set_image(image)
end)

This will not work, because you are giving the same path to the :set_image-method. So what can you do?

The solution

Instead of sending the same path string every time, what you have to do is to create a new "cairo surface" every time you want to redraw the imagebox (cairo is the graphics library used by awesome under the hood to paint custom widgets and graphics to the screen).

-- This is the code you want to copy without reading what I wrote ;)
local cairo = require("lgi").cairo
local wibox = require("wibox")
local gears = require("gears")
local image_path = 

local my_imagebox = wibox.widget {
	resize = true,
	widget = wibox.widget.imagebox,
}

awesome.connect_signal("imagebox_update_signal", function(image)
	my_imagebox:set_image(image)
end)

local function redraw_imagebox(image_path)
	local surface = cairo.ImageSurface.create('ARGB32', 50, 50)
	local cr      = cairo.Context(surface)
	local img     = cairo.ImageSurface.create_from_png(image_path)
	cr:paint()

	awesome.emit_signal("imagebox_update_signal", img)
end

The redraw_imagebox-function needs to be triggered every time you want to redraw the imagebox. This can, for example, be done using a gears.timer:

local timer = gears.timer {
	timeout   = 1,  -- call once per second
	autostart = true, -- start without `calling timer:start()` first
	callback  = function() {  -- the function called by the timer
		redraw_imagebox(image_path) -- assumes `image_path` was previously defined in-scope, like in the example above
	}
}

Converting the image to PNG

As mentioned at the beginning, this only works with PNG files. If you need to convert the image to a PNG beforehand, you can do so using this function calling ffmpeg:

local function convert_image_file_to_png(input_image_path, output_image_path)
	-- The `-y`-flag causes ffmpeg to automatically overwrite files, so be aware of that
	awful.spawn({"ffmpeg", "-y", "-i", input_image_path, output_image_path})
end

Important: The -y-flag causes ffmpeg to automatically overwrite files, so be aware of that. However, you probably want that to have an asynchronous callback, so you can redraw your imagebox once ffmpeg is done:

local function convert_image_file_to_png(input_image_path, output_image_path)
	awful.spawn.easy_async({"ffmpeg", "-y", "-i", input_image_path, output_image_path}, function()
		redraw_imagebox(output_image_path)
	end)
end

Further reading

Special thanks

License

This document is released into the public domain under the Creative Commons Zero (CC0 license) license, while the code snippets within it are licensed under the unlicense. Both licenses can be considered public domain, as-is licenses (this is not legal advice; read the licenses).

Any questions left?

Just leave a comment, I'll try to help!

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