After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 686482 - Use Logind for suspend when using systemd
Use Logind for suspend when using systemd
Status: RESOLVED FIXED
Product: gnome-shell
Classification: Core
Component: general
unspecified
Other All
: Normal normal
: ---
Assigned To: gnome-shell-maint
gnome-shell-maint
: 695899 (view as bug list)
Depends on:
Blocks: systemd 691202
 
 
Reported: 2012-10-19 15:59 UTC by Florian Müllner
Modified: 2013-03-15 21:51 UTC
See Also:
GNOME target: 3.8
GNOME version: ---


Attachments
loginManager: Add support for suspend() (2.89 KB, patch)
2012-10-19 15:59 UTC, Florian Müllner
none Details | Review
powerMenu: Use LoginManager for suspend (2.77 KB, patch)
2012-10-19 15:59 UTC, Florian Müllner
committed Details | Review
userMenu: Use LoginManager for suspend (3.43 KB, patch)
2012-10-19 15:59 UTC, Florian Müllner
committed Details | Review
loginManager: Add support for suspend() (3.15 KB, patch)
2012-10-19 22:30 UTC, Florian Müllner
committed Details | Review
loginManager: Add inhibitor API (6.25 KB, patch)
2012-10-23 14:10 UTC, Florian Müllner
needs-work Details | Review
screenShield: Use inhibitors to lock screen on suspend (2.19 KB, patch)
2012-10-23 14:10 UTC, Florian Müllner
reviewed Details | Review
userMenu: Remove explicit screen lock on suspend (2.24 KB, patch)
2012-10-23 14:10 UTC, Florian Müllner
committed Details | Review
update for the last patch (1.39 KB, patch)
2013-01-05 21:00 UTC, Matthias Clasen
none Details | Review
loginManager: Add inhibitor API (5.30 KB, patch)
2013-02-05 21:25 UTC, Florian Müllner
reviewed Details | Review
screenShield: Use inhibitors to lock screen on suspend (2.51 KB, patch)
2013-02-05 21:25 UTC, Florian Müllner
accepted-commit_now Details | Review
loginManager: Add inhibitor API (4.07 KB, patch)
2013-02-05 22:45 UTC, Florian Müllner
committed Details | Review
screenShield: Use inhibitors to lock screen on suspend (3.00 KB, patch)
2013-02-05 22:46 UTC, Florian Müllner
committed Details | Review

Description Florian Müllner 2012-10-19 15:59:29 UTC
See patches (mostly untested, so review should probably wait for me to do that)
Comment 1 Florian Müllner 2012-10-19 15:59:33 UTC
Created attachment 226837 [details] [review]
loginManager: Add support for suspend()

Logind provides a Suspend method, which we should use instead of
the UPower API when available. Expose this in loginManager, using
the UPower API for the ConsoleKit implementation.
Comment 2 Florian Müllner 2012-10-19 15:59:40 UTC
Created attachment 226838 [details] [review]
powerMenu: Use LoginManager for suspend
Comment 3 Florian Müllner 2012-10-19 15:59:45 UTC
Created attachment 226839 [details] [review]
userMenu: Use LoginManager for suspend
Comment 4 Florian Müllner 2012-10-19 22:30:59 UTC
Created attachment 226860 [details] [review]
loginManager: Add support for suspend()

Fix a couple of issues; I didn't test extensively, but in a quick test suspend works for both systemd and the CK.
Comment 5 Rui Matos 2012-10-20 18:36:22 UTC
Review of attachment 226860 [details] [review]:

Looks good
Comment 6 Rui Matos 2012-10-20 18:36:42 UTC
Review of attachment 226839 [details] [review]:

++
Comment 7 Rui Matos 2012-10-20 18:36:55 UTC
Review of attachment 226838 [details] [review]:

++
Comment 8 Bastien Nocera 2012-10-22 11:42:51 UTC
As per bug 685562 comment 1, gnome-shell should be taking a delay inhibitor with logind and release it when it's finished locking the screen up.
Comment 9 Florian Müllner 2012-10-23 14:10:43 UTC
Created attachment 227058 [details] [review]
loginManager: Add inhibitor API

