Message overflow in notification bubble

I posted this a while ago on a (now) deleted Q/A. Maybe it is useful to you.


A patch to allow (very) long messages

The "patch" below will allow you to have notifications as long as it takes on your desktop:

In case of (very) long notifications, instead of this:

enter image description here

you will see this:

enter image description here

The duration of the message is automatically set to the length of the text.

What it does

Notifications, send by notify-osd (notify-send), are limited to appr. 120 characters.
The solution "listens" to sent messages, using dbus-monitor. If a message exceeds the 120 characters, it takes over the messages and uses "its own" message window to display the notification, as shown above.

The scripts

  1. The setup exists of two sections; de "listen-" script, which intercepts the notifications:

    #!/bin/bash
    
    currdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
    
    dbus-monitor "interface='org.freedesktop.Notifications'" |\
     grep --line-buffered "string" |\
     grep --line-buffered -e method -e ":" -e '""' -e urgency -e notify -v |\
     grep --line-buffered '.*(?=string)|(?<=string).*' -oPi |\
     grep --line-buffered -v '^\s*$' |\
     xargs -I '{}' $currdir/message {}
    

    Copy the script into an empty file and save it as catch_notifs.sh

  2. The script that creates the replacement- notifications:

    #!/usr/bin/env python3
    import subprocess
    import os
    import gi
    gi.require_version('Gtk', '3.0')
    from gi.repository import GObject, Gtk, Gdk, Pango
    from threading import Thread
    import time
    import sys
    
    text = sys.argv[1]
    length = len(text)
    showtime = length/20
    
    def get_screen():
        scr = [s.split("x") for s in subprocess.check_output([
            "xrandr"]).decode("utf-8").split() if "+0+0" in s][0]
        return int(scr[0]) -450
    
    class Splash(Gtk.Window):
    
        def __init__(self):
            Gtk.Window.__init__(self, title="splashtitle")
            maingrid = Gtk.Grid()
            self.add(maingrid)
            maingrid.set_border_width(20)
            label = Gtk.Label(text)
            label.set_line_wrap(True)
            label.set_max_width_chars(45)
            label.modify_font(Pango.FontDescription('Ubuntu 11'))
            maingrid.attach(label, 0, 0, 1, 1)
            self.stop = Thread(target=self.close_window)
            self.stop.start()
    
        def close_window(self):
            time.sleep(showtime)
            Gtk.main_quit()
    
    def splashwindow():
        window = Splash()
        window.set_decorated(False)
        window.set_resizable(False)
        window.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(0,0,0,1))
        window.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("white"))
        # window.set_opacity(0.8)
        window.move(get_screen(), 80)
        window.set_keep_above(True)
        window.show_all()
        window.set_default_size(200, 500)
        GObject.threads_init()
        Gtk.main()
    
    if len(text) > 120:
        subprocess.Popen(["pkill", "notify-osd"])
        splashwindow()
    

    Copy the script above into an empty file, save it as (exactly!) message (no extension) and make it executable.

  3. Store both scripts in one and the same directory.
  4. Test- run the script by the command (from a terminal window):

    /bin/bash /path/to/catch_notifs.sh
    

    (keep it running)

    You can test the setup by running (in another terminal):

    notify-send '<long_text>'
    
  5. If all works fine, add it to Startup Applications: Dash > Startup Applications > Add. Add the command:

    /bin/bash /path/to/catch_notifs.sh
    

And it should work :)


As I've noted in the comments , notify-osd is not very suitable for extensive messages and one should prefer zenity instead.

Simple example of usage would be spawning zenity dialog via subprocess.call([COMMAND,OPTIONS])

import subprocess 

text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
command=['zenity', '--info', '--text="' +text + '"', '--width=250', '--height=300' ]
subprocess.call(command)

Very simple example. With something that requires checking exit status, like questions , you might wanna use try - except - else structure

import subprocess 

text='Do you want to use Zenity?'
command=['zenity', '--question', 
         '--text="' +text + '"',
         '--width=250', '--height=300' ]


try:
    stdout = subprocess.check_call(command)

except subprocess.CalledProcessError:
    pass # if return sttus is non-zero, do something here

else:
    # if exit status was 0 , we do something here
    print "Yes, I want to use Zenity too"

If you want something more advanced, probably consider learning one of the graphic toolkits like PyQt or Gtk.