awesome icon indicating copy to clipboard operation
awesome copied to clipboard

textclock: should update immediately after suspending more than 1 minute

Open blueyed opened this issue 10 years ago • 15 comments

I've noticed that the textclock is not being updated immediately after resuming from suspend, although the maximum of 59 seconds for the timer have passed.

It seems like the glib timer does not use absolute time, but is relative? Can we do something about this?

I think the relative behavior is good in general, but not for the textclock widget.

blueyed avatar Jul 23 '15 23:07 blueyed

Daniel Hahler wrote:

I've noticed that the textclock is not being updated immediately after resuming from suspend, although the maximum of 59 seconds for the timer have passed.

It seems like the glib timer does not use absolute time, but is relative? Can we do something about this? Yes ;) Catch the resume and do the update. For systemd (and consolekit?) it should be simply connecting to a dbus signal. Triggering a signal would be really great because it would simplify updating other widgets. I personally would like to get current battery state directly after resume.

I think the relative behavior is good in general, but not for the textclock widget.


Reply to this email directly or view it on GitHub: https://github.com/awesomeWM/awesome/issues/344

ff2000 avatar Jul 24 '15 06:07 ff2000

@ff2000 Sounds like a plan: awesome would connect to the D-Bus signal(s) and then emit one itself internally, e.g. resume (according to the already existing startup).

Do you feel like creating a PR for this?

blueyed avatar Jul 24 '15 13:07 blueyed

On Fri, 24 Jul 2015 06:43:07 -0700, Daniel Hahler [email protected] wrote:

@ff2000 Sounds like a plan: awesome would connect to the D-Bus signal(s) and then emit one itself internally, e.g. resume (according to the already existing startup).

Do you feel like creating a PR for this? Sorry for the late reply... My lua is still bad as hell (my dbus is even worse), so it would be great if you could do that.