If screen locking is enabled, the screen shield should drop down
on suspend. Currently this is achieved by either explicitly locking
the screen (when selecting "Suspend" from the user menu) or by
relying on g-s-d delaying the suspension enough time for the shield
to get into place (lid close, power button).
Systemd inhibitors offer a safer way to ensure that the screen is
locked before going to sleep, so add a small abstraction for them
in the loginManager - the ConsoleKit implementation will only
work when suspending explicitly from the shell, and thus does
not offer any improvement over the current situation.
Comment 10 Florian Müllner 2012-10-23 14:10:49 UTC
Created attachment 227059 [details] [review]
screenShield: Use inhibitors to lock screen on suspend

If the screen lock is enabled, lock the screen before suspension.
When using systemd, this will cover both explicitly suspending from
the user menu and suspension initiated by g-s-d (lid close, power
button).
Comment 11 Florian Müllner 2012-10-23 14:10:54 UTC
Created attachment 227060 [details] [review]
userMenu: Remove explicit screen lock on suspend

This is now handled by the screen shield itself.
Comment 12 Florian Müllner 2012-10-23 19:19:20 UTC
Attachment 226838 [details] pushed as 9904434 - powerMenu: Use LoginManager for suspend
Attachment 226839 [details] pushed as fed007e - userMenu: Use LoginManager for suspend
Attachment 226860 [details] pushed as 1f183b8 - loginManager: Add support for suspend()
Comment 13 Rui Matos 2012-10-24 21:20:32 UTC
Review of attachment 227058 [details] [review]:

This looks very neat overall, I only have one doubt although it might stem from some misunderstanding on my part.

::: js/misc/loginManager.js
@@ +324,3 @@
+        if (index > -1)
+            this._inhibitors.splice(index, 1);
+        if (this._inhibitors.length == 0)

Don't you want to call suspend() here so that prepare-for-sleep gets emitted?
Comment 14 Rui Matos 2012-10-24 21:31:01 UTC
Review of attachment 227058 [details] [review]:

::: js/misc/loginManager.js
@@ +324,3 @@
+        if (index > -1)
+            this._inhibitors.splice(index, 1);
+        if (this._inhibitors.length == 0)

Actually, I don't think we want to do this here, do we?

let inhibitor = loginManager.inhibit();
inhibitor.release();
// machine suspends ?

The same goes for the systemd case I think, do we want to release the systemd inhibitor when calling code releases all inhibitors?
Comment 15 Florian Müllner 2012-10-24 22:06:04 UTC
(In reply to comment #13)
> Review of attachment 227058 [details] [review]:
> 
> This looks very neat overall, I only have one doubt although it might stem from
> some misunderstanding on my part.
> 
> ::: js/misc/loginManager.js
> @@ +324,3 @@
> +        if (index > -1)
> +            this._inhibitors.splice(index, 1);
> +        if (this._inhibitors.length == 0)
> 
> Don't you want to call suspend() here so that prepare-for-sleep gets emitted?

No, we already did.

The good code path (systemd) works as follows:

 1. systemd emits PrepareForSleep on suspend
    (either us calling Suspend(), or lid close/power button/whatever)

 2. we emit prepare-for-sleep, to allow shell components to allow shell
    components to get stuff done before suspend by taking an inhibitor

 3. when the last inhibitor is released, we release the systemd inhibitor,
    so systemd goes ahead and suspends


Now the problem with the fallback path is that ConsoleKit doesn't have anything like PrepareForSleep/inhibit(). We still pretend to support the same API, but in reality we only do that for the only case where we know that we are about to suspend - namely, when loginManager.suspend() is called. So the above becomes:

 1.+2. in suspend(), instead of actually suspending we emit prepare-for-sleep,
    to allow shell components yadda yadda ...

 3. when the last inhibitor is released, we do the actual UPower call to suspend


So calling suspend() in 3. would create a loop by going straight back to 1.+2. :-)

