Ubuntu: Problem with `notify-send`



Question:

I have been working in a script to change audio output when you (dis)connect am HDMI screen/TV. Basically it uses UDEV to check any change in the connection and acts accordingly.

Everything works fine except one thing: I can't use notify-send to warn about the change. I use the following code (output is just a wrapper to subprocess.check_output):

output("sudo -u {0} notify-send \"{1}\" \"{2}\"".format(user, title, message))  

but I don get any notification at all.

What is really odd is that if I run hdmi_sound_toggle (as a normal user or with sudo) everything works just fine!

So what could be the problem here? There is any better way to present a notification than with notify-send?


Solution:1

The notify-send has trouble putting notifications on a user's screen when called from a script run by root or another user.

You should use:

output("export DISPLAY=:0; sudo -u {0} notify-send \"{1}\" \"{2}\"".format(user, title, message))  

So, use:

export DISPLAY=:0  

Normally a user is on display :0, but to be sure, you can find which display a user is on using who command as follow:

who | grep -m1 ^username.*\( | awk '{print $5}' | sed 's/[(|)]//g'  

This worked for me in this script.

See also: Can I launch a graphical program on another user's desktop as root?


Solution:2

I was researching a consistent way to notify all X users (as root) and my research (looking at a bunch of places on the net) indicated that although it was possible to use notify-send in this way, it required scripting to find DBUS session info and/or DISPLAY's in use and/or Xauthority file names and locations, and even then sometimes people still couldn't get it to work. In summary, trying to bend notify-send to your will to enable broadcasting to X users will prove to be unreliable (particularly if you upgrade or change distro at some point in the future).

However... on my system the wall command worked like a charm and is incredibly simple to use. The only downside is that it also broadcasts the message to all text terminals/consoles as well. If you don't mind that, then wall might be a better and more reliable option. Note: the user invoking wall must be root.


Solution:3

Radu's answer does not seem to work for me on 16.04. Rather than try to fight the DISPLAY problem which seems to change with different releases, I go about this in a slightly different manner. I create a single script that is called in two ways. A udev rule calls the script, sending some kind of output to a named pipe. Upon login, the script is also started in a service mode. Here it listens to the pipe and runs the desired GUI command.

As an example, I like to receive notifications of USB storage devices as they are attached, and in particular, I like to know what the path of the device is and its serial number (that may seem strange but I have good reasons). Here's the script I use to accomplish this.

#!/bin/bash  # script name: usb-notify.sh  # This script needs to be called at logon with "service" parameter  # This script needs to be called by udev on USB insertion with no parameter    pipe="/tmp/usb-notifications"  if [ "$1" == "service" ]; then      # create the named pipe that will help us trigger events from udev      rm "$pipe"      mkfifo "$pipe"        # This outer while loop ensures that we can process multiple triggers      while true      do          # This inner while loop reads individual trigger events          while read info          do              # run some GUI command. Here, I'm running notify-send              notify-send "USB Inserted" "$(echo -e $info)"          done < "$pipe"      done  else      # Here's where udev triggers our event. If you don't need to pass any arguments      # you  could just as easily pass an empty line as a trigger for the service.      [ -e "$pipe" ] && echo "Device: $DEVNAME\\\nSN: $ID_SERIAL_SHORT" > "$pipe"  fi  

This script then needs to be called in two ways. First, a udev rule needs to be created to call this script. This can be done with the following command (obviously you should change this to watch whatever device should be triggering your script):

echo 'ACTION=="add",KERNEL=="sd?",RUN+="[path-to-script]/usb-notify.sh"' | sudo tee -a /etc/udev/rules.d/80-USB.rules  

Second, you need to call this script with the "service" parameter on login. So, open the "Startup Applications" program and add an entry that runs "[path-to-your-script]/usb-notify.sh service"

This script can be modified to run pretty much any GUI application on udev events. If you don't want other users to be able to watch your pipe, you should probably set restrictive permissions on it.


Solution:4

Do you need to call it with sudo? That might solve the problem.

Alternatively, I found I needed DISPLAY=:0 and XAUTHORITY=/home/<user_name>/.Xauthority set for it to work when running as root (from a systemd service in this case - set with Environment=...).


Solution:5

You can use pynotify instead of a shell command. It's quite simple and is installed by default in Ubuntu. A quick sample:

import pynotify    pynotify.init("Name")  n = pynotify.Notification("Name", "This is a notification")  n.show()  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »