Skip to content

Commit 66e6110

Browse files
committed
Get basic signals working
1 parent 6c393c9 commit 66e6110

11 files changed

+161
-19
lines changed

liboxide/_apps.py

+25
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,23 @@ class Application(APIObject):
3939
("unregister", None),
4040
("setEnvironment", None, dict[str, object]),
4141
]
42+
signals = [
43+
("launched",),
44+
("paused",),
45+
("resumed",),
46+
("unregistered",),
47+
("exited", int),
48+
("permissionsChanged", list[str]),
49+
("displayNameChanged", str),
50+
("onPauseChanged", str),
51+
("onResumeChanged", str),
52+
("onStopChanged", str),
53+
("autoStartChanged", bool),
54+
("iconChanged", str),
55+
("environmentChanged", list[str]),
56+
("workingDirectoryChanged", str),
57+
("directoriesChanged", str),
58+
]
4259

4360

4461
@static_init
@@ -62,6 +79,14 @@ class AppsAPI(API):
6279
("getApplicationPath", str, str),
6380
("previousApplication", Application),
6481
]
82+
signals = [
83+
("applicationRegistered", Application),
84+
("applicationLaunched", Application),
85+
("applicationUnregistered", Application),
86+
("applicationPaused", Application),
87+
("applicationResumed", Application),
88+
("applicationExited", Application, int),
89+
]
6590

6691
@classmethod
6792
def getApplication(cls, name):

liboxide/_base.py

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
1-
from ._util import _registerProperty
1+
from ._util import _listenMethod
22
from ._util import _registerMethod
3+
from ._util import _registerProperty
4+
5+
6+
class SignalHandler:
7+
def __init__(self, host):
8+
self.__host = host
9+
10+
def __getattr__(self, name):
11+
for _name, *signature in self.__host.signals:
12+
if name == _name:
13+
return _listenMethod(self.__host, name, *signature)
14+
15+
raise NotImplementedError(name)
316

417

518
class API:
619
rotArgs = []
720
properties = []
821
methods = []
22+
signals = []
923

1024
@staticmethod
1125
def _raise(e):
1226
raise e
1327

1428
@classmethod
1529
def static_init(cls):
30+
cls.on = SignalHandler(cls)
1631
cls.rotArgs = [cls.__name__.lower()[:-3]]
1732
for name in cls.properties:
1833
_registerProperty(cls, name)
@@ -26,8 +41,10 @@ class APIObject:
2641
folder = None
2742
properties = []
2843
methods = []
44+
signals = []
2945

3046
def __init__(self, path):
47+
self.on = SignalHandler(self)
3148
if self.__class__.folder is None:
3249
self.__class__.folder = self.__class__.__name__.lower()
3350

liboxide/_errors.py

+8
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,11 @@ class TooManyArguments(Exception):
44

55
class TooFewArguments(Exception):
66
pass
7+
8+
9+
class ObjectNotFound(Exception):
10+
pass
11+
12+
13+
class RotException(Exception):
14+
pass

liboxide/_notification.py

+11
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ class Notification(APIObject):
1919
("remove", None),
2020
("click", None),
2121
]
22+
signals = [
23+
("changed", dict[str, str]),
24+
("removed",),
25+
("displayed",),
26+
("clicked",),
27+
]
2228

2329

2430
@static_init
@@ -33,6 +39,11 @@ class NotificationAPI(API):
3339
("take", Notification, bool, str),
3440
("get", Notification, str),
3541
]
42+
signals = [
43+
("notificationAdded", Notification),
44+
("notificationRemoved", Notification),
45+
("notificationChanged", Notification),
46+
]
3647

3748
@classproperty
3849
def notifications(cls):

liboxide/_power.py

+9
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,12 @@ class PowerAPI(API):
1111
"batteryTemperature",
1212
"chargerState",
1313
]
14+
signals = [
15+
("stateChanged", int),
16+
("batteryStateChanged", int),
17+
("batteryLevelChanged", int),
18+
("batteryTemperatureChanged", int),
19+
("batteryWarning",),
20+
("batteryAlert",),
21+
("chargerWarning",),
22+
]

liboxide/_screen.py

+9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ class Screenshot(APIObject):
1414
methods = [
1515
("remove", None),
1616
]
17+
signals = [
18+
("modified",),
19+
("removed",),
20+
]
1721

1822

1923
@static_init
@@ -26,6 +30,11 @@ class ScreenAPI(API):
2630
("drawFullScreenImage", Screenshot, str),
2731
("screenshot", Screenshot),
2832
]
33+
signals = [
34+
("screenshotAdded", Screenshot),
35+
("screenshotRemoved", Screenshot),
36+
("screenshotModified", Screenshot),
37+
]
2938

3039
@classproperty
3140
def screenshots(cls):

liboxide/_system.py

+11
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,14 @@ class SystemAPI(API):
1919
("inhibitPowerOff", None),
2020
("uninhibitPowerOff", None),
2121
]
22+
signals = [
23+
("leftAction",),
24+
("homeAction",),
25+
("rightAction",),
26+
("powerAction",),
27+
("sleepInhibitedChanged", bool),
28+
("powerOffInhibitedChanged", bool),
29+
("autoSleepChanged", bool),
30+
("deviceSuspending",),
31+
("deviceResuming",),
32+
]

