Using Lua scripts (Part 01): How does a lua script work - brndnmtthws/conky GitHub Wiki

About "Using Lua scripts"

This tutorial has been written by mrpeachy and was posted on Crunchbang; all credit goes to him. The tutorial was slightly adapted for Conky 1.10 and onwards. The Lua syntax did not change between Conky 1.9 and 1.10 so the scripts themselves are usable in both.

The tutorial could use a rewrite with proper punctuation and sometimes more explanation. If you feel like helping out, please feel free to edit/expand this tutorial! Much appreciated.

This tutorial is intended to be understandable by people new to programming. It should also be a good starting point for people who want to learn Lua itself.

i: How does a Lua script work?

In Conky there are several Lua-related settings and objects. Two of them are necessary for a Lua script to work:

lua_load
lua_draw_hook_xxx

These configs should be put in the conky.config={ ... } section of your conky.conf, which you should put in ~/.config/conky. You should have an example conky.conf in /etc/conky/conky.conf.

The value of lua_load is the location of the script you will write. So lua_load = '/home/username/scripts/script.lua' means Conky will load that script at runtime.

The second line, lua_draw_hook_xxx tells Conky which function to run from the Lua script that was loaded. Please note there are two kinds of lua_draw_hooks:

  • lua_draw_hook_pre: loads your function before any drawing to Conky's window
  • lua_draw_hook_post: loads your function after drawing to Conky's window Most Conky users call their main function, guess what? main

Before you continue, please ensure you've got the either the conky-cairo or the conky-all package installed as the cairo module used in these examples is what allows you to draw to the Conky window. Refer you your specific Linux distro's documentation on how to install this module.


A bare-bones Lua script for use in Conky might look like this.

-- This is a lua script for use in Conky.
require("cairo")
require("cairo_xlib")

function conky_main()
	if conky_window == nil then
		return
	end
	local cs = cairo_xlib_surface_create(
		conky_window.display,
		conky_window.drawable,
		conky_window.visual,
		conky_window.width,
		conky_window.height
	)
	cr = cairo_create(cs)
	local updates = tonumber(conky_parse("${updates}"))
	if updates > 5 then
		print("conky_main counted >5 updates to its window")
	end
	cairo_destroy(cr)
	cairo_surface_destroy(cs)
	cr = nil
end

To test this lua script add these lines into Conky configuration file inside the conky.config = { ... } section:

lua_load = "/path/to/luascript",
lua_draw_hook_post = "main",

Line by line we have:

-- This is a Lua script for use in Conky

Anything preceded by -- is a comment in Lua.

You can write a longer comment section starting with --[[ and ending with ]] like so:

--[[ this is a comment
and it can span multiple
lines until you end it with ]]

Next we have:

require("cairo")
require("cairo_xlib")

This line loads cairo, which is a popular graphics library designed to draw graphical vectors to a screen. We use them in Conky to write anything (text, drawings, etc) via Lua scripts. Have a look at the Cairo samples for usage examples. We also need to separately load cairo_xlib to draw to the Conky window with Xlib.

function conky_main()

This is our main function and the one we will set in our conky.conf file for lua_draw_hook. If you open a Lua script and are not sure which function to set in your conky.conf, look for conky_ in the function name. This function is called again and again while Conky is open.


The next lines are standard setup lines and are ONLY required for the main function that will be called in the conky.conf:

	if conky_window == nil then
		return
	end
	local cs = cairo_xlib_surface_create(
		conky_window.display,
		conky_window.drawable,
		conky_window.visual,
		conky_window.width,
		conky_window.height
	)
	cr = cairo_create(cs)

The first three lines give a taste of Lua syntax. There are no brackets or parenthesis in an if statement: rather, the if block starts on then and ends on end.

The rest of the code is necessary for drawing using cairo. This creates the "surface" onto which the text and graphics will be drawn. In this case the surface will be the Conky window itself.


Lua scripts can also make use of Conky objects:

	local updates = tonumber(conky_parse("${updates}"))
	if updates > 5 then
		print("conky_main counted >5 updates to its window")
	end

The function conky_parse does what it says it does: it parses a Conky object into our script. Then we use the function tonumber because we want the number of updates to be a number. In the if statement we say that after 5 Conky updates we want to print "conky_main counted >5 updates to its window". How much time it will take to print depends on the value of the update_interval variable in your conky.conf file itself. If the interval is 1, it will take 5 seconds, if 2, it will take 2*5=10, and so on.

NOTE: The print function prints to the terminal, not the Conky window, which makes it useful as a debugging tool. You can use print to check what your Lua script is really doing by executing your conky.conf in the terminal, like conky -c [conky.conf] and looking at the output in the terminal.

In the next tutorial we will see how to print to the Conky Window.

Notice that even though this part of the script is not inside a loop the value of updates still increments. That's because, as already implied, the Lua script is executed in a loop by Conky.

Of course, these lines are only important if you plan on reading something that requires such handling of updates (like cpu%) in the Lua script. But it's generally a good idea to include these lines -- one less thing to cause an error.

With conky_parse, you can get the output of any Conky object into Lua:

cpu = conky_parse ("${cpu}")
memory = conky_parse ("${memperc}")
home_used = conky_parse ("${fs_used /home}")

You can even use things like if_ objects from Conky using conky_parse, which can be useful as switches:

internet = conky_parse ("${if_up wlan0}1${else}0${endif}")

Now internet will have a value of 1 or 0 depending on the outcome of if_up.


Then we come to closing out the function

	cairo_destroy(cr)
	cairo_surface_destroy(cs)
	cr = nil

These lines do some cleanup. One thing that Lua can do is to eat up memory over time, especially with memory leaks, and these lines help to avoid that. Be aware that your script can cause memory leaks. You can check if your script is causing that by checking the memory consumption as the time passes. If it's getting abnormally huge, then something is wrong. One (very cheap) workaround is killing the Conky processes and restarting it again.