Merge tag 'v1.5.0'

Dunst v1.5.0
master
katherine 2 years ago
commit 2198c5f7fe
  1. 2
      .github/ISSUE_TEMPLATE.md
  2. 81
      .github/workflows/main.yml
  3. 22
      .gitignore
  4. 37
      .travis.yml
  5. 75
      .valgrind.suppressions
  6. 66
      CHANGELOG.md
  7. 2
      HACKING.md
  8. 135
      Makefile
  9. 8
      README.md
  10. 50
      RELEASE_NOTES
  11. 27
      config.h
  12. 34
      config.mk
  13. 200
      docs/dunst.pod
  14. 59
      docs/dunstctl.pod
  15. 4
      dunst.systemd.service.in
  16. 110
      dunstctl
  17. 40
      dunstify.c
  18. 85
      dunstrc
  19. 769
      src/dbus.c
  20. 5
      src/dbus.h
  21. 159
      src/draw.c
  22. 4
      src/draw.h
  23. 62
      src/dunst.c
  24. 32
      src/dunst.h
  25. 333
      src/icon.c
  26. 41
      src/icon.h
  27. 26
      src/log.c
  28. 134
      src/markup.c
  29. 38
      src/markup.h
  30. 379
      src/menu.c
  31. 13
      src/menu.h
  32. 309
      src/notification.c
  33. 101
      src/notification.h
  34. 272
      src/option_parser.c
  35. 32
      src/option_parser.h
  36. 280
      src/queues.c
  37. 54
      src/queues.h
  38. 75
      src/rules.c
  39. 12
      src/rules.h
  40. 352
      src/settings.c
  41. 35
      src/settings.h
  42. 124
      src/utils.c
  43. 121
      src/utils.h
  44. 195
      src/x11/screen.c
  45. 13
      src/x11/screen.h
  46. 366
      src/x11/x.c
  47. 10
      src/x11/x.h
  48. 14
      test/data/test-ini
  49. 873
      test/dbus.c
  50. 32
      test/dunst.c
  51. 618
      test/greatest.h
  52. 35
      test/helpers.c
  53. 9
      test/helpers.h
  54. 116
      test/icon.c
  55. 35
      test/log.c
  56. 17
      test/markup.c
  57. 74
      test/menu.c
  58. 21
      test/misc.c
  59. 233
      test/notification.c
  60. 126
      test/option_parser.c
  61. 801
      test/queues.c
  62. 57
      test/queues.h
  63. 27
      test/test-install.sh
  64. 36
      test/test.c
  65. 67
      test/utils.c

@ -7,7 +7,7 @@ These program calls might help:
While the notification gets sent:
`dbus-monitor path=/org/freedesktop/Notifications`
If dunst segfaults (please install the debug symbols or install dunst manually again):
If dunst segfaults (please install the debug symbols or install dunst manually again):
`gdb -ex run dunst -ex bt`
* ISSUE DESCRIPTION GOES BELOW THIS LINE * -->

@ -0,0 +1,81 @@
name: main
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
strategy:
matrix:
CC:
- clang
- gcc
distro:
- alpine
- archlinux
- debian-stretch
- fedora
- ubuntu-xenial
- ubuntu-bionic
env:
CC: ${{ matrix.CC }}
steps:
- uses: actions/checkout@v2
with:
# Clone the whole branch, we have to fetch tags later
fetch-depth: 0
# Fetch tags to determine proper version number inside git
- name: fetch tags
run: git fetch --tags
# We cannot pull tags with old distros, since there is no `.git`. See below.
if: "! (matrix.distro == 'ubuntu-bionic' || matrix.distro == 'ubuntu-xenial' || matrix.distro == 'debian-stretch')"
# The Github checkout Action doesn't support distros with git older than 2.18
# With git<2.18 it downloads the code via API and does not clone it via git :facepalm:
# To succeed the tests, we have to manually replace the VERSION macro
- name: fix version number for old distros
run: 'sed -i "s/1.4.1-non-git/1.4.1-ci-oldgit-$GITHUB_SHA/" Makefile'
if: " (matrix.distro == 'ubuntu-bionic' || matrix.distro == 'ubuntu-xenial' || matrix.distro == 'debian-stretch')"
- name: build
run: make -j all dunstify test/test
- name: test
run: make -j test
- name: installation
run: ./test/test-install.sh
- name: valgrind memleaks
run: |
make clean
make -j test-valgrind
- name: coverage
run: |
make clean
make -j test-coverage
- name: Generate coverage report
run: lcov -c -d . -o lcov.info
if: "matrix.CC == 'gcc'"
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: unittests
name: ${{ matrix.distro }}-${{ matrix.CC }}
fail_ci_if_error: true
if: "matrix.CC == 'gcc'"
runs-on: ubuntu-latest
container:
image: dunst/ci:${{ matrix.distro }}

22
.gitignore vendored

