kernc / xsuspender

:eyes: :computer: :zzz: :battery: Save battery by auto-suspending unfocused X11 applications.

Home Page:https://kernc.github.io/xsuspender/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Xsuspender does not register focus/unfocus events

dbedrenko opened this issue · comments

Hello, firstly, thank you very much for this program! It's just what I need for a few pesky applications that take up CPU even when not being used.

Specs

OS: ArchLinux
Xsuspender version: Latest as-of today (4cce090)
Window Manager: AwesomeWM v4.3
Xorg-server version: 21.1.8

Steps to reproduce

  1. Have this config:
[Default]
suspend_delay = 5
resume_every = 0
resume_for = 0
send_signals = true
only_on_battery = false
auto_suspend_on_battery = true
downclock_on_battery = 0
# Suspend all processes.
suspend_subtree_pattern = .

[Pavucontrol]
match_wm_class_group_contains = Pavucontrol
  1. Open pavucontrol (I tried Chromium and other apps too, any app will do)
  2. Run G_MESSAGES_DEBUG=xsuspender xsuspender in a terminal
  3. Focus Pavucontrol and notice that it's responding to mouse events.
  4. Wait 5 seconds
  5. Pavucontrol stops responding to mouse/keyboard events. No amount of clicking or minimising and re-maximising resumes the process.
  6. Terminate xsuspender to have Pavucontrol resume running.

Here's the output of that:

$ G_MESSAGES_DEBUG=xsuspender xsuspender
(xsuspender:110132): xsuspender-DEBUG: 21:24:53.280: Initializing.
(xsuspender:110132): xsuspender-DEBUG: 21:24:53.282:
needle_wm_class = (null)
needle_wm_class_group = Pavucontrol
needle_wm_name = (null)
delay = 5
resume_every = 0
resume_for = 1
only_on_battery = 0
send_signals = 1
subtree_pattern = .
downclock_on_battery = 0
exec_suspend = (null)
exec_resume = (null)

(xsuspender:110132): xsuspender-DEBUG: 21:25:03.244: AC power = 0; State changed. Suspending/resuming windows.
(xsuspender:110132): xsuspender-DEBUG: 21:25:04.244: kill -STOP 104986
(xsuspender:110132): xsuspender-DEBUG: 21:25:04.244: Exec: pstree 104986 (.) | kill -STOP
(xsuspender:110132): xsuspender-DEBUG: 21:25:04.244:       kill -STOP 104986
^C(xsuspender:110132): xsuspender-DEBUG: 21:25:12.548: Exiting ...
(xsuspender:110132): xsuspender-DEBUG: 21:25:12.549: kill -CONT 104986
(xsuspender:110132): xsuspender-DEBUG: 21:25:12.549: Exec: pstree 104986 (.) | kill -CONT
(xsuspender:110132): xsuspender-DEBUG: 21:25:12.549:       kill -CONT 104986
(xsuspender:110132): xsuspender-DEBUG: 21:25:12.558: Bye.

It seems that whatever mechanism xsuspender uses to listen to the focus/unfocus events isn't working? Can I provide any more info or experiments to help debug this issue?

commented

Yes, you can run the example with G_MESSAGES_DEBUG=all xsuspender to obtain a more verbose output.

We use this to subscribe to window change events:

xsuspender/src/events.c

Lines 16 to 19 in a26b7e7

WnckScreen *screen = wnck_screen_get_default ();
g_signal_connect (screen, "active-window-changed",
G_CALLBACK (on_active_window_changed), NULL);

xsuspender/src/events.c

Lines 80 to 90 in a26b7e7

on_active_window_changed (WnckScreen *screen,
WnckWindow *prev_active_window)
{
WnckWindow *active_window = wnck_screen_get_active_window (screen);
active_window = get_main_window (active_window);
prev_active_window = get_main_window (prev_active_window);
// Main windows are one and the same; do nothing
if (windows_are_same_process (active_window, prev_active_window))
return;

xsuspender/src/events.c

Lines 59 to 76 in a26b7e7

windows_are_same_process (WnckWindow *w1,
WnckWindow *w2)
{
// Consider windows to be of the same process when they
// are one and the same window,
if (w1 == w2)
return TRUE;
// Or when they have the same PID, map to the same rule,
// and the rule says that signals should be sent.
Rule *rule;
return (WNCK_IS_WINDOW (w1) &&
WNCK_IS_WINDOW (w2) &&
wnck_window_get_pid (w1) == wnck_window_get_pid (w2) &&
(rule = xsus_window_get_rule (w1)) &&
rule->send_signals &&
rule == xsus_window_get_rule (w2));
}

Anything strike you as odd?

Thanks for replying so quickly!

I added some debug prints and reran the program. It seems that on_active_window_changed() only gets entered once at the start of the program--and that's even without changing the active window (why is that?). Clicking around windows, minimising and maximising windows and switching virtual desktops back and forth did not trigger this function again.

$ G_MESSAGES_DEBUG=all ./src/xsuspender
(xsuspender:128842): xsuspender-DEBUG: 22:29:07.244: Initializing@@@@@@@@.
(xsuspender:128842): xsuspender-DEBUG: 22:29:07.246:
needle_wm_class = (null)
needle_wm_class_group = Pavucontrol
needle_wm_name = (null)
delay = 5
resume_every = 0
resume_for = 1
only_on_battery = 0
send_signals = 1
subtree_pattern = .
downclock_on_battery = 0
exec_suspend = (null)
exec_resume = (null)

(xsuspender:128842): xsuspender-DEBUG: 22:29:07.246: 8888888 wnck_screen_get_default():
(xsuspender:128842): xsuspender-DEBUG: 22:29:07.246:  s+\xe8\xf7U
(xsuspender:128842): xsuspender-DEBUG: 22:29:07.246:  s+\xe8\xf7U
(xsuspender:128842): xsuspender-DEBUG: 22:29:07.246: @@@@@@ screen 0 found
(xsuspender:128842): xsuspender-DEBUG: 22:29:07.309: 1111 entered on_active_window_changed()
(xsuspender:128842): xsuspender-DEBUG: 22:29:07.309: 55555 entered windows_are_same_process()
(xsuspender:128842): xsuspender-DEBUG: 22:29:07.309: 222222 windows_are_same_process() evaluated to true
(xsuspender:128842): xsuspender-DEBUG: 22:29:17.144: AC power = 0; State changed. Suspending/resuming windows.
(xsuspender:128842): xsuspender-DEBUG: 22:29:18.144: kill -STOP 104986
(xsuspender:128842): xsuspender-DEBUG: 22:29:18.144: Exec: pstree 104986 (.) | kill -STOP
(xsuspender:128842): xsuspender-DEBUG: 22:29:18.145:       kill -STOP 104986
^C(xsuspender:128842): xsuspender-DEBUG: 22:29:24.653: Exiting ...
(xsuspender:128842): xsuspender-DEBUG: 22:29:24.655: kill -CONT 104986
(xsuspender:128842): xsuspender-DEBUG: 22:29:24.656: Exec: pstree 104986 (.) | kill -CONT
(xsuspender:128842): xsuspender-DEBUG: 22:29:24.656:       kill -CONT 104986
(xsuspender:128842): xsuspender-DEBUG: 22:29:24.666: Bye.

I thought that maybe this line could be the cause:

 WnckScreen *screen = wnck_screen_get_default ();

because I have 2 screens, so I thought maybe it's connecting to the other screen than the one I am using. But I disabled 1 screen (via xrandr), and verified with the debug prints that only 1 screen is detected in xsuspender, yet the bug still manifested with the same behaviour.

Any ideas what else I could try? I see 2 issues:

  1. Signal doesn't trigger on_active_window_changed() when I click around different windows
  2. Why the heck is on_active_window_changed() executing that one time? It shouldn't because I have a terminal window open where I type in xsuspender and don't switch to another window. This is mighty suspicious. Just a mere g_signal_connect() call should not trigger the callback: only a signal can.
commented

Make sure the platform is X11 and not Wayland.

If it works with another WM, such as flwm or Xfce, you might ask @awesomeWM guys.

I tested with Openbox and Xfce, but unfortunately it's the same behaviour. The application just seems to fail to listen to window events.

I am definitely not in Wayland:

$ echo $XDG_SESSION_TYPE
x11

For anyone else encountering this issue, you can recreate the suspend functionality in AwesomeWM, just paste this into your rc.lua:

-- Suspend these when not in focus
local classes_to_suspend = {
	["starter.exe"] = true,
	["Pavucontrol"] = true,
}
client.connect_signal("focus",
	function(c)
		if classes_to_suspend[c.class] and c.pid then
			awful.util.spawn_with_shell("kill -s SIGCONT " .. c.pid)
		end
	end)
client.connect_signal("unfocus",
	function(c)
		if classes_to_suspend[c.class] and c.pid then
			awful.util.spawn_with_shell("kill -s SIGSTOP " .. c.pid)
		end
	end)