Freeze problem

Let’s say we have a text widget which displays output of some script (get unread emails for instance). And sometimes execution of this script takes some time. Since lua is not multi-threaded you’ll have a ‘freeze’ - you won’t be able to interact with Awesome (switch tags, open Awesome menu, etc.) because Awesome will wait for the response.

I will demonstrate it on a simple example. Let’s say I have a python script which sleeps for 5 seconds and then returns some string, sleep.py:

#!/usr/bin/python

import time
time.sleep(5)
print 'wow'

Pread example

By using awful.util.pread Awesome will just wait until execution of a script is finished. To check it let’s create a text widget in a separate lus file:

local wibox = require("wibox")
local awful = require("awful")

sleepMessage = wibox.widget.textbox()

-- Pread (Awesome freezes  while waiting for response)
sleepMessageTimer = timer({ timeout = 10 })
sleepMessageTimer:connect_signal("timeout",
  function()
    sleepMessage:set_text(awful.util.pread("python ~/HomeDev/temp/sleep.py")) 
  end)
sleepMessageTimer:start()

And put it in rc.lua:

require("sleep")
...
right_layout:add(sleepMessage)

After restart of Awesome after 5 seconds Awesome will freeze for 5 seconds and then message will be displayed on a widget. This is exactly what happens when execution of some scripts takes time.

Now let’s have on a solution of this problem: using DBus to transfer messages between scripts and Awesome.

DBus example

To use DBus for this example change implementation of sleep.py

local wibox = require("wibox")
local awful = require("awful")

sleepMessage = wibox.widget.textbox()

-- DBus (Command are sent to DBus, which prevents Awesome from freezing)
sleepTimerDbus = timer ({timeout = 5})
sleepTimerDbus:connect_signal ("timeout",
  function ()
    awful.util.spawn_with_shell("dbus-send --session --dest=org.naquadah.awesome.awful /com/console/sleep com.console.sleep.sleepMessage string:$(python ~/HomeDev/temp/sleep.py)" )
  end)
sleepTimerDbus:start()

dbus.request_name("session", "com.console.sleep")
dbus.add_match("session", "interface='com.console.sleep', member='sleepMessage' " )
dbus.connect_signal("com.console.sleep",
  function (...)
    local data = {...}
    local dbustext = data[2]
    sleepMessage:set_text(dbustext)
  end)

With this implementation Awesome will not freeze. Here instead of reading output of a script we send it to DBus:

dbus-send --session --dest=org.naquadah.awesome.awful /com/console/sleep com.console.sleep.sleepMessage string:$(python ~/HomeDev/temp/sleep.py)

And when execution has finished we take it and display:

dbus.request_name("session", "com.console.sleep")
dbus.add_match("session", "interface='com.console.sleep', member='sleepMessage' " )
dbus.connect_signal("com.console.sleep",
  function (...)
    local data = {...}
    local dbustext = data[2]
    sleepMessage:set_text(dbustext)
  end)

Conclusion

For widgets, which uses scripts which could take some time to run, like calling some service use DBus :)