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.
# 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
if [ "$1" == "service" ]; then
# create the named pipe that will help us trigger events from udev
# This outer while loop ensures that we can process multiple triggers
# This inner while loop reads individual trigger events
while read info
# run some GUI command. Here, I'm running notify-send
notify-send "USB Inserted" "$(echo -e $info)"
done < "$pipe"
# 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"
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.