-
Notifications
You must be signed in to change notification settings - Fork 0
/
notify
executable file
·163 lines (155 loc) · 5.36 KB
/
notify
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/python3
#+
# DBussy example -- how to construct a proxy interface using entirely
# local information, without the overhead of actually introspecting
# the bus peer. Invoke this script as follows:
#
# notify [«opts»] «summary» [«body»]
#
# where «summary» is the message summary text, and «body» is the optional
# more detailed message body text (defaults to the empty string if omitted).
# Valid «opts» are:
#
# --app-icon=«icon-name»
# The name of the icon to show. Try names from here:
# <https://specifications.freedesktop.org/icon-naming-spec/latest/ar01s04.html>.
# If omitted, defaults to “dialog-information”.
# --app-name=«app-name»
# the name to specify for the application showing the notification.
# --timeout=«seconds»
# how many seconds to show the notification for. If omitted,
# defaults to 5.0.
#
# Copyright 2018 by Lawrence D'Oliveiro <ldo@geek-central.gen.nz>. This
# script is licensed CC0
# <https://creativecommons.org/publicdomain/zero/1.0/>; do with it
# what you will.
#-
import sys
import asyncio
import getopt
import dbussy as dbus
from dbussy import \
DBUS
import ravel
if hasattr(asyncio, "run") :
# Python ≥ 3.7
asyncio_run = asyncio.run
else :
# Python < 3.7
asyncio_run = asyncio.get_event_loop().run_until_complete
# not exactly equivalent to asyncio.run(), but close enough
#end if
#+
# Interface definition
#-
# The following XML is copied out of an actual introspection on a KDE
# system. This is converted to a more Pythonic dbussy.Introspection
# tree below, which is the format expected by other calls, such as
# ravel.def_proxy_interface(). But it is easy to go back and forth
# between the two formats. I could have substituted the equivalent
# dbussy.Introspection expression here (and saved the parse call), but
# I am using standard D-Bus XML instead because that is what is more
# likely to be available from other sources (e.g. published
# application information, and of course the D-Bus introspection
# mechanism itself).
notifications_xml = \
"""<node>
<interface name="org.freedesktop.Notifications">
<signal name="NotificationClosed">
<arg direction="out" type="u" name="id"/>
<arg direction="out" type="u" name="reason"/>
</signal>
<signal name="ActionInvoked">
<arg direction="out" type="u" name="id"/>
<arg direction="out" type="s" name="action_key"/>
</signal>
<method name="Notify">
<arg direction="out" type="u"/>
<arg direction="in" type="s" name="app_name"/>
<arg direction="in" type="u" name="replaces_id"/>
<arg direction="in" type="s" name="app_icon"/>
<arg direction="in" type="s" name="summary"/>
<arg direction="in" type="s" name="body"/>
<arg direction="in" type="as" name="actions"/>
<arg direction="in" type="a{sv}" name="hints"/>
<arg direction="in" type="i" name="timeout"/>
</method>
<method name="CloseNotification">
<arg direction="in" type="u" name="id"/>
</method>
<method name="GetCapabilities">
<arg direction="out" type="as" name="caps"/>
</method>
<method name="GetServerInformation">
<arg direction="out" type="s" name="name"/>
<arg direction="out" type="s" name="vendor"/>
<arg direction="out" type="s" name="version"/>
<arg direction="out" type="s" name="spec_version"/>
</method>
</interface>
</node>
"""
notifications_bus_name = "org.freedesktop.Notifications"
notifications_object_path = "/org/freedesktop/Notifications"
notifications_interface_name = "org.freedesktop.Notifications"
notifications_introspection = \
dbus.Introspection.parse(notifications_xml).interfaces_by_name[notifications_interface_name]
# convert to my more Pythonic format, and pull out just the relevant
# interface definition
#+
# Mainline
#-
async def mainline() :
app_name = "DBussy Test"
app_icon = "dialog-information"
timeout = 5
opts, args = getopt.getopt \
(
sys.argv[1:],
"",
["app-icon=", "app-name=", "timeout="]
)
if len(args) not in (1, 2) :
raise getopt.GetoptError("need one or two args, the summary and the message body")
#end if
summary = args[0]
body = ""
if len(args) > 1 :
body = args[1]
#end if
for keyword, value in opts :
if keyword == "--app-icon" :
app_icon = value
elif keyword == "--app-name" :
app_name = value
elif keyword == "--timeout" :
timeout = float(value)
assert timeout >= 0
#end if
#end for
conn = await dbus.Connection.bus_get_async(DBUS.BUS_SESSION, private = False)
notifications_proxy = ravel.def_proxy_interface \
(
ravel.INTERFACE.CLIENT,
name = None, # take from interface name
introspected = notifications_introspection,
is_async = True
)
notifications_object = \
notifications_proxy(connection = conn, dest = notifications_bus_name) \
[notifications_object_path]
await notifications_object \
.Notify \
(
app_name = app_name,
replaces_id = 0,
app_icon = app_icon,
summary = summary,
body = body,
actions = [],
hints = {},
timeout = round(timeout * 1000),
)
#end mainline
asyncio_run(mainline())