@ -1,10 +1,18 @@
dunst
*.o
*.d
*.gcda
*.gcno
*.gcov
/lcov.info
core
vgcore.*
dunst.1
org.knopwob.dunst.service
dunst.systemd.service
dunstify
test/test
docs/internal/html
/docs/*.1
/docs/internal/coverage
/docs/internal/html
/dunst
/dunstify
/dunst.systemd.service
/org.knopwob.dunst.service
/test/test

@ -1,37 +0,0 @@
addons:
apt:
packages:
- doxygen
- graphviz
- libdbus-1-dev
- libx11-dev
- libxrandr-dev
- libxinerama-dev
- libxss-dev
- libxdg-basedir-dev
- libglib2.0-dev
- libpango1.0-dev
- libcairo2-dev
- libnotify-dev
- libgtk-3-dev
- valgrind
dist: trusty
sudo: false
language: c
before_install:
- pip install --user cpp-coveralls
script:
- CFLAGS="-Werror" make all dunstify test-valgrind doc-doxygen
- make clean
- CFLAGS="-Werror -fprofile-arcs -ftest-coverage -O0" make test
matrix:
include:
- compiler: gcc
after_success:
- coveralls --exclude 'test'
- compiler: clang
after_success:
- coveralls --exclude 'test' --gcov llvm-cov --gcov-options gcov

@ -1,39 +1,72 @@
# Ignore musls' weird error
{
xdgBaseDir_leak
# see https://github.com/devnev/libxdg-basedir/pull/6
Memcheck:Leak
fun:malloc
...
fun:xdgInitHandle
...
fun:main
musl_alpine_libc
Memcheck:Free
fun:free
obj:/lib/ld-musl-x86_64.so.1
}
# librsvg leaks some memory, when an invalid svg file is read
# TODO: find the memory leak and fix it upstream
# rsvg_error_handle_close got fixed in
# - GNOME/librsvg@7bf1014
# (2018-11-12, first tags: v2.45.0, v2.44.9)
# but the release has to seep into the distros
{
invalid_svgs1
rsvg_error_handle_close
Memcheck:Leak
...
fun:gdk_pixbuf__svg_image_load_increment
...
match-leak-kinds: definite
fun:malloc
fun:g_malloc
fun:g_slice_alloc
fun:g_error_new_valist
fun:g_set_error
obj:*/librsvg-2.so*
fun:rsvg_handle_close
obj:*/loaders/libpixbufloader-svg.so
fun:gdk_pixbuf_loader_close
fun:gdk_pixbuf_get_file_info
fun:get_pixbuf_from_file
...
}
# same as above, but as occurs in CI environment
{
invalid_svgs2
rsvg_error_handle_close2
Memcheck:Leak
...
fun:gdk_pixbuf__svg_image_begin_load
...
match-leak-kinds: definite
fun:malloc
fun:g_malloc
fun:g_slice_alloc
fun:g_error_new_valist
fun:g_set_error
obj:*/librsvg-2.so*
obj:*/librsvg-2.so*
obj:*/loaders/libpixbufloader-svg.so
obj:*/libgdk_pixbuf-2.0.so*
fun:gdk_pixbuf_loader_close
fun:gdk_pixbuf_get_file_info
fun:get_pixbuf_from_file
...
}
# rsvg_error_writehandler got fixed in
# - GNOME/librsvg@7b4cc9b
# (2018-11-12, first tags: v2.45.0, v2.44.9)
# but the release has to seep into the distros
{
invalid_svgs3
rsvg_error_writehandler
Memcheck:Leak
...
match-leak-kinds: definite
fun:malloc
fun:g_malloc
fun:g_slice_alloc
fun:g_error_new_valist
fun:g_set_error
obj:*/librsvg-2.so*
fun:rsvg_handle_write
...
obj:*/loaders/libpixbufloader-svg.so
obj:*/libgdk_pixbuf-2.0.so*
fun:gdk_pixbuf_loader_close
fun:gdk_pixbuf_get_file_info
fun:get_pixbuf_from_file
...
}

