Is there a "don't disturb" option to temporarily hide notifications, like on macbooks?

Introduction

The script bellow allows muting any notifications from appearing on screen. There are two basic options -m for mute and -u for unmute. Both are put together into a .desktop file to serve as a launcher.

When -m is used, the notify-osd will send a final notification before being blocked. If there is another instance of script running, it will show a graphical popup that will inform a user that the script is already doing its job.

When called with -u option, the script will stop blocking notifications and will confirm that by showing one. If no previous instance of script is running, the user will be notified that nothing is blocked right now.

Script Source

The script source is available here. For more up-to-date version you can always find it on my github. You can install git with sudo apt-get install git and clone the whole repository with git clone https://github.com/SergKolo/sergrep.git or use

wget https://raw.githubusercontent.com/SergKolo/sergrep/master/notify-block.sh  && chmod +x notify-block.sh

to get just the script itself.

#!/usr/bin/env bash
#
###########################################################
# Author: Serg Kolo , contact: [email protected] 
# Date: May 10th 2016
# Purpose: Notification blocker for Ubuntu
# Written for: 
# Tested on:  Ubuntu 14.04 LTS
###########################################################
# Copyright: Serg Kolo ,2016 
#    
#     Permission to use, copy, modify, and distribute this software is hereby granted
#     without fee, provided that  the copyright notice above and this permission statement
#     appear in all copies.
#
#     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
#     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
#     DEALINGS IN THE SOFTWARE.

ARGV0="$0"
ARGC=$#

mute_notifications()
{ 

  self=${ARGV0##*/}
  CHECK_PID_NUMS=$(pgrep -f  "$self -m" | wc -l )
  if [ "$CHECK_PID_NUMS" -gt 2 ]; then
     zenity --info --text "Notifications already disabled"
     exit 0
  else  
     killall notify-osd 2> /dev/null # ensure we have PID
     notify-send 'All notifications will be muted after this one' 
     sleep 1
     while true 
     do 
        PID=$(pgrep notify-osd)
        [  "x$PID" != "x" ]  && 
        kill -TERM $PID 
        sleep 0.25
     done
  fi
}

unmute()
{
  echo $0
  self=${0##*/}

  MUTE_PID=$(pgrep -f  "$self -m" ) #match self with -m option
  if [ "x$MUTE_PID" != "x"   ];then
     kill -TERM "$MUTE_PID" &&
     sleep 1 && # ensure the previous process exits
     notify-send "UNMUTED"
     exit 0
  else 
     notify-send "NOTIFICATIONS ALREADY UNMUTED"
     exit 0
  fi  
}

print_usage()
{
  cat > /dev/stderr <<EOF
  usage: notify-block.sh [-m|-u]
EOF
exit 1
}
main()
{
  [ $# -eq 0  ] && print_usage

  while getopts "mu" options
  do

     case ${options} in
          m) mute_notifications & ;;
          u) unmute ;;
          \?) print_usage ;;
     esac

  done
}
main "$@"

.desktop shortcut template

This is just an example of what I personally use. Replace each Exec= line with appropriate path to script in your environment. Of course your Icon= will have to be changed as well. Preferably , keep this file in your ~/.local/share/applications folder

[Desktop Entry]
Name=Notification Blocker
Comment=blocks any on-screen notifications
Terminal=false
Actions=Mute;Unmute
Type=Application
Exec=/home/xieerqi/sergrep/notify-block.sh -m
Icon=/home/xieerqi/Desktop/no-notif2.png

[Desktop Action Mute]
Name=Mute Notifications
Exec=/home/xieerqi/sergrep/notify-block.sh -m
Terminal=false

[Desktop Action Unmute]
Name=Unmute Notifications
Exec=/home/xieerqi/sergrep/notify-block.sh -u
Terminal=false

Screenshots

image1

The shortcut file locked to launcher

enter image description here

Final notification before muting


1. Major update

Just finished a completely rewritten version of the indicator (0.9.0). Options now include:

  • suppressing only notifications, containing specific strings
  • suppressing (muting) sound
  • logging missed notifications
  • running on startup
  • remembering the last state (suppressing or not) on next run

Furthermore many, many improvements on interface and behaviour.

enter image description here enter image description here

Installing is unchanged (ppa):

sudo apt-add-repository  ppa:vlijm/nonotifs
sudo apt-get update
sudo apt-get install nonotifs

2. Old(er) answer

Indicator to mute/show notifications

