blueman-project / blueman

Blueman is a GTK+ Bluetooth Manager
GNU General Public License v3.0
1.27k stars 193 forks source link

Handle screensaver independent of X11 #1848

Open cschramm opened 2 years ago

cschramm commented 2 years ago

I think we could use GTK+ power, namely gtk_application_inhibit with GTK_APPLICATION_INHIBIT_IDLE and gtk_application_uninhibit. To my understanding it would save us from the X11 interaction as GTK+ will route it to either its X11 backend or its Wayland backend where it's a noop and since 3.99.0 it even implements the idle-inhibit Wayland protocol (https://gitlab.gnome.org/GNOME/gtk/-/commit/5af7d6bff3d2920aca118a36f13b23cbb68c1641#a64185fe139cee5b6c20bff1d9e5e985a228410f) that should get it working in Wayland as well.

Originally posted by @cschramm in https://github.com/blueman-project/blueman/issues/1461#issuecomment-739582638

infirit commented 2 years ago

Yes we can use that. I remember trying it on KDE once but for some reason it didn't work for me then. But now it's fine. It does depend on a freedesktop portal, not sure we should add that as a dep?

Horrible testscript below.

from gi.repository import Gtk, GLib, Gio

class InhibitApp(Gtk.Application):
    def __init__(self):
        super().__init__(
            application_id="org.blueman.Inhibit",
            flags=Gio.ApplicationFlags.FLAGS_NONE
        )

        self.hold()
        GLib.timeout_add_seconds(5, self.start_inhibit)

    def do_startup(self):
        Gtk.Application.do_startup(self)

    def start_inhibit(self):
        self.inhibit(None, Gtk.ApplicationInhibitFlags.IDLE, "Games")

app = InhibitApp()
app.run()
infirit commented 2 years ago

xdg-deaktop-portal provides a pkgconfig file so we can just add it to the runtime deps. Then it's up to the individual desktop/user to make sure to make sure they provide the required implementations.

cschramm commented 2 years ago

I quickly tested this on MATE and checked the X implementation:

What it does is use a session manager if one is available, specifically interfaces org.gnome.SessionManager and org.xfce.Session.Manager. Otherwise, it uses the Inhibit portal.

MATE actually provides the org.gnome.SessionManager interface that GTK looks for, so it tries to use that. I tried your call in #1896. First thing I got is Warning: g_variant_new_string: assertion 'string != NULL' failed from the g_variant_new as dbus->application_id is NULL so that string [Invalid UTF-8] gets transferred. Not sure if that's related (it probably is as the purpose of that argument is most probably to keep checking if the application is still alive), but the screensaver's idle timeout does jump in.

I then tried the portal fallback manually with xdg-desktop-portal-gtk set up and

Gio.bus_get_sync(Gio.BusType.SESSION).call_sync(
    "org.freedesktop.portal.Desktop",
    "/org/freedesktop/portal/desktop",
    "org.freedesktop.portal.Inhibit",
    "Inhibit",
    GLib.Variant("(sua{sv})", ("", 8, {"reason": GLib.Variant("s", "")})),
    None,
    Gio.DBusCallFlags.NONE,
    -1
)

That seems to have worked. At least my screensaver does not show up at all anymore now and even if I invoke it manually, it is black. :see_no_evil:

cschramm commented 2 years ago

Strike that. Tried again after restart and the portal way did not prevent the screensaver this time. But... I fixed my application_id and now the session manager way does prevent the screensaver as long as the application is running, so the intended way between GTK and MATE does work.

If things do not work for you, I'd expect an issue with xdg-desktop-portal-kde.

cschramm commented 2 years ago

Cinnamon implements org.gnome.SessionManager as well, so I guess most things are covered even without the portal. KDE and LXQt fall back to their portal implementations.

cschramm commented 2 years ago

From a quick glance, ...

The LXQt portal does not implement inhibit at all. It uses xdg-screensaver, so I guess the xset s off implementation in xdg-screensaver should work for it while GTK inhibit probably does not... :unamused:

The GTK portal's inhibit implementation looks pointless for this, as it basically just delegates to org.gnome.SessionManager which GTK would handle preferred anyway.

The KDE portal's inhibit implementation, well, looks like it should do something useful and is in place since 5.10. It delegates to the power manager.

infirit commented 2 years ago

The KDE portal's inhibit implementation, well, looks like it should do something useful and is in place since 5.10. It delegates to the power manager.

It doesn't actually prevent the screen going dark. I do see it show up in the inhibitors list.

Experiment calling directly into the portal #1914.

It's clear to me now the whole portal inhibition is broken on anything but gnome (and those that implement gnome's session manager).