By using this site, you agree to have cookies stored on your device, strictly for functional purposes, such as storing your session and preferences.

Dismiss

 __init__.py

View raw Download
text/plain • 4.86 kiB
Python script, ASCII text executable
        
            
1
"""
2
D-Bus notifier applet for the Panorama panel.
3
Copyright 2025, roundabout-host.com <vlad@roundabout-host.com>
4
5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public Licence as published by
7
the Free Software Foundation, either version 3 of the Licence, or
8
(at your option) any later version.
9
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public Licence for more details.
14
15
You should have received a copy of the GNU General Public Licence
16
along with this program. If not, see <https://www.gnu.org/licenses/>.
17
"""
18
19
from __future__ import annotations
20
21
import panorama_panel
22
import locale
23
from pathlib import Path
24
from pydbus import SessionBus
25
26
import gi
27
gi.require_version("Gtk", "4.0")
28
29
from gi.repository import Gtk, Gdk, GLib
30
31
32
module_directory = Path(__file__).resolve().parent
33
34
locale.bindtextdomain("panorama-app-menu", module_directory / "locale")
35
_ = lambda x: locale.dgettext("panorama-app-menu", x)
36
37
38
custom_css = """
39
.notification-button {
40
padding: 0;
41
}
42
"""
43
44
css_provider = Gtk.CssProvider()
45
css_provider.load_from_data(custom_css)
46
Gtk.StyleContext.add_provider_for_display(
47
Gdk.Display.get_default(),
48
css_provider,
49
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
50
)
51
52
53
class NotificationsService:
54
"""
55
<node>
56
<interface name="org.freedesktop.Notifications">
57
<method name="GetCapabilities">
58
<arg type="as" name="caps" direction="out"/>
59
</method>
60
<method name="GetServerInformation">
61
<arg type="s" name="name" direction="out"/>
62
<arg type="s" name="vendor" direction="out"/>
63
<arg type="s" name="version" direction="out"/>
64
<arg type="s" name="spec_version" direction="out"/>
65
</method>
66
<method name="Notify">
67
<arg type="s" name="app_name" direction="in"/>
68
<arg type="u" name="replaces_id" direction="in"/>
69
<arg type="s" name="app_icon" direction="in"/>
70
<arg type="s" name="summary" direction="in"/>
71
<arg type="s" name="body" direction="in"/>
72
<arg type="as" name="actions" direction="in"/>
73
<arg type="a{sv}" name="hints" direction="in"/>
74
<arg type="i" name="expire_timeout" direction="in"/>
75
<arg type="u" name="id" direction="out"/>
76
</method>
77
</interface>
78
</node>
79
"""
80
81
def __init__(self, applet: NotifierApplet):
82
self._next_id = 1
83
self.applet = applet
84
85
def GetCapabilities(self):
86
return ["body"]
87
88
def GetServerInformation(self):
89
# name, vendor, version, spec_version
90
return "panorama-panel", "panorama", "0.1", "1.2"
91
92
def Notify(self, *args):
93
notification_id = self._next_id
94
self._next_id += 1
95
self.applet.push_notification(*args)
96
return notification_id
97
98
99
class NotifierApplet(panorama_panel.Applet):
100
name = _("Notification centre")
101
description = _("Get desktop notifications")
102
103
def __init__(self, orientation=Gtk.Orientation.HORIZONTAL, config=None):
104
super().__init__(orientation=orientation, config=config)
105
if config is None:
106
config = {}
107
108
self.button = Gtk.MenuButton()
109
self.button.set_has_frame(False)
110
self.button.add_css_class("notification-button")
111
self.stack = Gtk.Stack()
112
self.button.set_child(self.stack)
113
self.notification_indicator = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
114
self.notification_indicator.append(Gtk.Image.new_from_icon_name(""))
115
self.stack.add_child(self.notification_indicator)
116
self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_UP_DOWN)
117
self.stack.set_transition_duration(500)
118
# TODO: support the other parameters; add a popover with a history
119
self.append(self.button)
120
121
self.service = NotificationsService(self)
122
bus = SessionBus()
123
self.publishing = bus.publish("org.freedesktop.Notifications", self.service)
124
125
def push_notification(self, app_name, replaces_id, app_icon, summary, body, actions, hints, expire_timeout):
126
new_child = Gtk.Label.new(_(summary))
127
self.stack.add_child(new_child)
128
self.stack.set_visible_child(new_child)
129
def remove_notification():
130
self.stack.set_visible_child(self.stack.get_visible_child().get_prev_sibling())
131
def remove_child():
132
self.stack.remove(new_child)
133
GLib.timeout_add(self.stack.get_transition_duration(), remove_child)
134
return False
135
if expire_timeout <= 0:
136
expire_timeout = 2500
137
GLib.timeout_add(expire_timeout, remove_notification)
138
# TODO: notify that it was closed
139
140
def get_config(self):
141
return {}
142
143
def shutdown(self):
144
self.publishing.unpublish()
145