diff --git a/not2osd b/not2osd new file mode 100755 index 0000000000000000000000000000000000000000..487f284cdd342b8448009757ef4c19055896db28 --- /dev/null +++ b/not2osd @@ -0,0 +1,181 @@ +#!/usr/bin/env python2 + +# +# not2osd - Bridge from DBus notifications to osd +# +# Copyright (c) 2009 by Henrik Hallberg (halhen@k2h.se) [program statnot] +# http://code.k2h.se +# Copyright (c) 2021 by Jiří Kalvoda (jirikalvoda@kam.mff.cuni.cz) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import dbus +import dbus.service +import dbus.mainloop.glib +import gobject +import os +import subprocess +import sys +import thread +import time +from htmlentitydefs import name2codepoint as n2cp +import re + + + +def strip_tags(value): + "Return the given HTML with all tags stripped." + return re.sub(r'<[^>]*?>', '', value) + +# from http://snipplr.com/view/19472/decode-html-entities/ +# also on http://snippets.dzone.com/posts/show/4569 +def substitute_entity(match): + ent = match.group(3) + if match.group(1) == "#": + if match.group(2) == '': + return unichr(int(ent)) + elif match.group(2) == 'x': + return unichr(int('0x'+ent, 16)) + else: + cp = n2cp.get(ent) + if cp: + return unichr(cp) + else: + return match.group() + +def decode_htmlentities(string): + entity_re = re.compile(r'&(#?)(x?)(\w+);') + return entity_re.subn(substitute_entity, string)[0] + + + +class NotificationFetcher(dbus.service.Object): + _id = 0 + + @dbus.service.method("org.freedesktop.Notifications", + in_signature='susssasa{ss}i', + out_signature='u') + def Notify(self, app_name, notification_id, app_icon, + summary, body, actions, hints, expire_timeout): + print "app_name", app_name + print "notification_id", notification_id + print "app_icon", app_icon + print "summary", summary + print "body", body + print "actions", actions + print "expire_timeout", expire_timeout + su = strip_tags(unicode(summary)).split("\n") + bo = strip_tags(unicode(body)).split("\n") + for i in range(len(su)): + if su[i]!="" and su[i][0]=='-': + su[i] = ' '+su[i]; + for i in range(len(bo)): + if bo[i]!="" and bo[i][0]=='-': + bo[i] = ' '+bo[i]; + if (expire_timeout <= 0) or (expire_timeout > 20000): + expire_timeout = 5000 + cmd = ["osdc","--duration="+str(expire_timeout),"--min-duration=1000","--color=blue","--outline-color=red"] + su + ["--outline-color=black"] + bo + subprocess.call(cmd) + + + if not notification_id: + self._id += 1 + notification_id = self._id + + text = ("%s %s" % (summary, body)).strip() + add_notification( [notification_id, + text[:NOTIFICATION_MAX_LENGTH], + int(expire_timeout) / 1000.0] ) + return notification_id + + @dbus.service.method("org.freedesktop.Notifications", in_signature='', out_signature='as') + def GetCapabilities(self): + return ('actions', 'body', 'body-hyperlinks', 'body-markup') + + @dbus.service.signal('org.freedesktop.Notifications', signature='uu') + def NotificationClosed(self, id_in, reason_in): + pass + + @dbus.service.method("org.freedesktop.Notifications", in_signature='u', out_signature='') + def CloseNotification(self, id): + pass + + @dbus.service.method("org.freedesktop.Notifications", in_signature='', out_signature='ssss') + def GetServerInformation(self): + return ("statnot", "http://code.k2h.se", "0.0.2", "1") + +if __name__ == '__main__': + for curarg in sys.argv[1:]: + if curarg in ('-v', '--version'): + #print "%s CURVERSION" % sys.argv[0] + sys.exit(1) + elif curarg in ('-h', '--help'): + #print " Usage: %s [-h] [--help] [-v] [--version] [configuration file]" % sys.argv[0] + #print " -h, --help: Print this help and exit" + #print " -v, --version: Print version and exit" + #print "" + #print " Configuration:" + #print " A file can be read to set the configuration." + #print " This configuration file must be written in valid python," + #print " which will be read if the filename is given on the command line." + #print " You do only need to set the variables you want to change, and can" + #print " leave the rest out." + #print "" + ##print " Below is an example of a configuration which sets the defaults." + #print "" + #print " # Default time a notification is show, unless specified in notification" + #print " DEFAULT_NOTIFY_TIMEOUT = 3000 # milliseconds" + #print " " + #print " # Maximum time a notification is allowed to show" + ###print " MAX_NOTIFY_TIMEOUT = 5000 # milliseconds" + #print " " + #print " # Maximum number of characters in a notification. " + #print " NOTIFICATION_MAX_LENGTH = 100 # number of characters" + #print " " + #print " # Time between regular status updates" + #print " STATUS_UPDATE_INTERVAL = 2.0 # seconds" + #print " " + ##print " # Command to fetch status text from. We read from stdout." + #print " # Each argument must be an element in the array" + ##print " # os must be imported to use os.getenv" + ##print " import os" + #print " STATUS_COMMAND = ['/bin/sh', '%s/.statusline.sh' % os.getenv('HOME')] " + ##print "" + #print " # Always show text from STATUS_COMMAND? If false, only show notifications" + #print " USE_STATUSTEXT=True" + #print " " + #print " # Put incoming notifications in a queue, so each one is shown." + #print " # If false, the most recent notification is shown directly." + #print " QUEUE_NOTIFICATIONS=True" + #print " " + #print " # update_text(text) is called when the status text should be updated" + #print " # If there is a pending notification to be formatted, it is appended as" + #print " # the final argument to the STATUS_COMMAND, e.g. as $1 in default shellscript" + ##print "" + #print " # dwm statusbar update" + #print " import subprocess" + #print " def update_text(text):" + #print " subprocess.call(['xsetroot', '-name', text])" + sys.exit(1) + + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + session_bus = dbus.SessionBus() + name = dbus.service.BusName("org.freedesktop.Notifications", session_bus) + nf = NotificationFetcher(session_bus, '/org/freedesktop/Notifications') + + context = gobject.MainLoop().get_context() + + while 1: + context.iteration(True) +