With the indicator below, you can choose to temporarily switch off notifications:

enter image description here

or show notifications:

enter image description here

How it works

The trick is a simple command, using dbus-monitor to intercept upcoming notifications and stop them before they appear.
The indicator is a user-friendly "wrapper" to toggle it off and on.

How to set up


As per now (for Trusty, Vivid, Wily, Xenial):

sudo apt-add-repository  ppa:vlijm/nonotifs
sudo apt-get update
sudo apt-get install nonotifs

This will install globally (including the launcher). Installing via ppa is preferred, since it maintains the latest version, and is regularly updated.
The indicator will appear in Dash as NoNotifications

If you install by the ppa, but previously installed manually from below, please run rm ~/.local/share/applications/nonotif.desktop first to remove the local .desktop file.


Or manually:

The solution exists of a number of items you simply need to store together in one and the same directory.

  1. Create a directory or folder (can be anywhere in your home directory e.g.)
  2. The indicator: Copy the script below into an empty file, save it as nonotif_indicator.py:

    #!/usr/bin/env python3
    import os
    import signal
    import gi
    import subprocess
    gi.require_version('Gtk', '3.0')
    gi.require_version('AppIndicator3', '0.1')
    from gi.repository import Gtk, AppIndicator3
    
    currpath = os.path.dirname(os.path.realpath(__file__))
    proc = "nonotifs.sh"
    
    def run(path):
        try: 
            pid = subprocess.check_output(["pgrep", "-f", proc]).decode("utf-8").strip()
        except subprocess.CalledProcessError:
            subprocess.Popen(path+"/"+proc)
    
    def show():
        try:
            pid = subprocess.check_output(["pgrep", "-f", proc]).decode("utf-8").strip()
            subprocess.Popen(["pkill", "-P", pid])
        except subprocess.CalledProcessError:
            pass
    
    class Indicator():
        def __init__(self):
            self.app = 'nonotif'
            iconpath = currpath+"/grey.png"
            self.testindicator = AppIndicator3.Indicator.new(
                self.app, iconpath,
                AppIndicator3.IndicatorCategory.OTHER)
            self.testindicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)       
            self.testindicator.set_menu(self.create_menu())
    
        def create_menu(self):
            menu = Gtk.Menu()
            item_quit = Gtk.MenuItem('Quit')
            item_quit.connect('activate', self.stop)
            item_silent = Gtk.MenuItem("Don't disturb")
            item_silent.connect('activate', self.silent)
            item_show = Gtk.MenuItem("Show notifications")
            item_show.connect('activate', self.show)
            menu.append(item_quit)
            menu.append(item_silent)
            menu.append(item_show)
            menu.show_all()
            return menu
    
        def stop(self, source):
            Gtk.main_quit()
    
        def silent(self, source):
            self.testindicator.set_icon(currpath+"/red.png")
            run(currpath)
    
        def show(self, source):
            self.testindicator.set_icon(currpath+"/green.png")
            show()
    
    Indicator()
    signal.signal(signal.SIGINT, signal.SIG_DFL)
    Gtk.main()
    
  3. The dbus-monitor script; save it (exactly) as nonotifs.sh in one and the same directory as the first script:

    #!/bin/bash
    dbus-monitor "interface='org.freedesktop.Notifications'" | xargs -I '{}' pkill notify-osd
    

    Make this script executable

  4. Three icons; right-click on each of them and save them together with the two scripts as (exactly):

    enter image description here <-- green.png

    enter image description here <-- red.png

    enter image description here<-- grey.png

  5. That's it. Now test-run the indicator with the command:

    python3 /path/to/nonotif_indicator.py
    

    and switch notifications on/of

Launcher

In case you'd like a launcher with the indicator:

enter image description here

  • Copy the icon below, save it as nonotificon.png:

    enter image description here

  • Copy the code below into an empty file:

    [Desktop Entry]
    Type=Application
    Name=No Notifications
    Exec=python3 /path/to/nonotif_indicator.py
    Icon=/path/to/nonotificon.png
    Type=Application
    
  • Edit the lines:

    Exec=python3 /path/to/nonotif_indicator.py
    

    and

    Icon=/path/to/nonotificon.png
    

    according to the actual paths, and save the file as nonotif.desktop in ~/.local/share/applications

Add the indicator to Startup Applications

You can add the indicator to Startup Applications: Dash > Startup Applications > Add. Add the command:

/bin/bash -c "sleep 15 && python3 /path/to/nonotif_indicator.py"