On a side note, I've noticed in testing that prepare-for-sleep may end up being called repeatedly. Currently I'm addressing that by guarding against taking multiple inhibitors in the screenShield code (only in my local tree so far), but I'm considering doing something fancier by requiring components to pass an identifier to inhibit() and return an existing inhibitor if it exists.
Comment 16 Matthias Clasen 2012-11-10 18:39:23 UTC
Should we get this landed for 3.7.2 ?
Comment 17 Matthias Clasen 2013-01-05 20:27:15 UTC
Ping.

Can we get this landed ?
Comment 18 Matthias Clasen 2013-01-05 21:00:15 UTC
Created attachment 232836 [details] [review]
update for the last patch
Comment 19 Matthias Clasen 2013-01-05 21:02:32 UTC
Unfortunately, my testing seems to indicate that the dropping of the system inhibitor doesn't work. Not sure whats wrong there. But after I hit Fn-F4, I see the shield come down, and then I have to wait for logind's max. delay timeout before the suspend happens. running systemd-inhibit --list while waiting confirms that that gnome-shell inhibitor is still in place. Despite releaseSystemInhibitor being called.
Comment 20 Jasper St. Pierre (not reading bugmail) 2013-01-23 16:11:39 UTC
Review of attachment 227058 [details] [review]:

::: js/misc/loginManager.js
@@ +186,3 @@
+        inhibitor.connect('released', Lang.bind(this, this._inhibitorReleased));
+        this._inhibitors.push(inhibitor);
+

No newline.

