After getting really frustrated with this bug, I spent most of 4th of July weekend wading knee-deep in gnome-session and gnome-screensaver code, but I finally rooted out the bugs behind this. There are two bugs:
Gnome Screensaver activates when the Gnome Session Manager's Presence module (gsm-presence.c) sends a StatusChanged signal over DBus. This signal is sent when an idle watch timer expires. When the timer expires and sends the signal, it needs to be reset. One code path to reset it is triggered when the screensaver activates or deactivates. (Notification of this is via DBus message.) Otherwise, resets are triggered by calls from gsm-manager.c that happen when a) the GConf key corresponding to screensaver timeout is changed (e.g., when the user changes the timeout in the preferences dialog), or b) an inhibitor is added or removed (e.g., when you watch a movie in vlc).
So, if the screensaver is disabled when the idle timer expires, nothing will be able to reset the idle timer. Furthermore, when the user re-enables the screensaver, the timer is still inactive, so the screensaver won't be called. Only by taking some special action, such as logging out&in, changing the screensaver timeout, or manually activating a screensaver, will the timer be re-activated.
I have fixed this by adding a callback in gsm-manager.c that watches for changes to the GConf key corresponding to the screensaver being enabled (/apps/gnome-screensaver/idle_activation_enabled). When this GConf key is changed, the idle watch timer is reset.
The above explains why screensavers are not triggered at all after re-enabling the screensaver. However, even with that fix, the screensaver fades out, but then snaps back to life as soon as the fade is done.
Gnome Screensaver activation is a 2-stage process: first, the gnome-session presence module sends a DBus StatusChanged signal, {gs-watcher-x11.c & gs-monitor.c} checks whether the screensaver is inhibited, and if not, begins a fade-out for 10 seconds. When the 10 seconds have expired, assuming the user has not interrupted the fade-out by doing something, {gs-watcher-x11.c & gs-monitor.c} triggers the screensaver activation. Activation is actually initiated from gs-listener-dbus.c.
Unfortunately, due to some convoluted and muddled logic in listener_check_activation and gs_listener_set_session_idle, if the screensaver is disabled when an idle session signal is received, the gs-listener-dbus.c believes that the session is idle (i.e., the screensaver is on), even though the screensaver is disabled. Then, once the screensaver is re-enabled and begins receiving more idle session notifications, gs-listener-dbus.c ignores those notifications, because it thinks the screensaver is already on! However, the fade-outs operate on a different, uncorrupted state variable, so they are unaffected. Thus, the fade-out happens correctly, but at the moment that the screensaver should activate, nothing happens and the session returns to the desktop.
My fixes to gs-listener-dbus.c maintain the correct state for the session_idle variable, and clean up the logic of the two mentioned functions, while adding comments and debugging messages.
=== Conclusion ===
When both packages are patched and recompiled, the screensaver will resume working correctly after it has been disabled and re-enabled.
The gnome-session patch is against gnome-session_2.30.0-0ubuntu1. To apply, drop it in gnome-session-2.30.0/debian/patches, append a line containing the filename to gnome-session-2.30.0/debian/patches/series, and rebuild.
The gnome-screensaver patch is against gnome-screensaver_2.30.0-0ubuntu2. To apply, drop it in gnome-screensaver-2.30.0/debian/patches and rebuild.
I will work to get these patches in a state where they can be accepted into Ubuntu and upstream. If anyone knows more about the process and could help, that would be appreciated.
After getting really frustrated with this bug, I spent most of 4th of July weekend wading knee-deep in gnome-session and gnome-screensaver code, but I finally rooted out the bugs behind this. There are two bugs:
=== Bug 1 -- gnome-session -- gsm-manager.c ===
Gnome Screensaver activates when the Gnome Session Manager's Presence module (gsm-presence.c) sends a StatusChanged signal over DBus. This signal is sent when an idle watch timer expires. When the timer expires and sends the signal, it needs to be reset. One code path to reset it is triggered when the screensaver activates or deactivates. (Notification of this is via DBus message.) Otherwise, resets are triggered by calls from gsm-manager.c that happen when a) the GConf key corresponding to screensaver timeout is changed (e.g., when the user changes the timeout in the preferences dialog), or b) an inhibitor is added or removed (e.g., when you watch a movie in vlc).
So, if the screensaver is disabled when the idle timer expires, nothing will be able to reset the idle timer. Furthermore, when the user re-enables the screensaver, the timer is still inactive, so the screensaver won't be called. Only by taking some special action, such as logging out&in, changing the screensaver timeout, or manually activating a screensaver, will the timer be re-activated.
I have fixed this by adding a callback in gsm-manager.c that watches for changes to the GConf key corresponding to the screensaver being enabled (/apps/ gnome-screensav er/idle_ activation_ enabled) . When this GConf key is changed, the idle watch timer is reset.
=== Bug 2 -- gnome-screensaver -- gs-listener-dbus.c ===
The above explains why screensavers are not triggered at all after re-enabling the screensaver. However, even with that fix, the screensaver fades out, but then snaps back to life as soon as the fade is done.
Gnome Screensaver activation is a 2-stage process: first, the gnome-session presence module sends a DBus StatusChanged signal, {gs-watcher-x11.c & gs-monitor.c} checks whether the screensaver is inhibited, and if not, begins a fade-out for 10 seconds. When the 10 seconds have expired, assuming the user has not interrupted the fade-out by doing something, {gs-watcher-x11.c & gs-monitor.c} triggers the screensaver activation. Activation is actually initiated from gs-listener-dbus.c.
Unfortunately, due to some convoluted and muddled logic in listener_ check_activatio n and gs_listener_ set_session_ idle, if the screensaver is disabled when an idle session signal is received, the gs-listener-dbus.c believes that the session is idle (i.e., the screensaver is on), even though the screensaver is disabled. Then, once the screensaver is re-enabled and begins receiving more idle session notifications, gs-listener-dbus.c ignores those notifications, because it thinks the screensaver is already on! However, the fade-outs operate on a different, uncorrupted state variable, so they are unaffected. Thus, the fade-out happens correctly, but at the moment that the screensaver should activate, nothing happens and the session returns to the desktop.
My fixes to gs-listener-dbus.c maintain the correct state for the session_idle variable, and clean up the logic of the two mentioned functions, while adding comments and debugging messages.
=== Conclusion ===
When both packages are patched and recompiled, the screensaver will resume working correctly after it has been disabled and re-enabled.
The gnome-session patch is against gnome-session_ 2.30.0- 0ubuntu1. To apply, drop it in gnome-session- 2.30.0/ debian/ patches, append a line containing the filename to gnome-session- 2.30.0/ debian/ patches/ series, and rebuild.
The gnome-screensaver patch is against gnome-screensav er_2.30. 0-0ubuntu2. To apply, drop it in gnome-screensav er-2.30. 0/debian/ patches and rebuild.
I will work to get these patches in a state where they can be accepted into Ubuntu and upstream. If anyone knows more about the process and could help, that would be appreciated.