Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xsuspender does not register focus/unfocus events #43

Open
dbedrenko opened this issue Apr 24, 2023 · 4 comments
Open

Xsuspender does not register focus/unfocus events #43

dbedrenko opened this issue Apr 24, 2023 · 4 comments

Comments

@dbedrenko
Copy link

dbedrenko commented Apr 24, 2023

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?

@kernc
Copy link
Owner

kernc commented Apr 25, 2023

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?

@dbedrenko
Copy link
Author

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.

@kernc
Copy link
Owner

kernc commented Apr 25, 2023

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.

@dbedrenko
Copy link
Author

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants