notification-hub

distraction-free notification daemon for simple linux desktops.
git clone https://git.ce9e.org/notification-hub.git

commit
0ec504e5d4282a73084c9c9efc0851cc4f69fc0b
parent
3d5ac263b5a8157548aaf2b077559a31c6d0a1d2
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2020-08-09 16:32
rm hub

Diffstat

M notification_hub.py 100 +++---------------------------------------------------------

1 files changed, 5 insertions, 95 deletions


diff --git a/notification_hub.py b/notification_hub.py

@@ -3,8 +3,6 @@
    3     3 # https://stackoverflow.com/questions/28949009/glib-gio-critical-error-while-invoking-a-method-on-dbus-interface
    4     4 
    5     5 import sys
    6    -1 import sqlite3
    7    -1 from datetime import datetime
    8     6 
    9     7 from gi.repository import Gio
   10     8 from gi.repository import GLib
@@ -13,7 +11,6 @@ VERSION = '0.0.0'
   13    11 
   14    12 FDN_PATH = '/org/freedesktop/Notifications'
   15    13 FDN_IFAC = 'org.freedesktop.Notifications'
   16    -1 FDN_IFAC2 = 'org.xi.Hub'
   17    14 
   18    15 INTROSPECTION_XML = """<?xml version="1.0" encoding="UTF-8"?>
   19    16 <node name="/org/freedesktop/Notifications">
@@ -50,89 +47,25 @@ INTROSPECTION_XML = """<?xml version="1.0" encoding="UTF-8"?>
   50    47             <arg name="action_key" type="s"/>
   51    48         </signal>
   52    49    </interface>
   53    -1    <interface name="org.xi.Hub">
   54    -1         <method name="GetNotifications">
   55    -1             <arg direction="out" name="notifications"   type="a(usss)"/>
   56    -1         </method>
   57    -1         <method name="CountNotifications">
   58    -1             <arg direction="out" name="count"           type="u"/>
   59    -1         </method>
   60    -1         <method name="DeleteNotification">
   61    -1             <arg direction="in"  name="id"              type="u"/>
   62    -1         </method>
   63    -1         <signal name="Changed">
   64    -1             <arg name="count"      type="u"/>
   65    -1         </signal>
   66    -1    </interface>
   67    50 </node>"""
   68    51 
   69    -1 # close reasons
   70    -1 EXPIRED = 1
   71    -1 DISMISSED = 2
   72    -1 CLOSED = 3
   73    -1 UNDEFINED = 4
   74    -1 
   75    52 node_info = Gio.DBusNodeInfo.new_for_xml(INTROSPECTION_XML)
   76    -1 dbus_conn = None
   77    -1 db = sqlite3.connect(':memory:')
   78    -1 
   79    -1 
   80    -1 def delete(_id):
   81    -1     db.execute('DELETE from notifications WHERE id=?', (_id,))
   82    -1     sig_changed()
   83    -1 
   84    -1 
   85    -1 def add(sender, app_name, replaces_id, icon, summary, body, actions, hints, timeout):
   86    -1     if replaces_id == 0:
   87    -1         sql = 'INSERT INTO notifications (sender, app_name, summary, dt) VALUES (?, ?, ?, ?)'
   88    -1         db.execute(sql, (sender, app_name, summary, datetime.now()))
   89    -1         db.commit()
   90    -1         sig_changed()
   91    -1         row = db.execute('SELECT last_insert_rowid()').fetchone()
   92    -1         return row[0]
   93    -1     else:
   94    -1         sql = 'UPDATE notifications SET sender=?, app_name=?, summary=?, dt=? WHERE id=?'
   95    -1         db.execute(sql, (sender, app_name, summary, datetime.now(), replaces_id))
   96    -1         db.commit()
   97    -1         sig_changed()
   98    -1         return replaces_id
   99    -1 
  100    -1 
  101    -1 def count():
  102    -1     row = db.execute('SELECT COUNT(*) FROM notifications').fetchone()
  103    -1     return row[0]
  104    -1 
  105    -1 
  106    -1 def getall():
  107    -1     return db.execute('SELECT id, app_name, summary, dt FROM notifications').fetchall()
   -1    53 next_id = 1
  108    54 
  109    55 
  110    56 def on_call(conn, sender, path, interface, method, parameters, invocation, user_data=None):
   -1    57     global next_id
  111    58     if method == 'GetCapabilities':
  112    59         reply = GLib.Variant('()', [])
  113    60     elif method == 'Notify':
  114    61         print(sender, parameters)
  115    -1         value = add(sender, *parameters)
  116    -1         reply = GLib.Variant('(u)', [value])
   -1    62         reply = GLib.Variant('(u)', [next_id])
   -1    63         next_id += 1
  117    64     elif method == 'CloseNotification':
  118    -1         delete(*parameters)
  119    65         reply = None
  120    66     elif method == 'GetServerInformation':
  121    67         info = ['notification-hub', 'xi', VERSION, '1.2']
  122    68         reply = GLib.Variant('(ssss)', info)
  123    -1     elif method == 'CountNotifications':
  124    -1         reply = GLib.Variant('(u)', [count()])
  125    -1     elif method == 'GetNotifications':
  126    -1         l = getall()
  127    -1         builder = GLib.VariantBuilder(GLib.VariantType('a(usss)'))
  128    -1         for notification in l:
  129    -1             builder.add_value(GLib.Variant('(usss)', notification))
  130    -1         reply = builder.end()
  131    -1         reply = GLib.Variant.new_tuple(reply)
  132    -1     elif method == 'DeleteNotification':
  133    -1         delete(*parameters)
  134    -1         sig_notification_closed(*parameters, DISMISSED)
  135    -1         reply = None
  136    69     else:
  137    70         print(f'Unknown method: {method}')
  138    71         return
@@ -140,23 +73,8 @@ def on_call(conn, sender, path, interface, method, parameters, invocation, user_
  140    73     conn.flush()
  141    74 
  142    75 
  143    -1 def sig_notification_closed(_id, reason):
  144    -1     # TODO: send only to owner of notification
  145    -1     body = GLib.Variant('(uu)', (_id, reason))
  146    -1     dbus_conn.emit_signal(None, FDN_PATH, FDN_IFAC, 'NotificationClosed', body);
  147    -1 
  148    -1 
  149    -1 def sig_changed():
  150    -1     body = GLib.Variant('(u)', [count()])
  151    -1     dbus_conn.emit_signal(None, FDN_PATH, FDN_IFAC2, 'Changed', body);
  152    -1 
  153    -1 
  154    76 def on_bus_acquired(conn, name, user_data=None):
  155    -1     global dbus_conn
  156    -1     dbus_conn = conn
  157    -1 
  158    77     conn.register_object(FDN_PATH, node_info.interfaces[0], on_call)
  159    -1     conn.register_object(FDN_PATH, node_info.interfaces[1], on_call)
  160    78 
  161    79 
  162    80 def on_name_lost(conn, name, user_data=None):
@@ -164,14 +82,6 @@ def on_name_lost(conn, name, user_data=None):
  164    82 
  165    83 
  166    84 if __name__ == '__main__':
  167    -1     db.execute("""CREATE TABLE IF NOT EXISTS notifications (
  168    -1         id INTEGER PRIMARY KEY,
  169    -1         sender TEXT,
  170    -1         app_name TEXT,
  171    -1         summary TEXT,
  172    -1         dt TEXT
  173    -1     );""")
  174    -1 
  175    85     owner_id = Gio.bus_own_name(
  176    86         Gio.BusType.SESSION,
  177    87         FDN_IFAC,
@@ -184,4 +94,4 @@ if __name__ == '__main__':
  184    94     loop = GLib.MainLoop()
  185    95     loop.run()
  186    96 
  187    -1     Gio.bus_unown_name(owner_id);
   -1    97     Gio.bus_unown_name(owner_id)