@@ +199,3 @@
+
+    _prepareForSleep: function(proxy, sender, [active]) {
+        if (active) {

What does "active" determine? Whether our inhibitor is active?

So, when we take the "else" path, ensureInhibitor is called, which sets up an inhibitor, and PrepareForSleep is re-emitted with "active" being true? Did I get that right?

@@ +220,3 @@
+                    this._systemdInhibitor = new Gio.UnixInputStream({ fd: fd });
+                } catch(e) {
+                    log(e);

logError, otherwise we'll fail with a TypeError.

@@ +316,3 @@
+        inhibitor.connect('released', Lang.bind(this, this._inhibitorReleased));
+        this._inhibitors.push(inhibitor);
+

No newline.
Comment 21 Jasper St. Pierre (not reading bugmail) 2013-01-23 16:12:15 UTC
Review of attachment 227059 [details] [review]:

::: js/ui/screenShield.js
@@ +423,3 @@
+        this._loginManager.connect('prepare-for-sleep', Lang.bind(this,
+            function() {
+                if (!this._settings.get_boolean(LOCK_ENABLED_KEY))

Not a giant fan of the inline function, would prefer if we had a this._prepareForSleep.
Comment 22 Jasper St. Pierre (not reading bugmail) 2013-01-23 16:12:38 UTC
Review of attachment 227060 [details] [review]:

OK. Feel free to update whatever patch you have to. This review goes to both of them.
Comment 23 Bastien Nocera 2013-01-26 14:37:25 UTC
(In reply to comment #20)
> Review of attachment 227058 [details] [review]:
> @@ +199,3 @@
> +
> +    _prepareForSleep: function(proxy, sender, [active]) {
> +        if (active) {
> 
> What does "active" determine? Whether our inhibitor is active?
> 
> So, when we take the "else" path, ensureInhibitor is called, which sets up an
> inhibitor, and PrepareForSleep is re-emitted with "active" being true? Did I
> get that right?

The gsd power plugin code will shed some light:
        g_variant_get (parameters, "(b)", &is_about_to_suspend);
        if (is_about_to_suspend) {
                handle_suspend_actions (manager);
        } else {
                handle_resume_actions (manager);
        }

is_about_to_suspend is a clearer name.
Comment 24 Florian Müllner 2013-02-05 21:25:08 UTC
Created attachment 235254 [details] [review]
loginManager: Add inhibitor API

- Update for review comments
 - Fix  problem with releasing inhibitor
Comment 25 Florian Müllner 2013-02-05 21:25:53 UTC
Created attachment 235255 [details] [review]
screenShield: Use inhibitors to lock screen on suspend

Don't use an anonymous function for the 'prepare-for-sleep' handler.
Comment 26 Jasper St. Pierre (not reading bugmail) 2013-02-05 21:57:49 UTC
Review of attachment 235254 [details] [review]:

::: js/misc/loginManager.js
@@ +192,3 @@
+            if (this._inhibitors.length == 0)
+                this._releaseSystemdInhibitor();
+        } else /* coming back from suspend */ {

The spec only says that preparation time is over. It says nothing whether it is emitted before or after the actual suspend, only that it "might be emitted after".

Can I some clarification on the state machine, and an update to the docs if it's a guarantee?

@@ +199,3 @@
+    _ensureInhibitor: function() {
+        let inVariant = GLib.Variant.new('(ssss)',
+                                         ['sleep', 'gnome-shell',

who should be "GNOME Shell"

@@ +200,3 @@
+        let inVariant = GLib.Variant.new('(ssss)',
+                                         ['sleep', 'gnome-shell',
+                                         'screen shield', 'delay']);

why should be "Locking the screen", except that's not the right place for this sort of stuff. I think we should take multiple systemd inhibitors so we can change the "why" strings up. I assume the end session dialog will show those instead soon.

Also, I think it should be translated, too.
Comment 27 Jasper St. Pierre (not reading bugmail) 2013-02-05 21:58:02 UTC
Review of attachment 235255 [details] [review]:

OK.
Comment 28 Florian Müllner 2013-02-05 22:19:45 UTC
(In reply to comment #26)
> The spec only says that preparation time is over. It says nothing whether it is
> emitted before or after the actual suspend, only that it "might be emitted
> after".
> 
> Can I some clarification on the state machine, and an update to the docs if
> it's a guarantee?

It doesn't really matter I think, what matters is this:
"It is usually the signal on which applications request a new delay lock in order to be synchronously notified about the next suspend/shutdown."

So what we do (and other users like g-s-d):

 - take an inhibitor on initialization (to indicate that we want to delay
   suspend)
 - do what we need to do when receiving PrepareForSleep(true) and release the
   inhibitor when done (the PrepareForSleep signal is guaranteed to be emitted,
   as there's at least one inhibitor - ours)
 - take a new inhibitor when receiving PrepareForSleep(false) to be notified
   about the next suspend
Comment 29 Florian Müllner 2013-02-05 22:45:49 UTC
Created attachment 235257 [details] [review]
loginManager: Add inhibitor API

Update patch to make the abstraction as thin as possible - LoginManager.inhibit() will now (asynchronously) return an InputStream that consumers are supposed to close to release the inhibitor; the 'prepare-for-sleep' signal has been changed to match the logind one as well.
Comment 30 Florian Müllner 2013-02-05 22:46:09 UTC
Created attachment 235258 [details] [review]
screenShield: Use inhibitors to lock screen on suspend

Update to the new inhibitor API
Comment 31 Jasper St. Pierre (not reading bugmail) 2013-02-05 23:57:22 UTC
Review of attachment 235258 [details] [review]:

OK.

::: js/ui/screenShield.js
@@ +548,3 @@
         this._becameActiveId = 0;
         this._lockTimeoutId = 0;
+        this._suspendInhibitor = null;

Seems to be unused? Did you have a rename in the works?
Comment 32 Jasper St. Pierre (not reading bugmail) 2013-02-05 23:57:27 UTC
Review of attachment 235257 [details] [review]:

OK.
Comment 33 Florian Müllner 2013-02-06 00:04:34 UTC
(In reply to comment #31)
>          this._lockTimeoutId = 0;
> +        this._suspendInhibitor = null;
> 
> Seems to be unused? Did you have a rename in the works?

No, it's a left-over from the previous patch version. Removed.


Attachment 235257 [details] pushed as 8747c0c - loginManager: Add inhibitor API
Attachment 235258 [details] pushed as 6bcad45 - screenShield: Use inhibitors to lock screen on suspend
Comment 34 Florian Müllner 2013-02-06 00:05:54 UTC
Attachment 227060 [details] pushed as 62ce907 - userMenu: Remove explicit screen lock on suspend
Comment 35 Florian Müllner 2013-03-15 21:51:48 UTC
*** Bug 695899 has been marked as a duplicate of this bug. ***