I just had the idea of a complete "system" module, that would encapsulate system calls like "reboot" or "hibernate" and add signals for system actions like "resumed" or "about-to-shutdown" and so on. (that's when I remembered this issue...)

Do you think that's doable?


Reply to this email directly or view it on GitHub: https://github.com/awesomeWM/awesome/issues/344#issuecomment-124525215Non-text part: text/html

ff2000 avatar Aug 19 '15 14:08 ff2000

I guess it's more on the C side, which would "just" need to hook into dbus and then emit the signal.

The "system module" would be just a particular set of signals then, e.g. system::resumed.

I've came across xss-lock, which provides calling a screenlocker when the system gets resumed. That code might be relevant: https://bitbucket.org/raymonad/xss-lock/src/1e158fb20108058dbd62bd51d8e8c003c0a48717/src/xss-lock.c?at=master.

blueyed avatar Aug 19 '15 19:08 blueyed

Do we really want systemd-specific code in awesome? :-( Also, I think it would be better to implement that in lua. Sadly, as far as I know, no one found good lua dbus bindings so far (or gdbus bindings).

Oh. Systemd's dbus API likely can't be used from lua. It requires FD passing (at least for some things?).

Edit: Two more hints about possible DBus APIs: http://askubuntu.com/questions/183516/how-do-i-detect-when-my-system-wakes-up-from-suspend-via-dbus-or-similar-in-a-py

psychon avatar Aug 20 '15 08:08 psychon

For reference: https://www.freedesktop.org/wiki/Software/systemd/logind/

blueyed avatar Sep 08 '17 21:09 blueyed

@blueyed Could you test if the following program does what I think it should be doing? (Great description, right? :-) )

local lgi = require("lgi")
local Gio = lgi.require("Gio")

local function listen_to_signals()
	local bus = lgi.Gio.bus_get_sync(Gio.BusType.SYSTEM)
	local sender = "org.freedesktop.login1"
	local interface = "org.freedesktop.login1.Manager"
	local object = "/org/freedesktop/login1"
	local member = "PrepareForSleep"
	bus:signal_subscribe(sender, interface, member, object, nil, Gio.DBusSignalFlags.NONE, function(bus, sender, object, interface, signal, params)
		-- "signals are sent right before (with the argument True) and
		-- after (with the argument False) the system goes down for
		-- reboot/poweroff, resp. suspend/hibernate."
		if not params[1] then
			print(os.date("%c"), "We are after suspend!")
		else
			print(os.date("%c"), "We are BEFORE suspend (this case should not be interesting)")
		end
	end)
end

listen_to_signals()
lgi.GLib.MainLoop():run()

psychon avatar Sep 10 '17 13:09 psychon

@psychon Yes, it works as expected!

I could see the "before" message just before suspending, and the other then after/when resuming.

blueyed avatar Sep 10 '17 13:09 blueyed

@blueyed Together with #2034 and the default config, the following (untested) code should work for you. Should this be added to the FAQ, the recipes, or something like that?

local lgi = require("lgi")
local Gio = lgi.require("Gio")

local function listen_to_signals()
	local bus = lgi.Gio.bus_get_sync(Gio.BusType.SYSTEM)
	local sender = "org.freedesktop.login1"
	local interface = "org.freedesktop.login1.Manager"
	local object = "/org/freedesktop/login1"
	local member = "PrepareForSleep"
	bus:signal_subscribe(sender, interface, member, object, nil, Gio.DBusSignalFlags.NONE,
	function(bus, sender, object, interface, signal, params)
		-- "signals are sent right before (with the argument True) and
		-- after (with the argument False) the system goes down for
		-- reboot/poweroff, resp. suspend/hibernate."
		if not params[1] then
			require("gears.timer").start_new(2, function()
				mytextclock:force_update()
			end)
		end
	end)
end

listen_to_signals()

Edit: Of course, no idea if the delay of two seconds is needed. Feel free to try without.

psychon avatar Sep 10 '17 16:09 psychon

So, what's the plan here? Do we really want this in awesome, or is it enough somewhere in the docs/recipes? If in awesome, you suggested adding an abstraction layer around it. So, gears.system that provides a singleton object on which various signals are emitted? Would it just abstract over logind/systemd, or are there other implementations that could be written?

psychon avatar Sep 11 '17 08:09 psychon

I am not sure, but I think having this functionality (the textclock updating it after resuming) in awesome by default makes sense.

blueyed avatar Sep 11 '17 12:09 blueyed

@blueyed Together with #2034 and the default config, the following (untested) code should work for you. Should this be added to the FAQ, the recipes, or something like that?

local lgi = require("lgi")
local Gio = lgi.require("Gio")

local function listen_to_signals()
	local bus = lgi.Gio.bus_get_sync(Gio.BusType.SYSTEM)
	local sender = "org.freedesktop.login1"
	local interface = "org.freedesktop.login1.Manager"
	local object = "/org/freedesktop/login1"
	local member = "PrepareForSleep"
	bus:signal_subscribe(sender, interface, member, object, nil, Gio.DBusSignalFlags.NONE,
	function(bus, sender, object, interface, signal, params)
		-- "signals are sent right before (with the argument True) and
		-- after (with the argument False) the system goes down for
		-- reboot/poweroff, resp. suspend/hibernate."
		if not params[1] then
			require("gears.timer").start_new(2, function()
				mytextclock:force_update()
			end)
		end
	end)
end

listen_to_signals()

Edit: Of course, no idea if the delay of two seconds is needed. Feel free to try without.

Was searching for how could this problem be solved and came across this, unfortunately this doesn't seem to work as intended, as despite subscribing to the signal being successful. It never ends up firing after resuming from suspend.

SteelT1 avatar Jul 09 '23 22:07 SteelT1

There's also some old-ish commit in one of my experimental branch here

https://github.com/Elv13/awesome-1/commits/experimental2

Those commits extend the gears.timer API and use the internal event loop ticks to detect wake-ups. This branch is missing a bunch of things and most of the API it adds have bugs in some corner case. It's pretty low in my priority list and honestly I just have too little time these days to ever get to work on things like that. If someone want to cherry pick those commits and get them to the finish line, it would be appreciated.

The goal of those commits was/is to fix the clock and have alarm clock level features built in the API. This has use cases like "change color theme based on time of day" or "have a calendar popup with basic iCal features". It also has the stuff a actually align the clock correctly to :00 or whatever granularity it needs.

Elv13 avatar Jul 09 '23 23:07 Elv13

@SteelT1 I modified psychon example to work although I used the dbus_proxy library instead of Gio directly so you will need that installed.

suspend_hook.lua

local p = require('dbus_proxy')

local proxy = p.Proxy:new {
    bus = p.Bus.SYSTEM,
    name = 'org.freedesktop.login1',
    interface = 'org.freedesktop.login1.Manager',
    path = '/org/freedesktop/login1'
}

local suspend_hook = {
    before = {},
    after  = {},
}

local function suspend_resume(_, suspend)
    if suspend then
        for _, callback in ipairs(suspend_hook.before) do
            callback()
        end
    else -- Resume
        for _, callback in ipairs(suspend_hook.after) do
            callback()
        end
    end
end
proxy:connect_signal(suspend_resume, 'PrepareForSleep', nil)

function suspend_hook:add(when, callback)
    table.insert(self[when], callback)
end

return suspend_hook

clock_update_fix.lua

local suspend_hook = require('module.suspend_hook')

-- Clocks can take up to 59 seconds to update when resuming from suspend
-- This fixes that by forcing an update
-- https://github.com/awesomeWM/awesome/issues/344#issuecomment-328354719

local clocks = {}

local clock_fix = {}
function clock_fix.add(clock)
    table.insert(clocks, clock)
end

suspend_hook:add('after', function()
    for _, clock in ipairs(clocks) do
        clock:force_update()
    end
end)

return clock_fix

Lastly add your textclock widgets to the list:

clock.lua

...
local clock_update_fix = require('module.clock_update_fix')

local widget = wibox.widget {
    format = '%H:%M',
    widget = wibox.widget.textclock
}
clock_update_fix.add(widget)
...

unai-ndz avatar Jul 18 '23 11:07 unai-ndz

@SteelT1 I modified psychon example to work although I used the dbus_proxy library instead of Gio directly so you will need that installed.

suspend_hook.lua

local p = require('dbus_proxy')

local proxy = p.Proxy:new {
    bus = p.Bus.SYSTEM,
    name = 'org.freedesktop.login1',
    interface = 'org.freedesktop.login1.Manager',
    path = '/org/freedesktop/login1'
}

local suspend_hook = {
    before = {},
    after  = {},
}

local function suspend_resume(_, suspend)
    if suspend then
        for _, callback in ipairs(suspend_hook.before) do
            callback()
        end
    else -- Resume
        for _, callback in ipairs(suspend_hook.after) do
            callback()
        end
    end
end
proxy:connect_signal(suspend_resume, 'PrepareForSleep', nil)

function suspend_hook:add(when, callback)
    table.insert(self[when], callback)
end

return suspend_hook

clock_update_fix.lua

local suspend_hook = require('module.suspend_hook')

-- Clocks can take up to 59 seconds to update when resuming from suspend
-- This fixes that by forcing an update
-- https://github.com/awesomeWM/awesome/issues/344#issuecomment-328354719

local clocks = {}

local clock_fix = {}
function clock_fix.add(clock)
    table.insert(clocks, clock)
end

suspend_hook:add('after', function()
    for _, clock in ipairs(clocks) do
        clock:force_update()
    end
end)

return clock_fix

Lastly add your textclock widgets to the list:

clock.lua

...
local clock_update_fix = require('module.clock_update_fix')

local widget = wibox.widget {
    format = '%H:%M',
    widget = wibox.widget.textclock
}
clock_update_fix.add(widget)
...

This works very nicely, thank you!

SteelT1 avatar Jul 18 '23 19:07 SteelT1