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

GameControllerWakelock: Use freedesktop portal #1914

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 79 additions & 54 deletions blueman/plugins/applet/GameControllerWakelock.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,10 @@
from gettext import gettext as _
import logging
from typing import Any
from typing import Any, Optional

from blueman.bluez.Device import Device
from blueman.Functions import launch
from blueman.plugins.AppletPlugin import AppletPlugin
from blueman.plugins.errors import UnsupportedPlatformError

import gi
gi.require_version('Gdk', '3.0')
try:
gi.require_version('GdkX11', '3.0')
except ValueError:
raise ImportError("Couldn't find required namespace GdkX11")

from gi.repository import Gdk
from gi.repository import GdkX11


if not isinstance(Gdk.Screen.get_default(), GdkX11.X11Screen):
raise UnsupportedPlatformError('Only X11 platform is supported')
from gi.repository import Gio, GLib


class GameControllerWakelock(AppletPlugin):
Expand All @@ -28,51 +13,91 @@ class GameControllerWakelock(AppletPlugin):
__icon__ = "input-gaming-symbolic"

def on_load(self) -> None:
self.wake_lock = 0
screen = Gdk.Screen.get_default()
assert screen is not None
window = screen.get_root_window()
assert isinstance(window, GdkX11.X11Window)
self.root_window_id = "0x%x" % window.get_xid()
self.__locks: int = 0
self._inhibit_request: Optional[str] = None
self._portal_inhibit: Optional[Gio.DBusProxy] = None
self.watch = Gio.bus_watch_name(
Gio.BusType.SESSION,
"org.freedesktop.portal.Desktop",
Gio.BusNameWatcherFlags.NONE,
self._on_name_appeared,
self._on_name_vanished
)

def on_unload(self) -> None:
if self.wake_lock:
self.wake_lock = 1
self.xdg_screensaver("resume")
self.__cleanup()

def __cleanup(self) -> None:
if self._inhibit_request:
self._remove_lock(force=True)

if self._portal_inhibit is not None:
self._portal_inhibit.destroy()
self._portal_inhibit = None

def _on_name_appeared(self, connection: Gio.DBusConnection, name: str, owner: str) -> None:
logging.debug(f"Got name {name} and owner: {owner}")
self._portal_inhibit = Gio.DBusProxy.new_sync(
connection,
Gio.DBusProxyFlags.NONE,
None,
"org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.Inhibit",
None
)

def _on_name_vanished(self, _connection: Gio.DBusConnection, name: str) -> None:
logging.debug(f"ScreenSaver {name} vanished")
self.__cleanup()

def on_device_property_changed(self, path: str, key: str, value: Any) -> None:
if key == "Connected":
klass = Device(obj_path=path)["Class"] & 0x1fff

if klass == 0x504 or klass == 0x508:
if value:
self.xdg_screensaver("suspend")
self._add_lock()
else:
self.xdg_screensaver("resume")

def xdg_screensaver(self, action: str) -> None:
command = f"xdg-screensaver {action} {self.root_window_id}"

if action == "resume":
if self.wake_lock <= 0:
self.wake_lock = 0
elif self.wake_lock > 1:
self.wake_lock -= 1
else:
ret = launch(command, sn=False)
if ret:
self.wake_lock -= 1
else:
logging.error(f"{action} failed")

elif action == "suspend":
if self.wake_lock >= 1:
self.wake_lock += 1
else:
ret = launch(command, sn=False)
if ret:
self.wake_lock += 1
else:
logging.error(f"{action} failed")
self._remove_lock()

def _add_lock(self) -> None:
if self.__locks > 0:
self.__locks += 1
else:
assert self._portal_inhibit is not None
reason = GLib.Variant("s", "Gamecontroller")
request_path = self._portal_inhibit.Inhibit("(sua{sv})", "blueman-applet", 8, {"reason": reason})
logging.debug(request_path)
if request_path:
self.__locks += 1
self._inhibit_request = request_path

logging.debug(f"Adding lock, total {self.__locks}")

def _remove_lock(self, force: bool = False) -> None:
if self._inhibit_request is None:
logging.warning("No inhibit request found")
self.__locks = 0
return

if self.__locks == 1 or force:
proxy = Gio.DBusProxy.new_for_bus_sync(
Gio.BusType.SESSION,
Gio.DBusProxyFlags.NONE,
None,
"org.freedesktop.portal.Desktop",
self._inhibit_request,
"org.freedesktop.portal.Request",
None
)
proxy.Close()
proxy.destroy()
self.__locks -= 1

# We should have no locks remaining
assert self.__locks == 0
else:
self.__locks -= 1

logging.info(f"Number of locks: {self.wake_lock}")
logging.debug(f"Removed lock, total {self.__locks}")