liboxide/_util.py

+44-17
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
from ._errors import TooFewArguments
66
from ._errors import TooManyArguments
7+
from ._errors import ObjectNotFound
8+
from ._errors import RotException
79

810

911
def static_init(cls):
@@ -24,9 +26,16 @@ def __contains__(self, obj):
2426

2527

2628
def rot(*args):
27-
stdout = subprocess.check_output(["/opt/bin/rot"] + list(args))
28-
if stdout:
29-
return json.loads(stdout)
29+
try:
30+
stdout = subprocess.check_output(["/opt/bin/rot"] + list(args))
31+
if stdout:
32+
return json.loads(stdout)
33+
except subprocess.CalledProcessError as e:
34+
stdout = e.output.decode("utf-8")
35+
if "org.freedesktop.DBus.Error.UnknownObject" in stdout:
36+
raise ObjectNotFound(stdout) from e
37+
38+
raise RotException(stdout) from e
3039

3140
return None
3241

@@ -44,6 +53,21 @@ def fn(self):
4453
setattr(obj.__class__, name, property(fn))
4554

4655

56+
def _convert(_type, val):
57+
if _type is None:
58+
return None
59+
60+
from ._base import APIObject
61+
62+
if issubclass(_type, APIObject):
63+
return _type(val)
64+
65+
if _type in (str, bool, int):
66+
return val
67+
68+
raise NotImplementedError(_type)
69+
70+
4771
def _createMethod(cls, name, retType, *signature):
4872
def fn(cls, *args):
4973
if len(args) > len(signature):
@@ -68,23 +92,11 @@ def fn(cls, *args):
6892
elif issubclass(argType, dict):
6993
qtype = "QVariant"
7094
else:
71-
raise NotImplementedError()
95+
raise NotImplementedError(argType)
7296

7397
arguments.append(f"{qtype}:{json.dumps(args[0])}")
7498

75-
res = rot(*cls.rotArgs, "call", name, *arguments)
76-
if retType is None:
77-
return None
78-
79-
from ._base import APIObject
80-
81-
if issubclass(APIObject, retType):
82-
return retType(res)
83-
84-
if retType in (str, bool, int):
85-
return res
86-
87-
raise NotImplementedError()
99+
return _convert(retType, rot(*cls.rotArgs, "call", name, *arguments))
88100

89101
return fn
90102

@@ -105,3 +117,18 @@ def _registerMethod(obj, name, retType, *signature):
105117
name,
106118
_createMethod(obj, name, retType, *signature),
107119
)
120+
121+
122+
def _listenMethod(obj, name, *signature):
123+
if len(signature) > 1:
124+
raise NotImplementedError()
125+
126+
# TODO cache these instead of creating them every time
127+
def fn():
128+
res = rot(*obj.rotArgs, "--once", "listen", name)
129+
if signature:
130+
return _convert(signature[0], res)
131+
132+
return res
133+
134+
return fn

liboxide/_wifi.py

+22
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ class Network(APIObject):
1919
("connect", None),
2020
("remove", None),
2121
]
22+
signals = [
23+
("stateChanged", bool),
24+
("propertiesChanged", dict[str, str]),
25+
("connected",),
26+
("disconnected",),
27+
("removed",),
28+
]
2229

2330
@property
2431
def bSSs(self):
@@ -42,6 +49,10 @@ class BSS(APIObject):
4249
methods = [
4350
("connect", Network),
4451
]
52+
signals = [
53+
("removed",),
54+
("propertiesChanged", dict[str, str]),
55+
]
4556

4657
@property
4758
def network(self):
@@ -78,6 +89,17 @@ class WifiAPI(API):
7889
("removeBlob", None, str),
7990
("getBlob", str, str),
8091
]
92+
signals = [
93+
("stateChanged", int),
94+
("linkChanged", int),
95+
("networkAdded", Network),
96+
("networkRemoved", Network),
97+
("networkConnected", Network),
98+
("disconnected",),
99+
("bssFound", BSS),
100+
("bssRemoved", BSS),
101+
("scanningChanged", bool),
102+
]
81103

82104
@classproperty
83105
def bSSs(cls):

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "liboxide"
33
description = "Python wrapper around the oxide command line tools."
44
readme = "README.md"
5-
version = "0.0.1"
5+
version = "0.1.0"
66
requires-python = ">= 3.9"
77
authors = [
88
{name = "Nathaniel van Diepen", email = "[email protected]"},

test.py

+3
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@
1818
print(f"Lockscreen App: {app.displayName}")
1919
autoLock = liboxide.settings.get("autoLock")
2020
print(f"Automatic lock: {autoLock} minutes")
21+
liboxide.wifi.scan(False)
22+
bss = liboxide.wifi.on.bssFound()
23+
print(f"Found BSS for SSID: {bss.ssid}")

0 commit comments

Comments
 (0)