@ -1,14 +1,76 @@
# Dunst changelog
## Unreleased
## 1.5.0 - 2020-07-23
### Added
- `min_icon_size` option to automatically scale up icons to a desired value (#674)
- `vertical_alignment` option to control the text/icon alignment within the notification (#684)
- Ability to configure multiple actions for each mouse event (#705)
- `dunstctl` command line control client (#651)
- RGBA support for all color strings (#717)
- Ability to run multiple scripts for each notification
- `ignore_dbusclose` setting (#732)
- `fullscreen` rule to hide notifications when a fullscreen window is active
### Changed
- `dunstify` notification client is now installed by default (#701)
- Keyboard follow mode falls back to the monitor with the mouse if no window has keyboard focus (#708)
### Fixed
- Overflow when setting a >=40 minute timeout (#646)
- Unset configuration options not falling back to default values (#649)
- Crash when `$HOME` environment variable is unset (#693)
- Lack of antialiasing with round corners enabled (#713)
## 1.4.1 - 2019-07-03
### Fixed
- `max_icon_size` not working with dynamic width (#614)
- Failure to parse color strings with trailing comments in the config (#626)
- Negative width in geometry being ignored (#628)
- Incorrect handling of the argument terminator `--` in dunstify
- Crash when changing DPI while no notifications are displayed (#630)
- Fullscreen status change not being detected in some cases (#613)
## 1.4.0 - 2019-03-30
### Added
- Add support to override `frame_color` via rules (#498)
- Support for round corners (#420)
- Ability to reference `$HOME` in icon paths with `~/` (#520)
- Support to customize the mouse bindings (#530)
- Command to toggle pause status (#535)
- Ability to automatically replace similar notifications (like volume changes)
via `stack_tag` (#552)
- Comparison of raw icons for duplicate notifications (#571)
- Introduce new desktop-entry filter (#470)
- `fullscreen` rule to hide notifications when a fullscreen window is active (#472)
- Added `skip_display` rule option to skip initial notification display, and
include the notification in the history. (#590)
### Fixed
- Notification age not counting the time while the computer was suspended (#492)
- Dunst losing always-on-top status on a window manager restart (#160)
- Xpm icons not being recognized
- When new notifications arrive, but display is full, important notifications don't
have to wait for a timeout in a displayed notification (#541)
- Dunst hanging while the context menu is open (#456)
- Having & inside a notification breaking markup (#546)
- `<I> more` notifications don't occupy space anymore, if there is only a single
notification waiting to get displayed. The notification gets displayed directly (#467)
- Segfault when comparing icon name with a notification with a raw icon (#536)
- Icon size can no longer be larger than the notification when a fixed width is specified (#540)
### Changed
- Transient notifications no longer skip history by default (#508)
- The notification summary no longer accepts markup (#497)
### Removed
- Dependency on libxdg-basedir (#550)
## 1.3.2 - 2018-05-06

@ -6,6 +6,8 @@
- Comment system is held similar to JavaDoc
- Use `@param` to describe all input parameters
- Use `@return` to describe the output value
- Use `@retval` to describe special return values (like `NULL`)
- Documentation comments should start with a double star (`/**`)
- Append `()` to function names and prepend variables with `#` to properly reference them in the docs
- Add comments to all functions and methods

@ -3,15 +3,15 @@
include config.mk
VERSION := "1.3.2-non-git"
VERSION := "1.5.0 (2020-07-23)"
ifneq ($(wildcard ./.git/),)
VERSION := $(shell git describe --tags)
VERSION := $(shell ${GIT} describe --tags)
endif
ifeq (,${SYSTEMD})
# Check for systemctl to avoid discrepancies on systems, where
# systemd is installed, but systemd.pc is in another package
systemctl := $(shell command -v systemctl >/dev/null && echo systemctl)
# systemd is installed, but systemd.pc is in another package
systemctl := $(shell command -v ${SYSTEMCTL} >/dev/null && echo systemctl)
ifeq (systemctl,${systemctl})
SYSTEMD := 1
else
@ -42,99 +42,138 @@ $(error "$(PKG_CONFIG) failed!")
endif
endif
CFLAGS := ${DEFAULT_CPPFLAGS} ${CPPFLAGS} ${DEFAULT_CFLAGS} ${CFLAGS} -I. ${INCS}
LDFLAGS := ${DEFAULT_LDFLAGS} ${LDFLAGS} -L. ${LIBS}
CFLAGS := ${DEFAULT_CPPFLAGS} ${CPPFLAGS} ${DEFAULT_CFLAGS} ${CFLAGS} ${INCS} -MMD -MP
LDFLAGS := ${DEFAULT_LDFLAGS} ${LDFLAGS} ${LIBS}
SRC := $(sort $(shell find src/ -name '*.c'))
SRC := $(sort $(shell ${FIND} src/ -name '*.c'))
OBJ := ${SRC:.c=.o}
TEST_SRC := $(sort $(shell find test/ -name '*.c'))
TEST_SRC := $(sort $(shell ${FIND} test/ -name '*.c'))
TEST_OBJ := $(TEST_SRC:.c=.o)
DEPS := ${SRC:.c=.d} ${TEST_SRC:.c=.d}
.PHONY: all debug
all: doc dunst service
all: doc dunst dunstify service
debug: CFLAGS += ${CPPFLAGS_DEBUG} ${CFLAGS_DEBUG}
debug: LDFLAGS += ${LDFLAGS_DEBUG}
debug: CPPFLAGS += ${CPPFLAGS_DEBUG}
debug: all
.c.o:
${CC} -o $@ -c $< ${CFLAGS}
-include $(DEPS)
${OBJ} ${TEST_OBJ}: Makefile config.mk
${OBJ}: config.mk
%.o: %.c
${CC} -o $@ -c $< ${CFLAGS}
dunst: ${OBJ} main.o
${CC} ${CFLAGS} -o $@ ${OBJ} main.o ${LDFLAGS}
${CC} -o ${@} ${OBJ} main.o ${CFLAGS} ${LDFLAGS}
dunstify: dunstify.o
${CC} ${CFLAGS} -o $@ dunstify.o ${LDFLAGS}
${CC} -o ${@} dunstify.o ${CFLAGS} ${LDFLAGS}
.PHONY: test test-valgrind
test: test/test
cd test && ./test
.PHONY: test test-valgrind test-coverage
test: test/test clean-coverage-run
./test/test -v
test-valgrind: test/test
cd ./test \
&& valgrind \
--suppressions=../.valgrind.suppressions \
--leak-check=full \
--show-leak-kinds=definite \
--errors-for-leak-kinds=definite \
--num-callers=40 \
--error-exitcode=123 \
./test
${VALGRIND} \
--suppressions=.valgrind.suppressions \
--leak-check=full \
--show-leak-kinds=definite \
--errors-for-leak-kinds=definite \
--num-callers=40 \
--error-exitcode=123 \
./test/test -v
test-coverage: CFLAGS += -fprofile-arcs -ftest-coverage -O0
test-coverage: test
test-coverage-report: test-coverage
mkdir -p docs/internal/coverage
${GCOVR} \
-r . \
--exclude=test \
--html \
--html-details \
-o docs/internal/coverage/index.html
test/%.o: test/%.c src/%.c
${CC} -o $@ -c $< ${CFLAGS}
test/test: ${OBJ} ${TEST_OBJ}
${CC} ${CFLAGS} -o $@ ${TEST_OBJ} ${OBJ} ${LDFLAGS}
${CC} -o ${@} ${TEST_OBJ} $(filter-out ${TEST_OBJ:test/%=src/%},${OBJ}) ${CFLAGS} ${LDFLAGS}
.PHONY: doc doc-doxygen
doc: docs/dunst.1
doc: docs/dunst.1 docs/dunstctl.1
# Can't dedup this as we need to explicitly provide the name and title text to
# pod2man :(
docs/dunst.1: docs/dunst.pod
pod2man --name=dunst -c "Dunst Reference" --section=1 --release=${VERSION} $< > $@
${POD2MAN} --name=dunst -c "Dunst Reference" --section=1 --release=${VERSION} $< > $@
docs/dunstctl.1: docs/dunstctl.pod
${POD2MAN} --name=dunstctl -c "dunstctl reference" --section=1 --release=${VERSION} $< > $@
doc-doxygen:
doxygen docs/internal/Doxyfile
${DOXYGEN} docs/internal/Doxyfile
.PHONY: service service-dbus service-systemd
service: service-dbus
service-dbus:
@sed "s|##PREFIX##|$(PREFIX)|" org.knopwob.dunst.service.in > org.knopwob.dunst.service
@${SED} "s|##PREFIX##|$(PREFIX)|" org.knopwob.dunst.service.in > org.knopwob.dunst.service
ifneq (0,${SYSTEMD})
service: service-systemd
service-systemd:
@sed "s|##PREFIX##|$(PREFIX)|" dunst.systemd.service.in > dunst.systemd.service
@${SED} "s|##PREFIX##|$(PREFIX)|" dunst.systemd.service.in > dunst.systemd.service
endif
.PHONY: clean clean-dunst clean-dunstify clean-doc clean-tests
clean: clean-dunst clean-dunstify clean-doc clean-tests
.PHONY: clean clean-dunst clean-dunstify clean-doc clean-tests clean-coverage clean-coverage-run
clean: clean-dunst clean-dunstify clean-doc clean-tests clean-coverage clean-coverage-run
clean-dunst:
rm -f dunst ${OBJ} main.o
rm -f dunst ${OBJ} main.o main.d ${DEPS}
rm -f org.knopwob.dunst.service
rm -f dunst.systemd.service
clean-dunstify:
rm -f dunstify.o
rm -f dunstify.d
rm -f dunstify
clean-doc:
rm -f docs/dunst.1
rm -f docs/dunstctl.1
rm -fr docs/internal/html
rm -fr docs/internal/coverage
clean-tests:
rm -f test/test test/*.o
rm -f test/test test/*.o test/*.d
clean-coverage: clean-coverage-run
${FIND} . -type f -name '*.gcno' -delete
${FIND} . -type f -name '*.gcna' -delete
# Cleans the coverage data before every run to not double count any lines
clean-coverage-run:
${FIND} . -type f -name '*.gcov' -delete
${FIND} . -type f -name '*.gcda' -delete
.PHONY: install install-dunst install-doc \
.PHONY: install install-dunst install-dunstctl install-doc \
install-service install-service-dbus install-service-systemd \
uninstall \
uninstall uninstall-dunstctl \
uninstall-service uninstall-service-dbus uninstall-service-systemd
install: install-dunst install-doc install-service
install: install-dunst install-dunstctl install-doc install-service install-dunstify
install-dunst: dunst doc
install -Dm755 dunst ${DESTDIR}${PREFIX}/bin/dunst
install -Dm755 dunst ${DESTDIR}${BINDIR}/dunst
install -Dm644 docs/dunst.1 ${DESTDIR}${MANPREFIX}/man1/dunst.1
install -Dm644 docs/dunstctl.1 ${DESTDIR}${MANPREFIX}/man1/dunstctl.1
install-dunstctl: dunstctl
install -Dm755 dunstctl ${DESTDIR}${BINDIR}/dunstctl
install-doc:
install -Dm644 dunstrc ${DESTDIR}${PREFIX}/share/dunst/dunstrc
install -Dm644 dunstrc ${DESTDIR}${DATADIR}/dunst/dunstrc
install-service: install-service-dbus
install-service-dbus: service-dbus
@ -145,10 +184,18 @@ install-service-systemd: service-systemd
install -Dm644 dunst.systemd.service ${DESTDIR}${SERVICEDIR_SYSTEMD}/dunst.service
endif
uninstall: uninstall-service
rm -f ${DESTDIR}${PREFIX}/bin/dunst
install-dunstify: dunstify
install -Dm755 dunstify ${DESTDIR}${BINDIR}/dunstify
uninstall: uninstall-service uninstall-dunstctl
rm -f ${DESTDIR}${BINDIR}/dunst
rm -f ${DESTDIR}${BINDIR}/dunstify
rm -f ${DESTDIR}${MANPREFIX}/man1/dunst.1
rm -rf ${DESTDIR}${PREFIX}/share/dunst
rm -f ${DESTDIR}${MANPREFIX}/man1/dunstctl.1
rm -rf ${DESTDIR}${DATADIR}/dunst
uninstall-dunstctl:
rm -f ${DESTDIR}${BINDIR}/dunstctl
uninstall-service: uninstall-service-dbus
uninstall-service-dbus:

@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/dunst-project/dunst.svg?branch=master)](https://travis-ci.org/dunst-project/dunst) [![Coverage Status](https://coveralls.io/repos/github/dunst-project/dunst/badge.svg?branch=coveralls)](https://coveralls.io/github/dunst-project/dunst?branch=master)
[![main](https://github.com/dunst-project/dunst/workflows/main/badge.svg)](https://github.com/dunst-project/dunst/actions?query=workflow%3Amain) [![codecov](https://codecov.io/gh/dunst-project/dunst/branch/master/graph/badge.svg)](https://codecov.io/gh/dunst-project/dunst)
## Dunst
@ -22,10 +22,10 @@ Dunst has a number of build dependencies that must be present before attempting
- libxinerama
- libxrandr
- libxss
- libxdg-basedir
- glib
- pango/cairo
- libgtk-3-dev
- libnotify (for dunstify only)
### Building
@ -39,7 +39,9 @@ sudo make install
### Make parameters
- `PREFIX=<PATH>`: Set the prefix of the installation. (Default: `/usr/local`)
- `MANPREFIX=<PATH>`: Set the prefix of the manpage. (Default: `${PREFIX}/share/man`)
- `BINDIR=<PATH>`: Set the `dunst` executable's path (Default: `${PREFIX}/bin`)
- `DATADIR=<PATH>`: Set the path for shared files. (Default: `${PREFIX}/share`)
- `MANDIR=<PATH>`: Set the prefix of the manpage. (Default: `${DATADIR}/man`)
- `SYSTEMD=(0|1)`: Enable/Disable the systemd unit. (Default: detected via `pkg-config`)
- `SERVICEDIR_SYSTEMD=<PATH>`: The path to put the systemd user service file. Unused, if `SYSTEMD=0`. (Default: detected via `pkg-config`)
- `SERVICEDIR_DBUS=<PATH>`: The path to put the dbus service file. (Default: detected via `pkg-config`)

@ -1,3 +1,53 @@
===================================================================================
Release Notes For v1.5.0
===================================================================================
For users:
The most important update from the previous version is the addition of the
dunstctl command and dunstify utility, a drop-in notify-send replacement (which
existed for a while, but wasn't installed by default).
The internal keyboard shortcut support in dunst is now considered deprecated
and should be replaced by dunstctl calls. You can use the configuration of your
WM or DE to bind these to shortcuts of your choice.
Additionally, another long requested feature implemented is RGBA/transparency
support. Given an active compositor you can now add an optional transparency
component to all colors in #RRGGBBAA format.
For maintainers:
As mentioned above, two new binaries are now installed by default, dunstctl and dunstify.
libnotify has been added as a dependency as it's used internally by dunstify.
===================================================================================
Release Notes For v1.4.0
===================================================================================
There has been significant internal refactoring since the last release which
might have introduced some new bugs. Be sure to report anything you find.
However, as usual, there has been a lot of bug-fixing and a lot of new features
have been added as well. Look at the full changelog for a breakdown.
Some important points to note:
For users:
* Behavioural changes
In the previous release we introduced support for clients to mark
notifications as 'transient'. Transient notifications used to 1) bypass
idle_threshold and 2) not be saved in history.
The latter behaviour has been disabled by default and can be re-created using
rules if necessary. Transient notifications will now only bypass
idle_threshold.
Additionally, to be compliant with the notification spec, the notification
summary no longer accepts markup.
For maintainers:
* Dependency on libxdg-basedir has been removed
===================================================================================
Release Notes For v1.3.0
===================================================================================

@ -4,15 +4,15 @@ struct settings defaults = {
.font = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*",
.markup = MARKUP_NO,
.normbgcolor = "#1793D1",
.normfgcolor = "#DDDDDD",
.critbgcolor = "#ffaaaa",
.critfgcolor = "#000000",
.lowbgcolor = "#aaaaff",
.lowfgcolor = "#000000",
.colors_norm.bg = "#1793D1",
.colors_norm.fg = "#DDDDDD",
.colors_crit.bg = "#ffaaaa",
.colors_crit.fg = "#000000",
.colors_low.bg = "#aaaaff",
.colors_low.fg = "#000000",
.format = "%s %b", /* default format */
.timeouts = { 10*G_USEC_PER_SEC, 10*G_USEC_PER_SEC, 0 }, /* low, normal, critical */
.timeouts = { S2US(10), S2US(10), S2US(0) }, /* low, normal, critical */
.icons = { "dialog-information", "dialog-information", "dialog-warning" }, /* low, normal, critical */
.transparency = 0, /* transparency */
@ -33,10 +33,12 @@ struct settings defaults = {
.idle_threshold = 0, /* don't timeout notifications when idle for x seconds */
.show_age_threshold = -1, /* show age of notification, when notification is older than x seconds */
.align = ALIGN_LEFT, /* text alignment ALIGN_[LEFT|CENTER|RIGHT] */
.vertical_alignment = VERTICAL_CENTER, /* vertical content alignment VERTICAL_[TOP|CENTER|BOTTOM] */
.sticky_history = true,
.history_length = 20, /* max amount of notifications kept in history */
.show_indicators = true,
.word_wrap = false,
.ignore_dbusclose = false,
.ellipsize = ELLIPSE_MIDDLE,
.ignore_newline = false,
.line_height = 0, /* if line height < font height, it will be raised to font height */
@ -46,8 +48,7 @@ struct settings defaults = {
.separator_height = 2, /* height of the separator line between two notifications */
.padding = 0,
.h_padding = 0, /* horizontal padding */
.sep_color = SEP_AUTO, /* SEP_AUTO, SEP_FOREGROUND, SEP_FRAME, SEP_CUSTOM */
.sep_custom_color_str = NULL,/* custom color if sep_color is set to CUSTOM */
.sep_color = {SEP_AUTO}, /* SEP_AUTO, SEP_FOREGROUND, SEP_FRAME, SEP_CUSTOM */
.frame_width = 0,
.frame_color = "#888888",
@ -66,6 +67,7 @@ struct settings defaults = {
.browser = "/usr/bin/firefox",
.min_icon_size = 0,
.max_icon_size = 0,
/* paths to default icons */
@ -102,11 +104,11 @@ struct settings defaults = {
.code = 0,.sym = NoSymbol,.is_valid = false
}, /* ignore this */
.mouse_left_click = MOUSE_CLOSE_CURRENT,
.mouse_left_click = (enum mouse_action []){MOUSE_CLOSE_CURRENT, -1},
.mouse_middle_click = MOUSE_DO_ACTION,
.mouse_middle_click = (enum mouse_action []){MOUSE_DO_ACTION, -1},
.mouse_right_click = MOUSE_CLOSE_ALL,
.mouse_right_click = (enum mouse_action []){MOUSE_CLOSE_ALL, -1},
};
@ -130,6 +132,7 @@ struct rule default_rules[] = {
.history_ignore = -1,
.match_transient = -1,
.set_transient = -1,
.skip_display = -1,
.new_icon = NULL,
.fg = NULL,
.bg = NULL,

@ -1,8 +1,20 @@
# paths
PREFIX ?= /usr/local
MANPREFIX = ${PREFIX}/share/man
BINDIR ?= ${PREFIX}/bin
DATADIR ?= ${PREFIX}/share
# around for backwards compatibility
MANPREFIX ?= ${DATADIR}/man
MANDIR ?= ${MANPREFIX}
DOXYGEN ?= doxygen
FIND ?= find
GCOVR ?= gcovr
GIT ?= git
PKG_CONFIG ?= pkg-config
POD2MAN ?= pod2man
SED ?= sed
SYSTEMCTL ?= systemctl
VALGRIND ?= valgrind
# Disable systemd service file installation,
# if you don't want to use systemd albeit installed
@ -21,10 +33,9 @@ CPPFLAGS_DEBUG := -DDEBUG_BUILD
CFLAGS_DEBUG := -O0
LDFLAGS_DEBUG :=
pkg_config_packs := dbus-1 \
gio-2.0 \
pkg_config_packs := gio-2.0 \
gdk-pixbuf-2.0 \
"glib-2.0 >= 2.36" \
"glib-2.0 >= 2.44" \
pangocairo \
x11 \
xinerama \
@ -32,14 +43,9 @@ pkg_config_packs := dbus-1 \
"xrandr >= 1.5" \
xscrnsaver
# check if we need libxdg-basedir
ifeq (,$(findstring STATIC_CONFIG,$(CFLAGS)))
pkg_config_packs += libxdg-basedir
else
$(warning STATIC_CONFIG is deprecated behavior. It will get removed in future releases)
endif
# dunstify also needs libnotify
ifneq (,$(findstring dunstify,${MAKECMDGOALS}))
pkg_config_packs += libnotify
pkg_config_packs += libnotify
ifneq (,$(findstring STATIC_CONFIG,$(CFLAGS)))
$(warning STATIC_CONFIG is deprecated behavior. It will get removed in future releases)
endif

@ -235,8 +235,8 @@ See TIME FORMAT for valid times.
Set to 0 to disable.
Transient notifications will ignore this setting and timeout anyway.
Use a rule overwriting with 'set_transient = no' to disable this behavior.
A client can mark a notification as transient to bypass this setting and timeout
anyway. Use a rule with 'set_transient = no' to disable this behavior.
=item B<font> (default: "Monospace 8")
@ -272,7 +272,7 @@ Allow a small subset of html markup in notifications
<u>underline</u>
For a complete reference see
<http://developer.gnome.org/pango/stable/PangoMarkupFormat.html>
<https://developer.gnome.org/pango/stable/pango-Markup.html>
=item B<strip>
@ -337,6 +337,11 @@ removed from the format.
Defines how the text should be aligned within the notification.
=item B<vertical_alignment> (values: [top/center/bottom], default: center)
Defines how the text and icon should be aligned vertically within the
notification. If icons are disabled, this option has no effect.
=item B<show_age_threshold> (default: -1)
Show age of message if message is older than this time.
@ -384,14 +389,28 @@ ACTIONS below for further details.
Defines the position of the icon in the notification window. Setting it to off
disables icons.
=item B<min_icon_size> (default: 0)
Defines the minimum size in pixels for the icons.
If the icon is larger than or equal to the specified value it won't be affected.
If it's smaller then it will be scaled up so that the smaller axis is equivalent
to the specified size.
Set to 0 to disable icon upscaling. (default)
If B<icon_position> is set to off, this setting is ignored.
=item B<max_icon_size> (default: 0)
Defines the maximum size in pixels for the icons.
If the icon is smaller than the specified value it won't be affected.
If the icon is smaller than or equal to the specified value it won't be affected.
If it's larger then it will be scaled down so that the larger axis is equivalent
to the specified size.
Set to 0 to disable icon scaling. (default)
Set to 0 to disable icon downscaling. (default)
If both B<min_icon_size> and B<max_icon_size> are enabled, the latter
gets the last say.
If B<icon_position> is set to off, this setting is ignored.
@ -496,9 +515,16 @@ Close all notifications.
=back
=item B<ignore_dbusclose> (default: false)
Ignore the dbus closeNotification message. This is useful to enforce the timeout
set by dunst configuration. Without this parameter, an application may close
the notification sent before the user defined timeout.
=back
=head2 Shortcut section
=head2 Shortcut section B<DEPRECATED SEE DUNSTCTL>
Keyboard shortcuts are defined in the following format: "Modifier+key" where the
modifier is one of ctrl,mod1,mod2,mod3,mod4 and key is any keyboard key.
@ -583,6 +609,13 @@ See TIME FORMAT for valid times.
=back
=head1 DUNSTCTL
Dunst now contains a command line control command that can be used to interact
with it. It supports all functions previously done only via keyboard shortcuts
but also has a lot of extra functionality. So see more see the dunstctl man
page.
=head1 HISTORY
Dunst saves a number of notifications (specified by B<history_length>) in memory.
@ -610,11 +643,64 @@ matched.
=item B<filtering>
Notifications can be matched for any of the following attributes: appname,
summary, body, icon, category, match_transient and msg_urgency where each is
the respective notification attribute to be matched and 'msg_urgency' is the
urgency of the notification, it is named so to not conflict with trying to
modify the urgency.
Notifications can be matched for any of the following attributes:
=over 4
=item C<appname> (discouraged, see desktop_entry)
The name of the application as reported by the client. Be aware that the name
can often differ depending on the locale used.
=item C<body>
The body of the notification
=item C<category>
The category of the notification as defined by the notification spec. See
https://developer.gnome.org/notification-spec/#categories
=item C<desktop_entry>
GLib based applications export their desktop-entry name. In comparison to the appname,
the desktop-entry won't get localized.
=item C<icon>
The icon of the notification in the form of a file path. Can be empty if no icon
is available or a raw icon is used instead.
=item C<match_transient>
Match if the notification has been declared as transient by the client or by
some other rule.
See C<set_transient> for more details about this attribute.
=item C<msg_urgency>
Matches the urgency of the notification as set by the client or by some other
rule.
=item C<stack_tag>
Matches the stack tag of the notification as set by the client or by some other
rule.
See set_stack_tag for more information about stack tags.
=item C<summary>
Matches the summary, 'title', of the notification.
=back
C<msg_urgency> is the urgency of the notification, it is named so to not conflict
with trying to modify the urgency.
Instead of the appname filter, it's recommended to use the desktop_entry filter.
To define a matching rule simply assign the specified value to the value that
should be matched, for example:
@ -629,10 +715,85 @@ Shell-like globing is supported.
=item B<modifying>
The following attributes can be overridden: timeout, urgency, foreground,
background, frame_color, new_icon, set_transient, format, fullscreen where,
as with the filtering attributes, each one corresponds to the respective
notification attribute to be modified.
The following attributes can be overridden:
=over 4
=item C<background>
The background color of the notification. See COLORS for possible values.
=item C<foreground>
The background color of the notification. See COLORS for possible values.
=item C<format>
Equivalent to the C<format> setting.
=item C<frame_color>
The frame color color of the notification. See COLORS for possible values.
=item C<fullscreen>
One of show, delay, or pushback.
This attribute specifies how notifications are handled if a fullscreen window
is focused. By default it's set to show so notifications are being shown.
Other possible values are delay: Already shown notifications are continued to be
displayed until they are dismissed or time out but new notifications will be
held back and displayed when the focus to the fullscreen window is lost.
Or pushback which is equivalent to delay with the difference that already
existing notifications are paused and hidden until the focus to the fullscreen
window is lost.
=item C<new_icon>
Updates the icon of the notification, it should be a path to a valid image.
=item C<set_stack_tag>
Sets the stack tag for the notification, notifications with the same (non-empty)
stack tag will replace each-other so only the newest one is visible. This can be
useful for example in volume or brightness notifications where only want one of
the same type visible.
The stack tag can be set by the client with the 'synchronous',
'private-synchronous' 'x-canonical-private-synchronous' or the
'x-dunst-stack-tag' hints.
=item C<set_transient>
Sets whether the notification is considered transient.
Transient notifications will bypass the idle_threshold setting.
By default notifications are _not_ considered transient but clients can set the
value of this by specifying the 'transient' hint when sending notifications.
=item C<timeout>
Equivalent to the C<timeout> setting in the urgency sections.
=item C<urgency>
This sets the notification urgency.
B<IMPORTANT NOTE>: This currently DOES NOT re-apply the attributes from the
urgency_* sections. The changed urgency will only be visible in rules defined
later. Use C<msg_urgency> to match it.
=item C<skip_display>
Setting this to true will prevent the notification from being displayed
initially but will be saved in history for later viewing.
=back
As with the filtering attributes, each one corresponds to
the respective notification attribute to be modified.
As with filtering, to make a rule modify an attribute simply assign it in the
rule definition.
@ -667,6 +828,8 @@ Colors are interpreted as X11 color values. This includes both verbatim
color names such as "Yellow", "Blue", "White", etc as well as #RGB and #RRGGBB
values.
You may also specify a transparency component in #RGBA or #RRGGBBAA format.
B<NOTE>: '#' is interpreted as a comment, to use it the entire value needs to
be in quotes like so: separator_color="#123456"
@ -718,9 +881,8 @@ Example time: "1000ms" "10m"
=head1 MISCELLANEOUS
Dunst can be paused by sending a notification with a summary of
"DUNST_COMMAND_PAUSE", resumed with a summary of "DUNST_COMMAND_RESUME" and
toggled with a summary of "DUNST_COMMAND_TOGGLE".
Dunst can be paused via the `dunstctl set-paused true` command. To unpause dunst use
`dunstctl set-paused false`.
Alternatively you can send SIGUSR1 and SIGUSR2 to pause and unpause
respectively. For Example:
@ -761,4 +923,4 @@ If you feel that copyrights are violated, please send me an email.
=head1 SEE ALSO
dwm(1), dmenu(1), twmn(1), notify-send(1)
dunstctl(1), dwm(1), dmenu(1), twmn(1), notify-send(1)

@ -0,0 +1,59 @@
=head1 NAME
dunstctl - Command line control utility for dunst, a customizable and lightweight notification-daemon
=head1 SYNOPSIS
dunstctl COMMAND [PARAMETER]
=head1 COMMANDS
=over 4
=item B<action> notification_position
Performs the default action or, if not available, opens the context menu of the
notification at the given position (starting count at the top, first
notification being 0).
=item B<close>
Close the topmost notification currently being displayed.
=item B<close-all>
Close all notifications currently being displayed
=item B<context>
Open the context menu, presenting all available actions and urls for the
currently open notifications.
=item B<history-pop>
Redisplay the notification that was most recently closed. This can be called
multiple times to show older notifications, up to the history limit configured
in dunst.
=item B<is-paused>
Check if dunst is currently running or paused. If dunst is paused notifications
will be kept but not shown until it is unpaused.
=item B<set-paused> true/false/toggle
Set the paused status of dunst. If false, dunst is running normally, if true,
dunst is paused. See the is-paused command and the dunst man page for more
information.
=item B<debug>
Tries to contact dunst and checks for common faults between dunstctl and dunst.
Useful if something isn't working
=item B<help>
Show all available commands with a brief description
=back

@ -7,7 +7,3 @@ PartOf=graphical-session.target
Type=dbus
BusName=org.freedesktop.Notifications
ExecStart=##PREFIX##/bin/dunst
[Install]
WantedBy=default.target

@ -0,0 +1,110 @@
#!/bin/sh
set -eu
DBUS_NAME="org.freedesktop.Notifications"
DBUS_PATH="/org/freedesktop/Notifications"
DBUS_IFAC_DUNST="org.dunstproject.cmd0"
DBUS_IFAC_PROP="org.freedesktop.DBus.Properties"
DBUS_IFAC_FDN="org.freedesktop.Notifications"
die(){ printf "%s\n" "${1}" >&2; exit 1; }
show_help() {
cat <<-EOH
Usage: dunstctl <command> [parameters]"
Commands:
action Perform the default action, or open the
context menu of the notification at the
given position
close Close the last notification
close-all Close the all notifications
context Open context menu
history-pop Pop one notification from history
is-paused Check if dunst is running or paused
set-paused [true|false|toggle] Set the pause status
debug Print debugging information
help Show this help
EOH
}
dbus_send_checked() {
dbus-send "$@" \
|| die "Failed to communicate with dunst, is it running? Or maybe the version is outdated. You can try 'dunstctl debug' as a next debugging step."
}
method_call() {
dbus_send_checked --print-reply=literal --dest="${DBUS_NAME}" "${DBUS_PATH}" "$@"
}
property_get() {
dbus_send_checked --print-reply=literal --dest="${DBUS_NAME}" "${DBUS_PATH}" "${DBUS_IFAC_PROP}.Get" "string:${DBUS_IFAC_DUNST}" "string:${1}"
}
property_set() {
dbus_send_checked --print-reply=literal --dest="${DBUS_NAME}" "${DBUS_PATH}" "${DBUS_IFAC_PROP}.Set" "string:${DBUS_IFAC_DUNST}" "string:${1}" "${2}"
}
command -v dbus-send >/dev/null 2>/dev/null || \
die "Command dbus-send not found"
case "${1:-}" in
"action")
method_call "${DBUS_IFAC_DUNST}.NotificationAction" "int32:${2:-0}" >/dev/null
;;
"close")
method_call "${DBUS_IFAC_DUNST}.NotificationCloseLast" >/dev/null
;;
"close-all")
method_call "${DBUS_IFAC_DUNST}.NotificationCloseAll" >/dev/null
;;
"context")
method_call "${DBUS_IFAC_DUNST}.ContextMenuCall" >/dev/null
;;
"history-pop")
method_call "${DBUS_IFAC_DUNST}.NotificationShow" >/dev/null
;;
"is-paused")
property_get paused | ( read -r _ _ paused; printf "%s\n" "${paused}"; )
;;
"set-paused")
[ "${2:-}" ] \
|| die "No status parameter specified. Please give either 'true', 'false' or 'toggle' as paused parameter."
[ "${2}" = "true" ] || [ "${2}" = "false" ] || [ "${2}" = "toggle" ] \
|| die "Please give either 'true', 'false' or 'toggle' as paused parameter."
if [ "${2}" = "toggle" ]; then
paused=$(property_get paused | ( read -r _ _ paused; printf "%s\n" "${paused}"; ))
if [ "${paused}" = "true" ]; then
property_set paused variant:boolean:false
else
property_set paused variant:boolean:true
fi
else
property_set paused variant:boolean:"$2"
fi
;;
"help"|"--help"|"-h")
show_help
;;
"debug")
dbus-send --print-reply=literal --dest="${DBUS_NAME}" "${DBUS_PATH}" "${DBUS_IFAC_FDN}.GetServerInformation" >/dev/null 2>/dev/null \
|| die "Dunst is not running."
dbus-send --print-reply=literal --dest="${DBUS_NAME}" "${DBUS_PATH}" "${DBUS_IFAC_FDN}.GetServerInformation" \
| (
read -r name _ version _
[ "${name}" = "dunst" ]
printf "dunst version: %s\n" "${version}"
) \
|| die "Another notification manager is running. It's not dunst"
dbus-send --print-reply=literal --dest="${DBUS_NAME}" "${DBUS_PATH}" "${DBUS_IFAC_DUNST}.Ping" >/dev/null 2>/dev/null \
|| die "Dunst controlling interface not available. Is the version too old?"
;;
"")
die "dunstctl: No command specified. Please consult the usage."
;;
*)
die "dunstctl: unrecognized command '${1:-}'. Please consult the usage."
;;
esac

@ -36,7 +36,7 @@ static GOptionEntry entries[] =
{ "serverinfo", 's', 0, G_OPTION_ARG_NONE, &serverinfo, "Print server information and exit", NULL},
{ "printid", 'p', 0, G_OPTION_ARG_NONE, &printid, "Print id, which can be used to update/replace this notification", NULL},
{ "replace", 'r', 0, G_OPTION_ARG_INT, &replace_id, "Set id of this notification.", "ID"},
{ "close", 'C', 0, G_OPTION_ARG_INT, &close_id, "Set id of this notification.", "ID"},
{ "close", 'C', 0, G_OPTION_ARG_INT, &close_id, "Close the notification with the specified ID", "ID"},
{ "block", 'b', 0, G_OPTION_ARG_NONE, &block, "Block until notification is closed and print close reason", NULL},
{ NULL }
};
@ -76,6 +76,33 @@ void print_serverinfo(void)
spec_version);
}
/*
* Glib leaves the option terminator "--" in the argv after parsing in some
* cases. This function gets the specified argv element ignoring the first
* terminator.
*
* See https://developer.gnome.org/glib/stable/glib-Commandline-option-parser.html#g-option-context-parse for details
*/
char *get_argv(char *argv[], int index)
{
for (int i = 0; i <= index; i++) {
if (strcmp(argv[i], "--") == 0) {
return argv[index + 1];
}
}
return argv[index];
}
/* Count the number of arguments in argv excluding the terminator "--" */
int count_args(char *argv[], int argc) {
for (int i = 0; i < argc; i++) {
if (strcmp(argv[i], "--") == 0)
return argc - 1;
}
return argc;
}
void parse_commandline(int argc, char *argv[])
{
GError *error = NULL;
@ -100,17 +127,18 @@ void parse_commandline(int argc, char *argv[])
die(0);
}
if (argc < 2 && close_id < 1) {
int n_args = count_args(argv, argc);
if (n_args < 2 && close_id < 1) {
g_printerr("I need at least a summary\n");
die(1);
} else if (argc < 2) {
} else if (n_args < 2) {
summary = g_strdup("These are not the summaries you are looking for");
} else {
summary = g_strdup(argv[1]);
summary = g_strdup(get_argv(argv, 1));
}
if (argc > 2) {
body = g_strcompress(argv[2]);
if (n_args > 2) {
body = g_strcompress(get_argv(argv, 2));
}
if (urgency_str) {

@ -80,7 +80,8 @@
# Don't remove messages, if the user is idle (no mouse or keyboard input)
# for longer than idle_threshold seconds.
# Set to 0 to disable.
# Transient notifications ignore this setting.
# A client can set the 'transient' hint to bypass this. See the rules
# section for how to disable this if necessary
idle_threshold = 120
### Text ###
@ -99,7 +100,7 @@
# <u>underline</u>
#
# For a complete reference see
# <http://developer.gnome.org/pango/stable/PangoMarkupFormat.html>.
# <https://developer.gnome.org/pango/stable/pango-Markup.html>.
#
# strip: This setting is provided for compatibility with some broken
# clients that send markup even though it's not enabled on the
@ -131,6 +132,10 @@
# Possible values are "left", "center" and "right".
alignment = left
# Vertical alignment of message text and icon.
# Possible values are "top", "center" and "bottom".
vertical_alignment = center
# Show age of message if message is older than show_age_threshold
# seconds.
# Set to -1 to disable.
@ -147,10 +152,10 @@
# Ignore newlines '\n' in notifications.
ignore_newline = no
# Merge multiple notifications with the same content
# Stack together notifications with the same content
stack_duplicates = true
# Hide the count of merged notifications with the same content
# Hide the count of stacked notifications with the same content
hide_duplicate_count = false
# Display indicators for URLs (U) and actions (A).
@ -159,7 +164,12 @@
### Icons ###
# Align icons left/right/off
icon_position = off
icon_position = left
# Scale small icons up to this size, set to 0 to disable. Helpful
# for e.g. small files or high-dpi screens. In case of conflict,
# max_icon_size takes precedence over this.
min_icon_size = 0
# Scale larger icons down to this size, set to 0 to disable
max_icon_size = 32
@ -214,6 +224,12 @@
# notification height to avoid clipping text and/or icons.
corner_radius = 0
# Ignore the dbus closeNotification message.
# Useful to enforce the timeout set by dunst configuration. Without this
# parameter, an application may close the notification sent before the
# user defined timeout.
ignore_dbusclose = false
### Legacy
# Use the Xinerama extension instead of RandR for multi-monitor support.
@ -228,15 +244,17 @@
### mouse
# Defines action of mouse event
# Defines list of actions for each mouse event
# Possible values are:
# * none: Don't do anything.
# * do_action: If the notification has exactly one action, or one is marked as default,
# invoke it. If there are multiple and no default, open the context menu.
# * close_current: Close current notification.
# * close_all: Close all notifications.
# These values can be strung together for each mouse event, and
# will be executed in sequence.
mouse_left_click = close_current
mouse_middle_click = do_action
mouse_middle_click = do_action, close_current
mouse_right_click = close_all
# Experimental features that may or may not work correctly. Do not expect them
@ -297,11 +315,36 @@
# Every section that isn't one of the above is interpreted as a rules to
# override settings for certain messages.
# Messages can be matched by "appname", "summary", "body", "icon", "category",
# "msg_urgency" and you can override the "timeout", "urgency", "foreground",
# "background", "frame_color", "new_icon" and "format", "fullscreen".