A haskell-written notification center for users that like a desktop with style…
Take part in the discussion on our discussion board!
▙ █ █ ████████████ ███▙ █ ▄██████▄ ███▄ █ █ ████ █ ███▙ █ ████ ██ ▜█████▄ █ █ ████ █ ███▙ █ █ ████ ▜█ ▜██████▄ █ █ ████ █ ███▙ ▙ █ █ ████ █▄ ▜██████▄ █ █ ████████████ █ ███▙ ██▙ █ █ ████ █ ▜█▄ ▜█████▄█ █ ████ █ ███▙ ███▙ █ █ ████ █ ▜█▄ ▜████ █ ████ █ ███▙█ ████ █ ████ █ ▜█▄ ▜█ █ ████ █ ███ █ ██ █▙ █ ████ █ ▜█▄ █ ████ █ █ █ █▙ █ ████ █ ▜▄ █ ████████████ █ █ ▜████▛ ██▛ ▄▇▇▀▀▀▀█▌ ▄▄▄▄▄▀▀██▇█▄▄▀▀▀▀▀ ▄▄▄▄▄▄ ▄▄█▇██▀▀▄▄▄▄▄ ▐█▀▀▀▀▇▇▄ ▐██▌ ▀▀ ▄▄▄████████▄▄█▀ ▄█████▀▀▀███▄ ▀█▄▄████████▄▄▄ ▀▀ ▐██▌ ████▄ ▄▄▄██████████▀▀ ▀▀▀█▄ ▇████▀ ▀▀██▌ ▄█▀▀▀ ▀▀██████████▄▄▄ ▄████ ▀███████████████▀▀ ▐█▌ ██████ ▄ ▐███ ▐█▌ ▀▀███████████████▀ ▀▀▀▀██████▀ ▀▀ ▐██▐▇▇ ▀▀▀▀ ▀▀ ▀██████▀▀▀▀ ▄▄██████▀ ██ ██▌ ▄ ▀██████▄▄ ▄███████▀ █▀██ ▀█▄▄ ▄▄ ▀███████▄ ▄███████ ▀██▄▄█████████▀ ███████▄ ██████ ▀▀█████▀▀▀ ███████ ▐████▌ ▐████▌ ███▄▄▄▄▄▌ ▐▄▄▄▄▄███ ▀▀▀▀▀▀ ▀▀▀▀▀▀ ╒══════╕ NEW │ 2023 │ Update: ╘══════╛ For all users of the non-git packages: ¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ Customize all CSS might [probably will] brake your current styling settings. (more information on this in the file updateyourconfig2021.org) New config style ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ █▀▄ █▀▄ █▀█ █ █ ▀█▀ █▀█ █▀▀ █▀▀ █ █ █▀█ █▀█ █▀▀ █▀▀ █▀▄ █▀▄ █▀█ █▀▄ █ █ █ █ █ █ █▀█ █▀█ █ █ █ █ █▀▀ ▀▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀▀▀ ▀▀▀ The configuration file is now in YAML format. It's also massively cleaned up thanks to the input of MyriaCore! The new configuration allows for: Extended Scriptability ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ Now any notification can be modified by an external script. This allows for all the logic you could possibly do on a notification. Define special styles for special notifications! Many more fixes ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ Additional Features from 2021 ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ New deadd.css configuration file Style all elements yourself Reload CSS styling on the fly Use CSS transitions when loading a new colortheme and smoothly change the mood As always, many thanks to our contributors: (¯`·.¸¸.·´ `·.¸¸.·´¯) ( \ / ) ( \ ) MyriaCore S-NA ahmubashshir mgil2 resolritter ( / ) ( ) ( woutervb avdv TaylanTatli rbowden91 kianmeng ) ( ) ( / ) opalmay balsoft trk9001 CobaltSpace lierdakil ( \ ) ( / \ ) (_.·´¯`·.¸ ¸.·´¯`·.¸_) Thank you very much! Finally, thank you to everyone who created issues, commented, and helped to further this project. ▝ ▝ ▖ ▐ ▖ ▐ ▌ Further news in releasenotes.org ▐ ▙▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▟
The notification center receives notifications via DBUS (like any notification daemon) and shows them in the upper right corner of the screen. The notification (if not specified in the notification otherwise) will also be shown in the notification center even after the notification disappeared by itself. The notifications can be clicked to make them disappear.
Notifications can be replaced by the use of the replaces-id
feature
of the notification specification.
The notification center can (optionally) show user-specified buttons in the bottom that can be in two states (highlighted/not highlighted) and that can run customizable shell commands.
Some applications, notification:
Link, Markup, Progressbar, and Action support:
To start it:
> deadd-notification-center
Toggle between hidden and shown state of the notification center:
kill -s USR1 $(pidof deadd-notification-center)
Set the state of a user defined button (in this example the first
button, which has id
0):
# turn highlighting on
notify-send.py a --hint boolean:deadd-notification-center:true \
int:id:0 boolean:state:true type:string:buttons
# turn highlighting off
notify-send.py a --hint boolean:deadd-notification-center:true \
int:id:0 boolean:state:false type:string:buttons
This snippet uses notify-send.py, an improved version of libnotify (notify-send).
Clear all notifications
# within the notification center
notify-send.py a --hint boolean:deadd-notification-center:true \
string:type:clearInCenter
# popups
notify-send.py a --hint boolean:deadd-notification-center:true \
string:type:clearPopups
Pause/Unpause popup notifications
# pause popup notifications
notify-send.py a --hint boolean:deadd-notification-center:true \
string:type:pausePopups
# unpause popup notifications
notify-send.py a --hint boolean:deadd-notification-center:true \
string:type:unpausePopups
Reload CSS Styling file
notify-send.py a --hint boolean:deadd-notification-center:true \
string:type:reloadStyle
Send notifications that only show up in the notification center but do not produce a popup:
notify-send.py "Does not pop up" -t 1
Action buttons with gtk icons
notify-send.py "And buttons" "Do you like buttons?" \
--hint boolean:action-icons:true \
--action yes:face-cool no:face-sick
Notification images by gtk icon
notify-send.py "Icons are" "COOL" \
--hint string:image-path:face-cool
Notification images by file
notify-send.py "Images are" "COOL" \
--hint string:image-path:file://path/to/image/from/root.png
Notification with progress bar
notify-send.py "This notification has a progressbar" "33%" \
--hint int:has-percentage:33)
#or
notify-send.py "This notification has a progressbar" "33%" \
--hint int:value:33)
Notification with slider
notify-send.py "This notification has a slider" "33%" \
--hint int:has-percentage:33
--action changeValue:abc)
This snippet can be used to produce a brightness-indicator. It requires the notify-send.py script.
#!/bin/bash
if [ "$1" == "inc" ]; then
xbacklight -inc 5
fi
if [ "$1" == "dec" ]; then
xbacklight -lower 5
fi
BRIGHTNESS=$(xbacklight -get)
NOTI_ID=$(notify-send.py "Bildschirmhelligkeit" "$BRIGHTNESS/100" \
--hint string:image-path:video-display boolean:transient:true \
int:has-percentage:$BRIGHTNESS \
--replaces-process "brightness-popup")
This snippet can be used to produce a volume-indicator. It requires the notify-send.py script.
#!/bin/bash
if [ "$1" == "inc" ]; then
amixer -q sset Master 5%+
fi
if [ "$1" == "dec" ]; then
amixer -q sset Master 5%-
fi
if [ "$1" == "mute" ]; then
amixer -q sset Master toggle
fi
AMIXER=$(amixer sget Master)
VOLUME=$(echo $AMIXER | grep 'Right:' | awk -F'[][]' '{ print $2 }' | tr -d "%")
MUTE=$(echo $AMIXER | grep -o '\[off\]' | tail -n 1)
if [ "$VOLUME" -le 20 ]; then
ICON=audio-volume-low
else if [ "$VOLUME" -le 60 ]; then
ICON=audio-volume-medium
else
ICON=audio-volume-high
fi
fi
if [ "$MUTE" == "[off]" ]; then
ICON=audio-volume-muted
fi
NOTI_ID=$(notify-send.py "Lautstärke" "$VOLUME/100" \
--hint string:image-path:$ICON boolean:transient:true \
int:has-percentage:$VOLUME \
--replaces-process "volume-popup")
Install from the AUR for Arch: deadd-notification-center.
OR
If you want to spare yourself the hassle of the build time there is a binary package available: deadd-notification-center-bin.
OR
If you don’t want to wait for me to publish the next stable release: Use the new AUR git-package.
deadd-notification-center-git.
OR
On Ubuntu, Debian, everything… Replace 1.7.2 with the current-most release from the release section.
Manually install the dependencies (exact names might differ in your distribution):
- gtk3
- gobject-introspection-runtime
tar -xvzf linux_notification_center-1.7.2.tar.gz
cd linux_notification_center-1.7.2
wget https://github.com/phuhl/linux_notification_center/releases/download/1.7.2/deadd-notification-center
mkdir -p .out
mv deadd-notification-center .out
sudo make install
OR
Dependencies:
- stack
- cairo
- pango
- gobject-introspection
- gtk3
make
sudo make install
NOTE: Some styling config has moved. More infos in this file: updateyourconfig2021.org
No configuration is necessary, the notification center comes with sensible defaults™.
All colors and sizes are customizable, as well as the default timeout
for notifications and the optional buttons in the notification
center. Below are possible configurable options shown. The
configuration file must be located at ~/.config/deadd/deadd.yml
(or,
if configured differently on your system:
${XDG_CONFIG_HOME}/deadd/deadd.yml
).
Additionally, a deadd.css
will be loaded from the same folder. It
contains the styling of the notification center. You can load changes
from the deadd.css
file by using the command described in the section
“Usage”.
### Margins for notification-center/notifications
margin-top: 0
margin-right: 0
### Margins for notification-center
margin-bottom: 0
### Width of the notification center/notifications in pixels.
width: 500
### Command to run at startup. This can be used to setup
### button states.
# startup-command: deadd-notification-center-startup
### Monitor on which the notification center/notifications will be
### printed. If "follow-mouse" is set true, this does nothing.
monitor: 0
### If true, the notification center/notifications will open on the
### screen, on which the mouse is. Overrides the "monitor" setting.
follow-mouse: false
notification-center:
### Margin at the top/right/bottom of the notification center in
### pixels. This can be used to avoid overlap between the notification
### center and bars such as polybar or i3blocks.
# margin-top: 0
# margin-right: 0
# margin-bottom: 0
### Width of the notification center in pixels.
# width: 500
### Monitor on which the notification center will be printed. If
### "follow-mouse" is set true, this does nothing.
# monitor: 0
### If true, the notification center will open on the screen, on which
### the mouse is. Overrides the "monitor" setting.
# follow-mouse: false
### Notification center closes when the mouse leaves it
hide-on-mouse-leave: true
### If newFirst is set to true, newest notifications appear on the top
### of the notification center. Else, notifications stack, from top to
### bottom.
new-first: true
### If true, the transient field in notifications will be ignored,
### thus the notification will be persisted in the notification
### center anyways
ignore-transient: false
### Custom buttons in notification center
buttons:
### Numbers of buttons that can be drawn on a row of the notification
### center.
# buttons-per-row: 5
### Height of buttons in the notification center (in pixels).
# buttons-height: 60
### Horizontal and vertical margin between each button in the
### notification center (in pixels).
# buttons-margin: 2
### Button actions and labels. For each button you must specify a
### label and a command.
actions:
# - label: VPN
# command: "sudo vpnToggle"
# - label: Bluetooth
# command: bluetoothToggle
# - label: Wifi
# command: wifiToggle
# - label: Screensaver
# command: screensaverToggle
# - label: Keyboard
# command: keyboardToggle
notification:
### If true, markup (<u>, <i>, <b>, <a>) will be displayed properly
use-markup: true
### If true, html entities (& for &, % for %, etc) will be
### parsed properly. This is useful for chromium-based apps, which
### tend to send these in notifications.
parse-html-entities: true
dbus:
### If noti-closed messages are enabled, the sending application
### will know that a notification was closed/timed out. This can
### be an issue for certain applications, that overwrite
### notifications on status updates (e.g. Spotify on each
### song). When one of these applications thinks, the notification
### has been closed/timed out, they will not overwrite existing
### notifications but send new ones. This can lead to redundant
### notifications in the notification center, as the close-message
### is send regardless of the notification being persisted.
send-noti-closed: false
app-icon:
### If set to true: If no icon is passed by the app_icon parameter
### and no application "desktop-entry"-hint is present, deadd will
### try to guess the icon from the application name (if present).
guess-icon-from-name: true
### The display size of the application icons in the notification
### pop-ups and in the notification center
icon-size: 20
image:
### The maximal display size of images that are part of
### notifications for notification pop-ups and in the notification
### center
size: 100
### The margin around the top, bottom, left, and right of
### notification images.
margin-top: 15
margin-bottom: 15
margin-left: 15
margin-right: 0
### Apply modifications to certain notifications:
### Each modification rule needs a "match" and either a "modify" or
### a "script" entry.
modifications:
### Match:
### Matches the notifications against these rules. If all of the
### values (of one modification rule) match, the "modify"/"script"
### part is applied.
# - match:
### Possible match criteria:
# title: "Notification title"
# body: "Notification body"
# time: "12:44"
# app-name: "App name"
# urgency: "low" # "low", "normal" or "critical"
# modify:
### Possible modifications
# title: "abc"
# body: "abc"
# app-name: "abc"
# app-icon: "file:///abc.png"
### The timeout has three special values:
### timeout: 0 -> don't time out at all
### timeout: -1 -> use default timeout
### timeout: 1 -> don't show as pop-up
### timeout: >1 -> milliseconds until timeout
# timeout: 1
# margin-right: 10
# margin-top: 10
# image: "file:///abc.png"
# image-size: 10
# transient: true
# send-noti-closed: false
### Remove action buttons from notifications
# remove-actions: true
### Set the action-icons hint to true, action labels will then
### be intergreted as GTK icon names
# action-icons: true
### List of actions, where the even elements (0, 2, ...) are the
### action name and the odd elements are the label
# actions:
# - previous
# - media-skip-backward
# - play
# - media-playback-start
# - next
# - media-skip-forward
### Action commands, where the keys (e.g. "play") is the action
### name and the value is a program call that should be executed
### on action. Prevents sending of the action to the application.
# action-commands:
# play: playerctl play-pause
# previous: playerctl previous
# next: playerctl next
### Add a class-name to the notification container, that can be
### used for specific styling of notifications using the
### deadd.css file
# class-name: "abc"
# - match:
# app-name: "Chromium"
### Instead of modifying a notification directly, a script can be
### run, which will receive the notification as JSON on STDIN. It
### is expected to return JSON/YAML configuration that defines the
### modifications that should be applied. Minimum complete return
### value must be '{"modify": {}, "match": {}}'. Always leave the "match"
### object empty (technical reasons, i.e. I am lazy).
# script: "linux-notification-center-parse-chromium"
- match:
app-name: "Spotify"
modify:
image-size: 80
timeout: 1
send-noti-closed: true
class-name: "Spotify"
action-icons: true
actions:
- previous
- media-skip-backward
- play
- media-playback-start
- next
- media-skip-forward
action-commands:
play: playerctl play-pause
previous: playerctl previous
next: playerctl next
# - match:
# title: Bildschirmhelligkeit
# modify:
# image-size: 60
popup:
### Default timeout used for notifications in milli-seconds. This can
### be overwritten with the "-t" option (or "--expire-time") of the
### notify-send command.
default-timeout: 10000
### Margin above/right/between notifications (in pixels). This can
### be used to avoid overlap between notifications and a bar such as
### polybar or i3blocks.
margin-top: 50
margin-right: 50
margin-between: 20
### Defines after how many lines of text the body will be truncated.
### Use 0 if you want to disable truncation.
max-lines-in-body: 3
### Determines whether the GTK widget that displays the notification body
### in the notification popup will be hidden when empty. This is especially
### useful for transient notifications that display a progress bar.
# hide-body-if-empty: false
### Monitor on which the notifications will be
### printed. If "follow-mouse" is set true, this does nothing.
# monitor: 0
### If true, the notifications will open on the
### screen, on which the mouse is. Overrides the "monitor" setting.
# follow-mouse: false
click-behavior:
### The mouse button for dismissing a popup. Must be either "mouse1",
### "mouse2", "mouse3", "mouse4", or "mouse5"
dismiss: mouse1
### The mouse button for opening a popup with the default action.
### Must be either "mouse1", "mouse2", "mouse3", "mouse4", or "mouse5"
default-action: mouse3
The default CSS style can be found in /etc/xdg/deadd/deadd.css
. It is
advised to copy this file to ${XDG_CONFIG_HOME}/deadd/deadd.css
(usually
.config/deadd/deadd.css
) if you want to make changes.
In the file you can change CSS styles (GTK3-flavor). Should the
installation not have created a dead.css
, you can use the content of
style.css as a foundation.
The following class-names for labels are defined:
- Notifications:
label.deadd-noti-center.notification.appname
- Appname
label.deadd-noti-center.notification.body
- Textbody
label.deadd-noti-center.notification.title
- Notification title
image.deadd-noti-center.notification.image
- Image of a notification
image.deadd-noti-center.notification.icon
- Appicon
button.deadd-noti-center.notification.actionbutton
- Action buttons
- Notifications in the notification center:
label.deadd-noti-center.in-center.appname
- Appname
label.deadd-noti-center.in-center.body
- Textbody
label.deadd-noti-center.in-center.title
- Notification title
label.deadd-noti-center.in-center.time
- Notification time
image.deadd-noti-center.in-center.image
- Image of a notification
image.deadd-noti-center.in-center.icon
- Appicon
button.deadd-noti-center.in-center.button-close
- Close button on notification
button.deadd-noti-center.in-center.actionbutton
- Action buttons
- Notification-center:
label.deadd-noti-center.noti-center.time
- The big time at the top
label.deadd-noti-center.noti-center.date
- The date text
label.deadd-noti-center.noti-center.delete-all
- “Delete all” Button
button.deadd-noti-center.noti-center.userbutton
- User buttons
Additionally, you can specify custom class-names in the
modifications-section of your deadd.yml
. These class names will be
defined on the notification container (all notification elements lie
within) of pop-ups and in-center.
Remove appname and icon from notifications
image.deadd-noti-center.notification.icon,
label.deadd-noti-center.notification.appname,
image.deadd-noti-center.in-center.icon,
label.deadd-noti-center.in-center.appname {
opacity: 0
}
Change font
.deadd-noti-center {
font-family: monospace;
}
Specify special background for one app
.notificationInCenter.Spotify {
background: linear-gradient(130deg, rgba(0, 0, 0, 0.1), rgba(0, 255, 0, 0.3));
border-radius: 5px;
}
This change requires a modification in your deadd.yml:
notification:
modifications:
- match:
app-name: "Spotify"
modify:
class-name: "Spotify"
You can modify notifications if they match certain criteria.
Matching:
The criteria you can specify are equality for the following parameters:
- title
- body
- app-name
- time
The matching parameters can be specified in the section
notification.modifications.match
of your deadd.yml
.
Modifying:
You can set the following parameters:
title
body
app-name
timeout
(specified in milliseconds)margin-right
(overridesdistanceRight
from the configuration)margin-top
(overridesdistanceTop
from the configuration)icon
(overrides the app-icon, value must be either empty, a path to an image or a gtk-icon-name)image
(overrides the image of the notification, value must be either empty, a path to an image or a gtk-icon-name)image-size
transient
(value has to betrue
orfalse
)send-noti-closed
(value has to betrue
orfalse
, if set to true it will prevent that a DBUSNotificationClosed
message will be send for this notification. Only applies if the configuration parameterconfigSendNotiClosedDbusMessage
is set totrue
)class-name
(adds a CSS-class name to the container of the notification for styling)remove-actions
(value can be anything, if used, no action buttons will be displayed on the notifications)action-icons
(true
orfalse
, if set totrue
the action label will be interpreted as an gtk-icon-name and an icon is displayed)actions
(array where every even element is the action name, every odd element is the action label. Actions are rendered as buttons in a notification. As the action most likely won’t be known by the notification sender, you probably want to use this with theaction-commands
modification)action-commands
(object where the keys are the action name and the value is a program call that should be executed when the action button has been clicked. Prevents sending of the action to the application.)
The modification parameters can be specified in the section
notification.modifications.modify
of your deadd.yml
.
Running Scripts:
Instead of modifying a notification directly, a script can be run,
which will receive the notification as JSON on STDIN. The script is
expected to return JSON/YAML configuration that defines the
modifications that should be applied. Minimum complete return value
must be {"modify": {}, "match": {}}
. Always leave the “match” object
empty (technical reasons, i.e. I am lazy).
Example script to turn a notification from WhatsApp in Chromium into something sensible:
Before:
After:
Configuration:
notification:
modifications:
- match:
app-name: "Chromium"
script: "linux-notification-center-parse-chromium"
Script executed on Chromium notifications:
#!/bin/bash
# Read notification from STDIN
noti=""
while read line
do
noti=${noti}${line}
done < "${1:-/dev/stdin}"
# Use jq to parse JSON and get the body field of the notification
body=$(echo $noti | jq '.body')
if [[ "$body" == "\"<a href=\\\"https://web.whatsapp.com/\\\">web.whatsapp.com</a>"* ]]; then
# It's Whatsapp web, lets modify the notification
isWhatsapp=1
body=$(echo $body | cut -c 64-)
img=$(echo $noti | jq '.image')
if [[ "$img" == "\"NamedIcon \\\""* ]]; then
filepath=$(echo $img | cut -c 14- | head -c -4)
cp $filepath /tmp/whatsappimg.png
fi
fi
if [[ "$isWhatsapp" == "1" ]]; then
# Returning the modifications to dnc as JSON
echo "{\"modify\": {\"app-icon\": \"whatsapp-desktop\", \"app-name\": \"WhatsApp\", \"image-size\": 50, \"image\": \"file:///tmp/whatsappimg.png\", \"remove-actions\": true, \"class-name\": \"WhatsApp\", \"body\":\"${body}}, \"match\": {}}"
else
echo '{"modify": {}, "match": {}}'
fi
First of all: Contribution is obviously 100% optional.
If you want to join the development chat, join our matrix channel: #deadd-notification-center:beeper.com or drop by on the discussion board: https://github.com/phuhl/linux_notification_center/discussions
If you do not want to contribute with your time, you can buy me a beer. Someone mentioned, they would be willing to donate, so here is my PayPal link: https://paypal.me/phuhl. Should you consider to donate, please be aware that this does not buy you the right to demand anything. This is a hobby and will be. But if you just want to give me some motivation by showing me that you appreciate my work, feel free to do so :)
Also take a look at my notify-send.py which imitates notify-send (libnotify) but also is able to replace notifications.