Compare commits

..

No commits in common. "master" and "v1.4.1" have entirely different histories.

98 changed files with 849 additions and 10103 deletions

71
.circleci/config.yml Normal file
View File

@ -0,0 +1,71 @@
version: 2.1
jobs:
misc-doxygen:
docker:
- image: dunst/ci:misc-doxygen
environment:
SYSTEMD: 0
SERVICEDIR_DBUS: /tmp/none
SERVICEDIR_SYSTEMD: /tmp/none
PKG_CONFIG: echo
steps:
- checkout
- run: make -j doc-doxygen
compileandtest:
environment:
CFLAGS: -Werror
parameters:
distro:
type: string
docker:
- image: dunst/ci:<<parameters.distro>>
steps:
- checkout
- run: make CC=clang -j all dunstify test/test
- run: make CC=clang -j test-valgrind
- run: ./test/test-install.sh
- run: make clean
- run: make CC=gcc -j all dunstify test/test
- run: make CC=gcc -j test-valgrind
- run: make clean
- run: make -j test-coverage
workflows:
version: 2
build-in-docker:
jobs:
- misc-doxygen
- compileandtest:
name: Alpine
distro: alpine
- compileandtest:
name: Debian Stretch
distro: debian-stretch
requires:
- misc-doxygen
- Alpine
- compileandtest:
name: Arch Linux
distro: archlinux
requires:
- misc-doxygen
- Alpine
- compileandtest:
name: Fedora 30
distro: fedora30
requires:
- misc-doxygen
- Alpine
- compileandtest:
name: Ubuntu 16.04
distro: ubuntu-xenial
requires:
- misc-doxygen
- Alpine
- compileandtest:
name: Ubuntu 18.04
distro: ubuntu-bionic
requires:
- misc-doxygen
- Alpine

View File

@ -1,82 +0,0 @@
name: main
on:
push:
pull_request:
branches:
- master
jobs:
build:
strategy:
matrix:
CC:
- clang
- gcc
distro:
- alpine
- archlinux
- debian-stretch
- debian-buster
- fedora
- ubuntu-xenial
- ubuntu-bionic
- ubuntu-focal
env:
CC: ${{ matrix.CC }}
EXTRA_CFLAGS: "-Werror"
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/-non-git/-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 }}

4
.gitignore vendored
View File

@ -3,13 +3,11 @@
*.gcda
*.gcno
*.gcov
/lcov.info
core
vgcore.*
/docs/*.1
/docs/*.5
/docs/dunst.1
/docs/internal/coverage
/docs/internal/html
/dunst

38
.travis.yml Normal file
View File

@ -0,0 +1,38 @@
addons:
apt:
packages:
- doxygen
- graphviz
- libdbus-1-dev
- libx11-dev
- libxrandr-dev
- libxinerama-dev
- libxss-dev
- libglib2.0-dev
- libpango1.0-dev
- libcairo2-dev
- libnotify-dev
- libgtk-3-dev
- valgrind
dist: xenial
sudo: false
language: c
git:
depth: false
before_install:
- pip install --user cpp-coveralls
script:
- CFLAGS="-Werror" make all dunstify test-valgrind doc-doxygen
- ./test/test-install.sh
- CFLAGS="-Werror" make clean
- CFLAGS="-Werror" make test-coverage
matrix:
include:
- compiler: gcc
after_success:
- coveralls
- compiler: clang

View File

@ -20,45 +20,11 @@
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
{
rsvg_error_handle_close2
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*
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
...
}
# Some new in ArchLinux
{
rsvg_rust_handle_close
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
...
fun:rsvg_rust_handle_close
obj:*/loaders/libpixbufloader-svg.so
...
fun:gdk_pixbuf_new_from_file
fun:get_pixbuf_from_file
...
}
@ -79,8 +45,7 @@
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:gdk_pixbuf_new_from_file
fun:get_pixbuf_from_file
...
}

View File

@ -1,66 +1,5 @@
# Dunst changelog
## Unreleased
### Added
### Changed
### Fixed
## 1.6.1 - 2021-02-21:
### Fixed
- Incorrect version in Makefile
## 1.6.0 - 2021-02-21:
### Added
- Wayland support. Dunst now runs natively on wayland. This fixes several bugs
with dunst on wayland and allows idle detection. (#781)
- A progress bar, useful for showing volume or brightness in notifications (#775)
- A script in contrib for using the progress bar (#791)
- `dunstctl count` for showing the number of notifications (#793)
- Expose environment variables info about the notification to scripts (#802)
- `text_icon_padding` for adding padding between the notification icon and text
(#810)
### Changed
- Dunst now installs a system-wide config in `/etc/dunst/dunstrc` (#798)
- Move part of the man page to dunst(5) (#799)
### Fixed
- `history_ignore` flag broken when using multiple rules (#747)
- Divide by zero in radius calculation (#750)
- Monitor setting overriding `follow_mode` (#755)
- Incorrect monitor usage when using multiple X11 screens (#762)
- Emit signal when `paused` property changes (#766)
- `dunstify` can pass empty appname to libnotify (#768)
- Incorrect handling of 'do_action, close' mouse action (#778)
# Removed
- `DUNST_COMMAND_{PAUSE,RESUME,TOGGLE}` (#830)
## 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)
### 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

View File

@ -15,10 +15,6 @@
- Add the comments to the prototype. Doxygen will merge the protoype and implementation documentation anyways.
Except for **static** methods, add the documentation header to the implementation and *not to the prototype*.
- Member documentation should happen with `/**<` and should span to the right side of the member
- Test files that have the same name as a file in src/\* can include the
associated .c file. This is because they are being compiled INSTEAD of the src
file.
## Log messages

View File

@ -3,7 +3,7 @@
include config.mk
VERSION := "1.6.1-non-git"
VERSION := "1.4.1 (2019-07-03)"
ifneq ($(wildcard ./.git/),)
VERSION := $(shell ${GIT} describe --tags)
endif
@ -33,14 +33,6 @@ $(error "Failed to query $(PKG_CONFIG) for package 'systemd'!")
endif
endif
ifneq (0,${WAYLAND})
DATA_DIR_WAYLAND_PROTOCOLS ?= $(shell $(PKG_CONFIG) wayland-protocols --variable=pkgdatadir)
DATA_DIR_WAYLAND_PROTOCOLS := ${DATA_DIR_WAYLAND_PROTOCOLS}
ifeq (,${DATA_DIR_WAYLAND_PROTOCOLS})
$(warning "Failed to query $(PKG_CONFIG) for package 'wayland-protocols'!")
endif
endif
LIBS := $(shell $(PKG_CONFIG) --libs ${pkg_config_packs})
INCS := $(shell $(PKG_CONFIG) --cflags ${pkg_config_packs})
@ -53,14 +45,7 @@ endif
CFLAGS := ${DEFAULT_CPPFLAGS} ${CPPFLAGS} ${DEFAULT_CFLAGS} ${CFLAGS} ${INCS} -MMD -MP
LDFLAGS := ${DEFAULT_LDFLAGS} ${LDFLAGS} ${LIBS}
ifeq (0,${WAYLAND})
# without wayland support
SRC := $(sort $(shell ${FIND} src/ -not \( -path src/wayland -prune \) -name '*.c'))
else
# with Wayland support
SRC := $(sort $(shell ${FIND} src/ -name '*.c'))
endif
OBJ := ${SRC:.c=.o}
TEST_SRC := $(sort $(shell ${FIND} test/ -name '*.c'))
TEST_OBJ := $(TEST_SRC:.c=.o)
@ -68,7 +53,7 @@ DEPS := ${SRC:.c=.d} ${TEST_SRC:.c=.d}
.PHONY: all debug
all: doc dunst dunstify service
all: doc dunst service
debug: CFLAGS += ${CPPFLAGS_DEBUG} ${CFLAGS_DEBUG}
debug: LDFLAGS += ${LDFLAGS_DEBUG}
@ -90,9 +75,7 @@ dunstify: dunstify.o
.PHONY: test test-valgrind test-coverage
test: test/test clean-coverage-run
# Make sure an error code is returned when the test fails
/usr/bin/env bash -c 'set -euo pipefail;\
./test/test -v | ./test/greenest.awk '
./test/test -v
test-valgrind: test/test
${VALGRIND} \
@ -123,21 +106,13 @@ test/test: ${OBJ} ${TEST_OBJ}
${CC} -o ${@} ${TEST_OBJ} $(filter-out ${TEST_OBJ:test/%=src/%},${OBJ}) ${CFLAGS} ${LDFLAGS}
.PHONY: doc doc-doxygen
doc: docs/dunst.1 docs/dunst.5 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.1.pod
doc: docs/dunst.1
docs/dunst.1: docs/dunst.pod
${POD2MAN} --name=dunst -c "Dunst Reference" --section=1 --release=${VERSION} $< > $@
docs/dunst.5: docs/dunst.5.pod
${POD2MAN} --name=dunst -c "Dunst Reference" --section=5 --release=${VERSION} $< > $@
docs/dunstctl.1: docs/dunstctl.pod
${POD2MAN} --name=dunstctl -c "dunstctl reference" --section=1 --release=${VERSION} $< > $@
doc-doxygen:
${DOXYGEN} docs/internal/Doxyfile
.PHONY: service service-dbus service-systemd wayland-protocols
.PHONY: service service-dbus service-systemd
service: service-dbus
service-dbus:
@${SED} "s|##PREFIX##|$(PREFIX)|" org.knopwob.dunst.service.in > org.knopwob.dunst.service
@ -147,23 +122,7 @@ service-systemd:
@${SED} "s|##PREFIX##|$(PREFIX)|" dunst.systemd.service.in > dunst.systemd.service
endif
ifneq (0,${WAYLAND})
wayland-protocols: src/wayland/protocols/wlr-layer-shell-unstable-v1.xml src/wayland/protocols/wlr-foreign-toplevel-management-unstable-v1.xml
# TODO: write this shorter
mkdir -p src/wayland/protocols
wayland-scanner private-code ${DATA_DIR_WAYLAND_PROTOCOLS}/stable/xdg-shell/xdg-shell.xml src/wayland/protocols/xdg-shell.h
wayland-scanner client-header ${DATA_DIR_WAYLAND_PROTOCOLS}/stable/xdg-shell/xdg-shell.xml src/wayland/protocols/xdg-shell-client-header.h
wayland-scanner client-header ${DATA_DIR_WAYLAND_PROTOCOLS}/unstable/xdg-output/xdg-output-unstable-v1.xml src/wayland/protocols/xdg-output-unstable-v1-client-header.h
wayland-scanner private-code ${DATA_DIR_WAYLAND_PROTOCOLS}/unstable/xdg-output/xdg-output-unstable-v1.xml src/wayland/protocols/xdg-output-unstable-v1.h
wayland-scanner client-header src/wayland/protocols/wlr-layer-shell-unstable-v1.xml src/wayland/protocols/wlr-layer-shell-unstable-v1-client-header.h
wayland-scanner private-code src/wayland/protocols/wlr-layer-shell-unstable-v1.xml src/wayland/protocols/wlr-layer-shell-unstable-v1.h
wayland-scanner client-header src/wayland/protocols/idle.xml src/wayland/protocols/idle-client-header.h
wayland-scanner private-code src/wayland/protocols/idle.xml src/wayland/protocols/idle.h
wayland-scanner client-header src/wayland/protocols/wlr-foreign-toplevel-management-unstable-v1.xml src/wayland/protocols/wlr-foreign-toplevel-management-unstable-v1-client-header.h
wayland-scanner private-code src/wayland/protocols/wlr-foreign-toplevel-management-unstable-v1.xml src/wayland/protocols/wlr-foreign-toplevel-management-unstable-v1.h
endif
.PHONY: clean clean-dunst clean-dunstify clean-doc clean-tests clean-coverage clean-coverage-run clean-wayland-protocols
.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:
@ -178,8 +137,6 @@ clean-dunstify:
clean-doc:
rm -f docs/dunst.1
rm -f docs/dunst.5
rm -f docs/dunstctl.1
rm -fr docs/internal/html
rm -fr docs/internal/coverage
@ -194,26 +151,18 @@ clean-coverage-run:
${FIND} . -type f -name '*.gcov' -delete
${FIND} . -type f -name '*.gcda' -delete
clean-wayland-protocols:
rm -f src/wayland/protocols/*.h
.PHONY: install install-dunst install-dunstctl install-doc \
.PHONY: install install-dunst install-doc \
install-service install-service-dbus install-service-systemd \
uninstall uninstall-dunstctl \
uninstall \
uninstall-service uninstall-service-dbus uninstall-service-systemd
install: install-dunst install-dunstctl install-doc install-service install-dunstify
install: install-dunst install-doc install-service
install-dunst: dunst doc
install -Dm755 dunst ${DESTDIR}${BINDIR}/dunst
install -Dm644 docs/dunst.1 ${DESTDIR}${MANPREFIX}/man1/dunst.1
install -Dm644 docs/dunst.5 ${DESTDIR}${MANPREFIX}/man5/dunst.5
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}${SYSCONFDIR}/dunst/dunstrc
install -Dm644 dunstrc ${DESTDIR}${DATADIR}/dunst/dunstrc
install-service: install-service-dbus
install-service-dbus: service-dbus
@ -224,19 +173,10 @@ install-service-systemd: service-systemd
install -Dm644 dunst.systemd.service ${DESTDIR}${SERVICEDIR_SYSTEMD}/dunst.service
endif
install-dunstify: dunstify
install -Dm755 dunstify ${DESTDIR}${BINDIR}/dunstify
uninstall: uninstall-service uninstall-dunstctl
uninstall: uninstall-service
rm -f ${DESTDIR}${BINDIR}/dunst
rm -f ${DESTDIR}${BINDIR}/dunstify
rm -f ${DESTDIR}${MANPREFIX}/man1/dunst.1
rm -f ${DESTDIR}${MANPREFIX}/man5/dunst.5
rm -f ${DESTDIR}${MANPREFIX}/man1/dunstctl.1
rm -rf ${DESTDIR}${SYSCONFDIR}/dunst
uninstall-dunstctl:
rm -f ${DESTDIR}${BINDIR}/dunstctl
rm -rf ${DESTDIR}${DATADIR}/dunst
uninstall-service: uninstall-service-dbus
uninstall-service-dbus:

113
README.md
View File

@ -1,94 +1,30 @@
[![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)
[![CircleCI](https://circleci.com/gh/dunst-project/dunst/tree/master.svg?style=svg)](https://circleci.com/gh/dunst-project/dunst/tree/master) [![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=master)](https://coveralls.io/github/dunst-project/dunst?branch=master)
# Dunst
## Dunst
<i>A highly configurable and lightweight notification daemon.</i>
![music](contrib/screenshots/music.png)
## Table of Contents
* [Features](#features)
* [Building](#building)
* [Documentation](#documentation)
* [Wiki][wiki]
* [Description](#description)
* [Compiling](#compiling)
* [Copyright](#copyright)
# Features
## Description
## ⚙️ Highly customizable
Dunst is a highly configurable and lightweight notification daemon.
Customize fonts, icons, timeouts, and more. Are you unhappy with the default
shortcuts and colors? No worries, you can change these all with a simple
configuration file tweak.
_click the images to see the dunstrc_
<a href="https://gist.github.com/NNBnh/5f6e601a6a82a6ed43b1959698758141">
<img alt="screenshot1" src="contrib/screenshots/screenshot1_cut.png">
</a>
<a href="https://gist.github.com/fwSmit/9127d988b07bcec9d869f2c927d0f616">
<img alt="screenshot2" src="contrib/screenshots/screenshot2_cut.png">
</a>
## 📜 Scripting
<a href="https://gitlab.manjaro.org/profiles-and-settings/manjaro-theme-settings/-/blob/master/skel/.config/dunst/dunstrc">
<img alt="screenshot_urgency" src="contrib/screenshots/screenshot_urgency.png">
</a>
Run custom scripts on notifications matching a specified pattern. Have espeak
read out your notifications, or play a song when your significant other signs on
in pidgin!
## 📋 Rules
Change the look or behavior of notifications matching a specified pattern. You
could use this to change the color of message notifications from your favorite
jabber buddies, or to prevent important work email notifications from
disappearing until you manually dismiss them.
## ⏸️ Pause
If you want to take a break and not receive any notifications for a while, just
pause dunst. All notifications will be saved for you to catch up
later.
## 🕘 History
Catch an unread notification disappearing from the corner of your eye? Just tap
a keyboard shortcut to replay the last notification, or continue tapping to see
your notification history.
# Documentation
Most documentation can be found in dunst's man pages. In
[**dunst(1)**](docs/dunst.1.pod) contains some general instructions on how
to run dunst and in
[**dunst(5)**](docs/dunst.5.pod) all of dunst's configuration options are
explained.
On the dunst [wiki][wiki] you can find guides and installation instructions and
on the dunst [website][website] there is a [FAQ][FAQ] with common issues.
## Installation
Dunst is available in many package repositories. If it's not available in your
distro's repositories, don't worry, it's not hard to build it yourself.
### Dependencies
- dbus (runtime)
Dunst has a number of build dependencies that must be present before attempting configuration. The names are different depending on [distribution](https://github.com/dunst-project/dunst/wiki/Dependencies):
- dbus
- libxinerama
- libxrandr
- libxss
- glib
- pango/cairo
- libnotify (optional, for dunstify)
- wayland-client (can build without, see [make parameters](#make-parameters))
- wayland-protocols (optional, for recompiling protocols)
The names will be different depending on your [distribution](https://github.com/dunst-project/dunst/wiki/Dependencies).
- libgtk-3-dev
### Building
@ -101,32 +37,21 @@ sudo make install
### Make parameters
- `DESTDIR=<PATH>`: Set the destination directory of the installation. (Default: `/`)
- `PREFIX=<PATH>`: Set the prefix of the installation. (Default: `/usr/local`)
- `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)`: Disable/Enable the systemd unit. (Default: detected via `pkg-config`)
- `WAYLAND=(0|1)`: Disable/Enable wayland support. (Default: 1 (enabled))
- `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`)
- `EXTRA_CFLAGS=<FLAGS>`: Additional flags for the compiler.
**Make sure to run all make calls with the same parameter set. So when building with `make PREFIX=/usr`, you have to install it with `make PREFIX=/usr install`, too.**
Checkout the [wiki][wiki] for more information.
## Bug reports
Please use the [issue tracker][issue-tracker] provided by GitHub to send us bug reports or feature requests.
## Screenshots
<a href="https://gist.github.com/MCotocel/2b34486ae59ccda4319fcb93454d212c">
<img alt="screenshot3" src="contrib/screenshots/screenshot3_cut.png">
</a>
<a href="https://gitlab.manjaro.org/profiles-and-settings/manjaro-theme-settings/-/blob/master/skel/.config/dunst/dunstrc">
<img alt="progress" src="https://user-images.githubusercontent.com/23078054/102542111-98b01e00-40b1-11eb-967e-bc952430bd06.png">
</a>
Please use the [issue tracker][issue-tracker] provided by GitHub to send us bug reports or feature requests. You can also join us on the IRC channel `#dunst` on Freenode.
## Maintainers
@ -135,13 +60,13 @@ Please use the [issue tracker][issue-tracker] provided by GitHub to send us bug
## Author
Written by Sascha Kruse <dunst@knopwob.de>
written by Sascha Kruse <dunst@knopwob.de>
## Copyright
Copyright 2013 Sascha Kruse and contributors (see [`LICENSE`](./LICENSE) for licensing information)
copyright 2013 Sascha Kruse and contributors (see [`LICENSE`](./LICENSE) for licensing information)
If you feel that copyrights are violated, please send me an email.
[issue-tracker]: https://github.com/dunst-project/dunst/issues
[wiki]: https://github.com/dunst-project/dunst/wiki
[website]: https://dunst-project.org
[FAQ]: https://dunst-project.org/faq

View File

@ -1,50 +1,3 @@
===================================================================================
Release Notes For v1.6.0
===================================================================================
For users:
At long last, dunst has native wayland support. On startup dunst will now
autodetect the display environment it's run on and use the appropriate backend
(X11 or wayland).
Additionally, support for progress bars has been added when the 'value' hint is
used. Try it out with `notify-send -h int:value:70 'Progress bars!'`
Last but most importantly, support for the
`DUNST_COMMAND_{PAUSE,RESUME,TOGGLE}` has been removed as they could
potentially be used to DoS dunst. `dunstctl` has been available as a direct
replacement for the use-case they served since last release. See
https://github.com/dunst-project/dunst/pull/830 for details
For maintainers:
Dunst now depends on the wayland libraries and (optionally) on the
wayland-protocols package. A global configuration file is now installed by
default in `/etc/dunst/dunstrc`
===================================================================================
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
===================================================================================

View File

@ -6,13 +6,10 @@ struct settings defaults = {
.markup = MARKUP_NO,
.colors_norm.bg = "#1793D1",
.colors_norm.fg = "#DDDDDD",
.colors_norm.highlight = "#1745d1",
.colors_crit.bg = "#ffaaaa",
.colors_crit.fg = "#000000",
.colors_crit.highlight = "#ff6666",
.colors_low.bg = "#aaaaff",
.colors_low.fg = "#000000",
.colors_low.highlight = "#7f7fff",
.format = "%s %b", /* default format */
.timeouts = { S2US(10), S2US(10), S2US(0) }, /* low, normal, critical */
@ -36,25 +33,19 @@ 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 */
.notification_height = 0, /* if notification height < font height and padding, it will be raised */
.corner_radius = 0,
.force_xinerama = false,
.force_xwayland = false,
.separator_height = 2, /* height of the separator line between two notifications */
.padding = 0,
.h_padding = 0, /* horizontal padding */
.text_icon_padding = 0, /* padding between icon and text*/
.sep_color = {SEP_AUTO}, /* SEP_AUTO, SEP_FOREGROUND, SEP_FRAME, SEP_CUSTOM */
.frame_width = 0,
@ -74,7 +65,6 @@ struct settings defaults = {
.browser = "/usr/bin/firefox",
.min_icon_size = 0,
.max_icon_size = 0,
/* paths to default icons */
@ -111,23 +101,12 @@ struct settings defaults = {
.code = 0,.sym = NoSymbol,.is_valid = false
}, /* ignore this */
.mouse_left_click = (enum mouse_action []){MOUSE_CLOSE_CURRENT, -1},
.mouse_left_click = MOUSE_CLOSE_CURRENT,
.mouse_middle_click = (enum mouse_action []){MOUSE_DO_ACTION, -1},
.mouse_middle_click = MOUSE_DO_ACTION,
.mouse_right_click = (enum mouse_action []){MOUSE_CLOSE_ALL, -1},
.mouse_right_click = MOUSE_CLOSE_ALL,
.progress_bar_height = 10,
.progress_bar_min_width = 150,
.progress_bar_max_width = 300,
.progress_bar_frame_width = 1,
.progress_bar = true,
.layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
};
struct rule default_rules[] = {
@ -159,4 +138,4 @@ struct rule default_rules[] = {
}
};
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -1,12 +1,10 @@
# paths
PREFIX ?= /usr/local
BINDIR ?= ${PREFIX}/bin
SYSCONFDIR ?= /etc
DATADIR ?= ${PREFIX}/share
# around for backwards compatibility
MANPREFIX ?= ${DATADIR}/man
MANDIR ?= ${MANPREFIX}
EXTRA_CFLAGS ?=
DOXYGEN ?= doxygen
FIND ?= find
@ -22,23 +20,14 @@ VALGRIND ?= valgrind
# if you don't want to use systemd albeit installed
#SYSTEMD ?= 0
# Disable dependency on wayland. This will force dunst to use
# xwayland on wayland compositors
# You can also use "make WAYLAND=0" to build without wayland
# WAYLAND ?= 0
ifneq (0, ${WAYLAND})
ENABLE_WAYLAND= -DENABLE_WAYLAND
endif
# uncomment to disable parsing of dunstrc
# or use "CFLAGS=-DSTATIC_CONFIG make" to build
#STATIC= -DSTATIC_CONFIG # Warning: This is deprecated behavior
# flags
DEFAULT_CPPFLAGS = -D_DEFAULT_SOURCE -DVERSION=\"${VERSION}\"
DEFAULT_CFLAGS = -g --std=gnu99 -pedantic -Wall -Wno-overlength-strings -Os ${STATIC} ${ENABLE_WAYLAND} ${EXTRA_CFLAGS}
DEFAULT_LDFLAGS = -lm -lrt
DEFAULT_CFLAGS = -g --std=gnu99 -pedantic -Wall -Wno-overlength-strings -Os ${STATIC}
DEFAULT_LDFLAGS = -lm
CPPFLAGS_DEBUG := -DDEBUG_BUILD
CFLAGS_DEBUG := -O0
@ -52,16 +41,13 @@ pkg_config_packs := gio-2.0 \
xinerama \
xext \
"xrandr >= 1.5" \
xscrnsaver \
# dunstify also needs libnotify
pkg_config_packs += libnotify
ifneq (0,${WAYLAND})
pkg_config_packs += wayland-client
endif
xscrnsaver
ifneq (,$(findstring STATIC_CONFIG,$(CFLAGS)))
$(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
endif

View File

@ -1,75 +0,0 @@
#!/usr/bin/env sh
# progress-notify - Send audio and brightness notifications for dunst
# dependencies: dunstify, ponymix, Papirus (icons)
### How to use: ###
# Pass the values via stdin and provide the notification type
# as an argument. Options are audio, brightness and muted
### Audio notifications ###
# ponymix increase 5 | notify audio
# ponymix decrease 5 | notify audio
# pulsemixer --toggle-mute --get-mute | notify muted
### Brightness notifications ###
# xbacklight -inc 5 && xbacklight -get | notify brightness
# xbacklight -dec 5 && xbacklight -get | notify brightness
notifyMuted() {
volume="$1"
dunstify -h string:x-canonical-private-synchronous:audio "Muted" -h int:value:"$volume" -t 1500 --icon audio-volume-muted
}
notifyAudio() {
volume="$1"
ponymix is-muted && notifyMuted "$volume" && return
if [ $volume -eq 0 ]; then
notifyMuted "$volume"
elif [ $volume -le 30 ]; then
dunstify -h string:x-canonical-private-synchronous:audio "Volume: " -h int:value:"$volume" -t 1500 --icon audio-volume-low
elif [ $volume -le 70 ]; then
dunstify -h string:x-canonical-private-synchronous:audio "Volume: " -h int:value:"$volume" -t 1500 --icon audio-volume-medium
else
dunstify -h string:x-canonical-private-synchronous:audio "Volume: " -h int:value:"$volume" -t 1500 --icon audio-volume-high
fi
}
notifyBrightness() {
brightness="$1"
if [ $brightness -eq 0 ]; then
dunstify -h string:x-canonical-private-synchronous:brightness "Brightness: " -h int:value:"$brightness" -t 1500 --icon display-brightness-off-symbolic
elif [ $brightness -le 30 ]; then
dunstify -h string:x-canonical-private-synchronous:brightness "Brightness: " -h int:value:"$brightness" -t 1500 --icon display-brightness-low-symbolic
elif [ $brightness -le 70 ]; then
dunstify -h string:x-canonical-private-synchronous:brightness "Brightness: " -h int:value:"$brightness" -t 1500 --icon display-brightness-medium-symbolic
else
dunstify -h string:x-canonical-private-synchronous:brightness "Brightness: " -h int:value:"$brightness" -t 1500 --icon display-brightness-high-symbolic
fi
}
input=`cat /dev/stdin`
case "$1" in
muted)
volume=`ponymix get-volume`
if [ "$input" -eq 0 ]
then
notifyAudio "$volume"
else
notifyMuted "$volume"
fi
;;
audio)
notifyAudio "$input"
;;
brightness)
notifyBrightness "$input"
;;
*)
echo "Not the right arguments"
echo "$1"
exit 2
esac

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 672 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 KiB

View File

@ -1,172 +0,0 @@
=head1 NAME
dunst - A customizable and lightweight notification-daemon
=head1 SYNOPSIS
dunst [-conf file] [-font font] [-geometry geom] [-format fmt] [-follow mode] [-monitor n] [-history_length n] ...
=head1 DESCRIPTION
Dunst is a highly configurable and lightweight notification daemon.
=head2 Autostarting dunst
On most installations dunst should be able to automatically be started by D-Bus
when a notification is sent. This is not recommended when multiple notification
deamons are installed, because D-Bus will not know which one to start.
Other ways of autostarting dunst include starting dunst with your desktop
environment or window manager's autostart functionality or via the provided
systemd service.
=head1 COMMAND LINE OPTIONS
=over 4
=item B<-h/--help>
List all command line flags
=item B<-conf/-config file>
Use alternative config file.
=item B<-v/--version>
Print version information.
=item B<-print>
Print notifications to stdout. This might be useful for logging, setting up
rules or using the output in other scripts.
=item B<->F<SETTING> B<[value]>
Where F<SETTING> can be any setting that's available in the global section of
the configuration file. See dunst(5) for possible settings.
Each configuration option in the global section can be overridden from the
command line by adding a single dash in front of it's name.
For example the font option can be overridden by running
$ dunst -font "LiberationSans Mono 4"
Configuration options that take boolean values can only currently be set to
"true" through the command line via the same method. e.g.
$ dunst -shrink
This is a known limitation of the way command line parameters are parsed and
will be changed in the future.
=back
=head1 CONFIGURATION
An example configuration file is included (usually /etc/dunst/dunstrc). Note:
this was previously /usr/share/dunst/dunstrc.
Before using dunst, copy this file to ~/.config/dunst/dunstrc and edit
it accordingly. See dunst(5) for all possible settings.
=head2 NOTIFY-SEND
dunst is able to get different colors for a message via notify-send.
In order to do that you have to add a hint via the -h option.
The progress value can be set with a hint, too.
=over 4
=item notify-send -h string:fgcolor:#ff4444
=item notify-send -h string:bgcolor:#4444ff -h string:fgcolor:#ff4444 -h string:frcolor:#44ff44
=item notify-send -h int:value:42 "Working ..."
=back
=head1 ACTIONS
Dunst allows notifiers (i.e.: programs that send the notifications) to specify
actions. Dunst has support for both displaying indicators for these, and
interacting with these actions.
If "show_indicators" is true and a notification has an action, an "(A)" will be
prepended to the notification format. Likewise, an "(U)" is prepended to
notifications with URLs. It is possible to interact with notifications that
have actions regardless of this setting, though it may not be obvious which
notifications HAVE actions.
The "context" keybinding is used to interact with these actions, by showing a
menu of possible actions. This feature requires "dmenu" or a dmenu drop-in
replacement present. It is preferred to set this keybinding with your window
manager or desktop envirorment and let it execute C<dunsctl context>. Another
option is to set this keybinding in your dunstrc, but this is soon to be deprecated
(and doesn't work on Wayland).
Alternatively, you can invoke an action with a middle click on the notification.
If there is exactly one associated action, or one is marked as default, that one
is invoked. If there are multiple, the context menu is shown. The same applies
to URLs when there are no actions. You can change the mouse button to right click
by setting C<mouse_right_click = close_all> in your dunstrc.
=head1 MISCELLANEOUS
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:
=over 4
=item killall -SIGUSR1 dunst # pause
=item killall -SIGUSR2 dunst # resume
=back
When paused dunst will not display any notifications but keep all notifications
in a queue. This can for example be wrapped around a screen locker (i3lock,
slock) to prevent flickering of notifications through the lock and to read all
missed notifications after returning to the computer.
=head1 FILES
These are the places where dunst will look for a configuration file. They are
listed here in order and if dunst finds one of them, it will stop looking for
more.
$XDG_CONFIG_HOME/dunst/dunstrc
$HOME/.config/dunst/dunstrc
-or-
$XDG_CONFIG_HOME/dunst/dunstrc
/etc/xdg/dunst/dunstrc
=over 4
=item /etc/dunst/dunstrc
This is where the default config file is located
=back
=head1 AUTHORS
Written by Sascha Kruse <knopwob@googlemail.com>
=head1 REPORTING BUGS
Bugs and suggestions should be reported on GitHub at https://github.com/dunst-project/dunst/issues
=head1 COPYRIGHT
Copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information)
If you feel that copyrights are violated, please send me an email.
=head1 SEE ALSO
dunst(5), dunstctl(1), dmenu(1), notify-send(1)

View File

@ -1,20 +1,48 @@
=head1 NAME
dunst - configuration file
dunst - A customizable and lightweight notification-daemon
=head1 SYNOPSIS
dunst [-conf file] [-font font] [-geometry geom] [-format fmt] [-follow mode] [-monitor n] [-history_length n] ...
=head1 DESCRIPTION
An example configuration file is included (usually /etc/dunst/dunstrc). Note:
this was previously /usr/share/dunst/dunstrc.
Dunst is a highly configurable and lightweight notification daemon.
=head1 COMMAND LINE OPTIONS
=over 4
=item B<-h/--help>
List all command line flags
=item B<-conf/-config file>
Use alternative config file.
=item B<-v/--version>
Print version information.
=item B<-print>
Print notifications to stdout. This might be useful for logging, setting up
rules or using the output in other scripts.
=back
=head1 CONFIGURATION
An example configuration file is included (usually /usr/share/dunst/dunstrc).
To change the configuration, copy this file to ~/.config/dunst/dunstrc and edit
it accordingly.
The configuration is divided into sections in an ini-like format. The 'global'
section contains most general settings while the setions 'urgency_low',
'urgency_normal' and 'urgency_critical' are for low, normal and critical urgency
notifications respectively. The 'shortcuts' section (deprecated) contains all
keyboard configuration and the 'experimental' section all the features that have
not yet been tested thoroughly.
section contains most general settings while the 'shortcuts' sections contains
all keyboard configuration and the 'experimental' section all the features that
have not yet been tested thoroughly.
Any section that is not one of the above is assumed to be a rule, see RULES for
more details.
@ -22,6 +50,24 @@ more details.
For backwards compatibility reasons the section name 'frame' is considered bound
and can't be used as a rule.
=head2 Command line
Each configuration option in the global section can be overridden from the
command line by adding a single dash in front of it's name.
For example the font option can be overridden by running
$ dunst -font "LiberationSans Mono 4"
Configuration options that take boolean values can only currently be set to
"true" through the command line via the same method. e.g.
$ dunst -shrink
This is a known limitation of the way command line parameters are parsed and
will be changed in the future.
Available settings per section:
=head2 Global section
=over 4
@ -36,10 +82,6 @@ starts at 0. See the B<follow> setting.
Defines where the notifications should be placed in a multi-monitor setup. All
values except I<none> override the B<monitor> setting.
On Wayland there is no difference between mouse and keyboard focus. When either
of the is used, the compositor will choose an output. This will generally be
the output last interacted with.
=over 4
=item B<none>
@ -100,32 +142,6 @@ the notification on the left border of the screen while a horizontal offset of
=back
=item B<progress_bar> (values: [true/false], default: true)
When an integer value is passed to dunst as a hint (see B<NOTIFY-SEND>), a
progress bar will be drawn at the bottom of the notification. This
behavior can be turned off by setting this setting to false.
=item B<progress_bar_height> (default: 10)
The height of the progress bar in pixel. This includes the frame. Make sure
this value is bigger than twice the frame width.
=item B<progress_bar_min_width> (default: 150)
The minimum width of the progress bar in pixels. The notification is rescaled
to fit the bar.
=item B<progress_bar_max_width> (default: 300)
The maximum width of the progress bar in pixels. The notification is resized
to fit the progress bar.
=item B<progress_bar_frame_width> (default: 1)
The frame width of the progress bar in pixels. This value should be smaller
than half of the progress bar height.
=item B<indicate_hidden> (values: [true/false], default: true)
If this is set to true, a notification indicating how many notifications are
@ -172,23 +188,6 @@ in the vertical axis
The distance in pixels from the content to the border of the window
in the horizontal axis
=item B<text_icon_padding> (default: 0)
The distance in pixels from the text to the icon (or vice versa)
in the horizontal axis.
Setting this to a non-zero value overwrites any padding that horizontal_padding was adding between the notification text and icon.
So for example setting
text_icon_padding=10
horizontal_padding=10
is equivalent to
text_icon_padding=0
horizontal_padding=10
=item B<frame_width> (default: 0)
Defines width in pixels of frame around the notification window. Set to 0 to
@ -239,25 +238,6 @@ Set to 0 to disable.
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.
Note: this doesn't work on xwayland.
=item B<layer> (Wayland only)
One of bottom, top or overlay.
Place dunst notifications on the selected layer. Using overlay
will cause notifications to be displayed above fullscreen windows, though
this may also occur at top depending on your compositor.
The bottom layer is below all windows and above the background.
Default: overlay
=item B<force_xwayland> (values: [true/false], default: false) (Wayland only)
Force the use of X11 output, even on a wayland compositor. This setting
has no effect when not using a Wayland compositor.
=item B<font> (default: "Monospace 8")
Defines the font or font set used. Optionally set the size as a decimal number
@ -292,7 +272,7 @@ Allow a small subset of html markup in notifications
<u>underline</u>
For a complete reference see
<https://developer.gnome.org/pango/stable/pango-Markup.html>
<http://developer.gnome.org/pango/stable/PangoMarkupFormat.html>
=item B<strip>
@ -357,11 +337,6 @@ 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.
@ -395,7 +370,7 @@ being displayed separately.
Two notifications are considered duplicate if the name of the program that sent
it, summary, body, icon and urgency are all identical.
=item B<hide_duplicate_count> (values: [true/false], default: false)
=item B<hide_duplicates_count> (values: [true/false], default: false)
Hide the count of stacked duplicate notifications.
@ -409,28 +384,14 @@ 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 or equal to the specified value it won't be affected.
If the icon is smaller than 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 downscaling. (default)
If both B<min_icon_size> and B<max_icon_size> are enabled, the latter
gets the last say.
Set to 0 to disable icon scaling. (default)
If B<icon_position> is set to off, this setting is ignored.
@ -489,7 +450,7 @@ Do not display log messages, which have lower precedence than specified
verbosity. This won't affect printing notifications on the terminal. Use
the '-print' option for this.
=item B<force_xinerama> (values: [true/false], default: false) (X11 only)
=item B<force_xinerama> (values: [true/false], default: false)
Use the Xinerama extension instead of RandR for multi-monitor support. This
setting is provided for compatibility with older nVidia drivers that do not
@ -511,10 +472,9 @@ single notification.
To avoid the corners clipping the icon or text the corner radius will be
automatically lowered to half of the notification height if it exceeds it.
=item B<mouse_left/middle/right_click> (values: [none/do_action/close_current/close_all/context/context_all])
=item B<mouse_left/middle/right_click> (values: [none/do_action/close_current/close_all])
Defines action of mouse click. A touch input in Wayland acts as a mouse left
click.
Defines action of mouse click.
=over 4
@ -524,13 +484,7 @@ Don't do anything.
=item B<do_action> (default for mouse_middle_click)
Invoke the action determined by the action_name rule. If there is no such
action, open the context menu.
=item B<open_url>
If the notification has exactly one url, open it. If there are multiple
ones, open the context menu.
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.
=item B<close_current> (default for mouse_left_click)
@ -540,26 +494,11 @@ Close current notification.
Close all notifications.
=item B<context>
Open context menu for the notification.
=item B<context_all>
Open context menu for all notifications.
=back
=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 B<DEPRECATED SEE DUNSTCTL> (X11 only)
=head2 Shortcut section
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.
@ -596,8 +535,8 @@ Specifies the keyboard shortcut that opens the context menu.
The urgency sections work in a similar way to rules and can be used to specify
attributes for the different urgency levels of notifications (low, normal,
critical). Currently only the background, foreground, hightlight, timeout,
frame_color and icon attributes can be modified.
critical). Currently only the background, foreground, timeout, frame_color and
icon attributes can be modified.
The urgency sections are urgency_low, urgency_normal, urgency_critical for low,
normal and critical urgency respectively.
@ -630,12 +569,6 @@ Defines the background color for low, normal and critical notifications respecti
See COLORS for the value format.
=item B<-lh/nh/ch color>
Defines the highlight color for low, normal and critical notifications respectively.
See COLORS for the value format.
=item B<-lfr/nfr/cfr color>
Defines the frame color for low, normal and critical notifications respectively.
@ -650,53 +583,18 @@ 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 dunstctl(1).
=head1 HISTORY
Dunst saves a number of notifications (specified by B<history_length>) in memory.
These notifications can be recalled (i.e. redisplayed) by calling
B<dunstctl history> (see dunstctl(1)). Whether these notifications will time out
like if they have been just send depends on the value of the B<sticky_history>
setting.
These notifications can be recalled (i.e. redisplayed) by pressing the
B<history_key> (see the shortcuts section), whether these notifications will
time out like if they have been just send depends on the value of the
B<sticky_history> setting.
Past notifications are redisplayed in a first-in-last-out order, meaning that
pressing the history key once will bring up the most recent notification that
had been closed/timed out.
=head1 WAYLAND
Dunst has Wayland support since version 1.6.0. Because the Wayland protocol
is more focused on security, some things that are possible in X11 are not
possible in Wayland. Those differences are reflected in the configuration.
The main things that change are that dunst on Wayland cannot use global
hotkeys (they are deprecated anyways, use dunstctl).
Some dunst features on wayland might need your compositor to support a certain
protocol. Dunst will warn you if an optional feature isn't supported and will
disable the corresponding functionality.
Fullscreen detection works on wayland with some limitations (see B<fullscreen>).
If you want notifications to appear over fullscreen windows, set
B<layer = overlay> in the global options.
Note that the same limitations exist when using xwayland.
If something doesn't quite work in Wayland, please file a bug report. In the
mean time, you can try if the X11 output does work on wayland. Use
B<force_xwayland = true> for that.
If you have your dunst notifications on the same side of your display as your
status bar, you might notice that your notifications appear a bit higher or
lower than on X11. This is because the notification cannot be placed on top of
your status bar. The notifications are placed relative to your status bar,
making them appear higher or lower by the height of your status bar. We cannot
do anything about that behavior, so you will need to change your B<geometry>
variable accordingly.
=head1 RULES
Rules allow the conditional modification of notifications. They are defined by
@ -794,12 +692,7 @@ The background color of the notification. See COLORS for possible values.
=item C<foreground>
The foreground color of the notification. See COLORS for possible values.
=item C<highlight>
The highlight color of the notification. This color is used for coloring the
progress bar. See COLORS for possible values.
The background color of the notification. See COLORS for possible values.
=item C<format>
@ -813,7 +706,7 @@ The frame color color of the notification. See COLORS for possible values.
One of show, delay, or pushback.
This attribute specifies how notifications are handled if a fullscreen window
This attribute speicifies 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
@ -824,16 +717,6 @@ 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.
On wayland, if B<follow> is set to mouse or keyboard, the output where the
notification is located cannot be determined. So dunst will delay or pushback if
any of the outputs is fullscreen. Since the fullscreen protocol is fairly new,
you will need a recent version of a compositor that supports it. At the time of
writing, you will need the git version of sway.
See also B<layer> to change if notifications appear above fullscreen windows in
Wayland.
Default: show
=item C<new_icon>
Updates the icon of the notification, it should be a path to a valid image.
@ -842,7 +725,7 @@ Updates the icon of the notification, it should be a path to a valid image.
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 you only want one of
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',
@ -874,13 +757,6 @@ later. Use C<msg_urgency> to match it.
Setting this to true will prevent the notification from being displayed
initially but will be saved in history for later viewing.
=item C<action_name>
Sets the name of the action to be invoked on do_action. If not specified, the
action set as default action or the only available action will be invoked.
Default: "default"
=back
As with the filtering attributes, each one corresponds to
@ -900,22 +776,11 @@ Within rules you can specify a script to be run every time the rule is matched
by assigning the 'script' option to the name of the script to be run.
When the script is called details of the notification that triggered it will be
passed via environment variables. The following variables are available:
B<DUNST_APP_NAME>, B<DUNST_SUMMARY>, B<DUNST_BODY>, B<DUNST_ICON_PATH>,
B<DUNST_URGENCY>, B<DUNST_ID>, B<DUNST_PROGRESS>, B<DUNST_CATEGORY>,
B<DUNST_STACK_TAG>, B<DUNST_URLS>, B<DUNST_TIMEOUT>, B<DUNST_TIMESTAMP>
and B<DUNST_STACK_TAG>.
passed via command line parameters in the following order: appname, summary,
body, icon, urgency.
Another, less recommended way to get notifcations details from a script is via
command line parameters. These are passed to the script in the following order:
B<appname>, B<summary>, B<body>, B<icon_path>, B<urgency>.
Where B<DUNST_ICON_PATH> or B<icon_path> is the absolute path to the icon file
if there is one. B<DUNST_URGENCY> or B<urgency> is one of "LOW", "NORMAL" or
"CRITICAL". B<DUNST_URLS> is a newline-separated list of urls associated with
the notification.
Note that some variables may be empty.
Where icon is the absolute path to the icon file if there is one and urgency is
one of "LOW", "NORMAL" or "CRITICAL".
If the notification is suppressed, the script will not be run unless
B<always_run_scripts> is set to true.
@ -930,8 +795,6 @@ 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"
@ -941,46 +804,6 @@ dunst is able to get different colors for a message via notify-send.
In order to do that you have to add a hint via the -h option.
The progress value can be set with a hint, too.
B<All hints>
See RULES for more detailed explanations for some options.
=over 4
=item B<fgcolor>:
Foreground cololor
=item B<bgcolor>:
Background color
=item B<frcolor>:
Frame color
=item B<hlcolor>:
Highlight color
=item B<value>:
Progress value.
=item B<image-path>:
Icon name. This may be a path or just the icon name.
=item B<image-data>:
A stream of raw image data.
=item B<category>:
The category.
=item B<desktop_entry>:
The desktop entry.
=item B<transient>:
The transient value.
=back
B<Examples>
=over 4
=item notify-send -h string:fgcolor:#ff4444
@ -1023,8 +846,9 @@ Example time: "1000ms" "10m"
=head1 MISCELLANEOUS
Dunst can be paused via the `dunstctl set-paused true` command. To unpause dunst use
`dunstctl set-paused false`.
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".
Alternatively you can send SIGUSR1 and SIGUSR2 to pause and unpause
respectively. For Example:
@ -1043,27 +867,11 @@ missed notifications after returning to the computer.
=head1 FILES
These are the places where dunst will look for a configuration file. They are
listed here in order and if dunst finds one of them, it will stop looking for
more.
$XDG_CONFIG_HOME/dunst/dunstrc
$HOME/.config/dunst/dunstrc
-or-
$XDG_CONFIG_HOME/dunst/dunstrc
/etc/xdg/dunst/dunstrc
=over 4
=item /etc/dunst/dunstrc
This is where the default config file is located
=back
$HOME/.config/dunst/dunstrc
=head1 AUTHORS
@ -1081,4 +889,4 @@ If you feel that copyrights are violated, please send me an email.
=head1 SEE ALSO
dunst(1), dunstctl(1), dmenu(1), notify-send(1)
dwm(1), dmenu(1), twmn(1), notify-send(1)

View File

@ -1,64 +0,0 @@
=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<count> [displayed/history/waiting]
Returns the number of displayed, shown and waiting notifications. If no argument
is provided, everything will be printed.
=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

View File

@ -1,33 +0,0 @@
# Main repo
- [ ] Verify that the changelog is up to date
- [ ] Write release notes (Only if non-patch release)
- [ ] Verify that the working directory is clean and on the master branch
- [ ] Change the version in the Makefile to "x.x.x (iso-date)"
- [ ] Update changelog `Unreleased` entry to the new version
- [ ] Commit changes (Commit title: `Dunst vX.X.X`)
- [ ] Tag commit, make sure it's an annotated tag (git tag -a) (Tag title: Dunst vX.X.X)
- [ ] Push commits
- [ ] Push tags
# Dunst-project.org
- [ ] Update release number in the download page
- [ ] Update release date in the download page
- [ ] Update version number in the download link
- [ ] Copy release notes to the download page (Only if non-patch release)
- [ ] Copy changelog to the changelog page
- [ ] Copy documentation to the documentation page
- [ ] Verify that they look fine when rendered
- [ ] Commit changes
- [ ] Run deploy script
- [ ] Push to main website repo
- [ ] Push to gh-pages
# Main repo
- [ ] Copy release notes to githubs release feature
- [ ] Publish release on github
- [ ] Update maint branch to point to master
- [ ] Create new Unreleased section for the changelog
- [ ] Update Makefile version to -non-git
- [ ] Commit & push

View File

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

122
dunstctl
View File

@ -1,122 +0,0 @@
#!/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
count [displayed|history|waiting] Show the number of notifications
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
;;
"count")
[ $# -eq 1 ] || [ "${2}" = "displayed" ] || [ "${2}" = "history" ] || [ "${2}" = "waiting" ] \
|| die "Please give either 'displayed', 'history', 'waiting' or none as count parameter."
if [ $# -eq 1 ]; then
property_get waitingLength | ( read -r _ _ waiting; printf " Waiting: %s\n" "${waiting}" )
property_get displayedLength | ( read -r _ _ displayed; printf " Currently displayed: %s\n" "${displayed}" )
property_get historyLength | ( read -r _ _ history; printf " History: %s\n" "${history}")
else
property_get ${2}Length | ( read -r _ _ notifications; printf "%s\n" "${notifications}"; )
fi
;;
"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

View File

@ -127,11 +127,6 @@ void parse_commandline(int argc, char *argv[])
die(0);
}
if (*appname == '\0') {
g_printerr("Provided appname was empty\n");
die(1);
}
int n_args = count_args(argv, argc);
if (n_args < 2 && close_id < 1) {
g_printerr("I need at least a summary\n");
@ -239,7 +234,7 @@ void add_action(NotifyNotification *n, char *str)
char *label = strchr(str, ',');
if (!label || *(label+1) == '\0') {
g_printerr("Malformed action. Expected \"action,label\", got \"%s\"", str);
g_printerr("Malformed action. Excpected \"action,label\", got \"%s\"", str);
return;
}
@ -364,4 +359,4 @@ int main(int argc, char *argv[])
die(0);
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

91
dunstrc
View File

@ -31,23 +31,6 @@
# screen width minus the width defined in within the geometry option.
geometry = "300x5-30+20"
# Turn on the progess bar
progress_bar = true
# Set the progress bar height. This includes the frame, so make sure
# it's at least twice as big as the frame width.
progress_bar_height = 10
# Set the frame width of the progress bar
progress_bar_frame_width = 1
# Set the minimum width for the progress bar
progress_bar_min_width = 150
# Set the maximum width for the progress bar
progress_bar_max_width = 300
# Show how many messages are currently hidden (because of geometry).
indicate_hidden = yes
@ -76,9 +59,6 @@
# Horizontal padding.
horizontal_padding = 8
# Padding between text and icon.
text_icon_padding = 0
# Defines width in pixels of frame around the notification window.
# Set to 0 to disable.
frame_width = 3
@ -120,7 +100,7 @@
# <u>underline</u>
#
# For a complete reference see
# <https://developer.gnome.org/pango/stable/pango-Markup.html>.
# <http://developer.gnome.org/pango/stable/PangoMarkupFormat.html>.
#
# strip: This setting is provided for compatibility with some broken
# clients that send markup even though it's not enabled on the
@ -152,10 +132,6 @@
# 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.
@ -184,12 +160,7 @@
### Icons ###
# Align icons left/right/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
icon_position = off
# Scale larger icons down to this size, set to 0 to disable
max_icon_size = 32
@ -244,22 +215,6 @@
# 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
### Wayland ###
# These settings are Wayland-specific. They have no effect when using X11
# Uncomment this if you want to let notications appear under fullscreen
# applications (default: overlay)
# layer = top
# Set this to true to use X11 output on Wayland.
force_xwayland = false
### Legacy
# Use the Xinerama extension instead of RandR for multi-monitor support.
@ -274,21 +229,15 @@
### mouse
# Defines list of actions for each mouse event
# Defines action of mouse event
# Possible values are:
# * none: Don't do anything.
# * do_action: Invoke the action determined by the action_name rule. If there is no
# such action, open the context menu.
# * open_url: If the notification has exactly one url, open it. If there are multiple
# ones, open the context menu.
# * 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.
# * context: Open context menu for the notification.
# * context_all: Open context menu for 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, close_current
mouse_middle_click = do_action
mouse_right_click = close_all
# Experimental features that may or may not work correctly. Do not expect them
@ -301,10 +250,6 @@
# where there are multiple screens with very different dpi values.
per_monitor_dpi = false
# 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.
# Check the dunstctl manual page for more info.
[shortcuts]
# Shortcuts are specified as [modifier+][modifier+]...key
@ -312,21 +257,20 @@
# "mod3" and "mod4" (windows-key).
# Xev might be helpful to find names for keys.
# Close notification. Equivalent dunstctl command:
# dunstctl close
# close = ctrl+space
# Close notification.
close = ctrl+space
# Close all notifications. Equivalent dunstctl command:
# dunstctl close-all
# close_all = ctrl+shift+space
# Close all notifications.
close_all = ctrl+shift+space
# Redisplay last message(s). Equivalent dunstctl command:
# dunstctl history-pop
# history = ctrl+grave
# Redisplay last message(s).
# On the US keyboard layout "grave" is normally above TAB and left
# of "1". Make sure this key actually exists on your keyboard layout,
# e.g. check output of 'xmodmap -pke'
history = ctrl+grave
# Context menu. Equivalent dunstctl command:
# dunstctl context
# context = ctrl+shift+period
# Context menu.
context = ctrl+shift+period
[urgency_low]
# IMPORTANT: colors have to be defined in quotation marks.
@ -377,7 +321,6 @@
# set_transient
# timeout
# urgency
# action_name
#
# Shell-like globbing will get expanded.
#

2
main.c
View File

@ -4,4 +4,4 @@ int main(int argc, char *argv[])
{
return dunst_main(argc, argv);
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -8,7 +8,6 @@
#include "dunst.h"
#include "log.h"
#include "menu.h"
#include "notification.h"
#include "queues.h"
#include "settings.h"
@ -18,12 +17,6 @@
#define FDN_IFAC "org.freedesktop.Notifications"
#define FDN_NAME "org.freedesktop.Notifications"
#define DUNST_PATH "/org/freedesktop/Notifications"
#define DUNST_IFAC "org.dunstproject.cmd0"
#define DUNST_NAME "org.freedesktop.Notifications"
#define PROPERTIES_IFAC "org.freedesktop.DBus.Properties"
GDBusConnection *dbus_conn;
static GDBusNodeInfo *introspection_data = NULL;
@ -69,27 +62,7 @@ static const char *introspection_xml =
" <arg name=\"id\" type=\"u\"/>"
" <arg name=\"action_key\" type=\"s\"/>"
" </signal>"
" </interface>"
" <interface name=\""DUNST_IFAC"\">"
" <method name=\"ContextMenuCall\" />"
" <method name=\"NotificationAction\">"
" <arg name=\"number\" type=\"i\"/>"
" </method>"
" <method name=\"NotificationCloseLast\" />"
" <method name=\"NotificationCloseAll\" />"
" <method name=\"NotificationShow\" />"
" <method name=\"Ping\" />"
" <property name=\"paused\" type=\"b\" access=\"readwrite\">"
" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"true\"/>"
" </property>"
" <property name=\"displayedLength\" type=\"u\" access=\"read\" />"
" <property name=\"historyLength\" type=\"u\" access=\"read\" />"
" <property name=\"waitingLength\" type=\"u\" access=\"read\" />"
" </interface>"
" </interface>"
"</node>";
static const char *stack_tag_hints[] = {
@ -125,6 +98,7 @@ DBUS_METHOD(Notify);
DBUS_METHOD(CloseNotification);
DBUS_METHOD(GetCapabilities);
DBUS_METHOD(GetServerInformation);
static struct dbus_method methods_fdn[] = {
{"CloseNotification", dbus_cb_CloseNotification},
{"GetCapabilities", dbus_cb_GetCapabilities},
@ -132,7 +106,7 @@ static struct dbus_method methods_fdn[] = {
{"Notify", dbus_cb_Notify},
};
void dbus_cb_fdn_methods(GDBusConnection *connection,
void handle_method_call(GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
@ -141,12 +115,12 @@ void dbus_cb_fdn_methods(GDBusConnection *connection,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
struct dbus_method *m = bsearch(method_name,
methods_fdn,
G_N_ELEMENTS(methods_fdn),
sizeof(struct dbus_method),
cmp_methods);
struct dbus_method *m = bsearch(
method_name,
&methods_fdn,
G_N_ELEMENTS(methods_fdn),
sizeof(struct dbus_method),
cmp_methods);
if (m) {
m->method(connection, sender, parameters, invocation);
@ -157,143 +131,6 @@ void dbus_cb_fdn_methods(GDBusConnection *connection,
}
}
DBUS_METHOD(dunst_ContextMenuCall);
DBUS_METHOD(dunst_NotificationAction);
DBUS_METHOD(dunst_NotificationCloseAll);
DBUS_METHOD(dunst_NotificationCloseLast);
DBUS_METHOD(dunst_NotificationShow);
DBUS_METHOD(dunst_Ping);
static struct dbus_method methods_dunst[] = {
{"ContextMenuCall", dbus_cb_dunst_ContextMenuCall},
{"NotificationAction", dbus_cb_dunst_NotificationAction},
{"NotificationCloseAll", dbus_cb_dunst_NotificationCloseAll},
{"NotificationCloseLast", dbus_cb_dunst_NotificationCloseLast},
{"NotificationShow", dbus_cb_dunst_NotificationShow},
{"Ping", dbus_cb_dunst_Ping},
};
void dbus_cb_dunst_methods(GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
struct dbus_method *m = bsearch(method_name,
methods_dunst,
G_N_ELEMENTS(methods_dunst),
sizeof(struct dbus_method),
cmp_methods);
if (m) {
m->method(connection, sender, parameters, invocation);
} else {
LOG_M("Unknown method name: '%s' (sender: '%s').",
method_name,
sender);
}
}
static void dbus_cb_dunst_ContextMenuCall(GDBusConnection *connection,
const gchar *sender,
GVariant *parameters,
GDBusMethodInvocation *invocation)
{
LOG_D("CMD: Calling context menu");
context_menu();
g_dbus_method_invocation_return_value(invocation, NULL);
g_dbus_connection_flush(connection, NULL, NULL, NULL);
}
static void dbus_cb_dunst_NotificationAction(GDBusConnection *connection,
const gchar *sender,
GVariant *parameters,
GDBusMethodInvocation *invocation)
{
int notification_nr = 0;
g_variant_get(parameters, "(i)", &notification_nr);
LOG_D("CMD: Calling action for notification %d", notification_nr);
if (notification_nr < 0 || queues_length_waiting() < notification_nr) {
g_dbus_method_invocation_return_error(invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
"Couldn't activate action for notification in position %d, %d notifications currently open",
notification_nr, queues_length_waiting());
return;
}
struct notification *n = g_list_nth_data(queues_get_displayed(), notification_nr);
if (n) {
LOG_D("CMD: Calling action for notification %s", n->summary);
notification_do_action(n);
}
g_dbus_method_invocation_return_value(invocation, NULL);
g_dbus_connection_flush(connection, NULL, NULL, NULL);
}
static void dbus_cb_dunst_NotificationCloseAll(GDBusConnection *connection,
const gchar *sender,
GVariant *parameters,
GDBusMethodInvocation *invocation)
{
LOG_D("CMD: Pushing all to history");
queues_history_push_all();
wake_up();
g_dbus_method_invocation_return_value(invocation, NULL);
g_dbus_connection_flush(connection, NULL, NULL, NULL);
}
static void dbus_cb_dunst_NotificationCloseLast(GDBusConnection *connection,
const gchar *sender,
GVariant *parameters,
GDBusMethodInvocation *invocation)
{
LOG_D("CMD: Closing last notification");
const GList *list = queues_get_displayed();
if (list && list->data) {
struct notification *n = list->data;
queues_notification_close_id(n->id, REASON_USER);
wake_up();
}
g_dbus_method_invocation_return_value(invocation, NULL);
g_dbus_connection_flush(connection, NULL, NULL, NULL);
}
static void dbus_cb_dunst_NotificationShow(GDBusConnection *connection,
const gchar *sender,
GVariant *parameters,
GDBusMethodInvocation *invocation)
{
LOG_D("CMD: Showing last notification from history");
queues_history_pop();
wake_up();
g_dbus_method_invocation_return_value(invocation, NULL);
g_dbus_connection_flush(connection, NULL, NULL, NULL);
}
/* Just a simple Ping command to give the ability to dunstctl to test for the existence of this interface
* Any other way requires parsing the XML of the Introspection or other foo. Just calling the Ping on an old dunst version will fail. */
static void dbus_cb_dunst_Ping(GDBusConnection *connection,
const gchar *sender,
GVariant *parameters,
GDBusMethodInvocation *invocation)
{
g_dbus_method_invocation_return_value(invocation, NULL);
g_dbus_connection_flush(connection, NULL, NULL, NULL);
}
static void dbus_cb_GetCapabilities(
GDBusConnection *connection,
const gchar *sender,
@ -307,7 +144,6 @@ static void dbus_cb_GetCapabilities(
g_variant_builder_add(builder, "s", "actions");
g_variant_builder_add(builder, "s", "body");
g_variant_builder_add(builder, "s", "body-hyperlinks");
g_variant_builder_add(builder, "s", "icon-static");
for (int i = 0; i < sizeof(stack_tag_hints)/sizeof(*stack_tag_hints); ++i)
g_variant_builder_add(builder, "s", stack_tag_hints[i]);
@ -386,11 +222,6 @@ static struct notification *dbus_message_to_notification(const gchar *sender, GV
g_variant_unref(dict_value);
}
if ((dict_value = g_variant_lookup_value(hints, "hlcolor", G_VARIANT_TYPE_STRING))) {
n->colors.highlight = g_variant_dup_string(dict_value, NULL);
g_variant_unref(dict_value);
}
if ((dict_value = g_variant_lookup_value(hints, "category", G_VARIANT_TYPE_STRING))) {
n->category = g_variant_dup_string(dict_value, NULL);
g_variant_unref(dict_value);
@ -455,7 +286,7 @@ static struct notification *dbus_message_to_notification(const gchar *sender, GV
}
if (timeout >= 0)
n->timeout = ((gint64)timeout) * 1000;
n->timeout = timeout * 1000;
g_variant_unref(hints);
g_variant_type_free(required_type);
@ -504,17 +335,7 @@ static void dbus_cb_CloseNotification(
{
guint32 id;
g_variant_get(parameters, "(u)", &id);
if (settings.ignore_dbusclose) {
LOG_D("Ignoring CloseNotification message");
// Stay commpliant by lying to the sender, telling him we closed the notification
if (id > 0) {
struct notification *n = queues_get_by_id(id);
if (n)
signal_notification_closed(n, REASON_SIG);
}
} else {
queues_notification_close_id(id, REASON_SIG);
}
queues_notification_close_id(id, REASON_SIG);
wake_up();
g_dbus_method_invocation_return_value(invocation, NULL);
g_dbus_connection_flush(connection, NULL, NULL, NULL);
@ -526,15 +347,19 @@ static void dbus_cb_GetServerInformation(
GVariant *parameters,
GDBusMethodInvocation *invocation)
{
GVariant *answer = g_variant_new("(ssss)", "dunst", "knopwob", VERSION, "1.2");
GVariant *value;
value = g_variant_new("(ssss)", "dunst", "knopwob", VERSION, "1.2");
g_dbus_method_invocation_return_value(invocation, value);
g_dbus_method_invocation_return_value(invocation, answer);
g_dbus_connection_flush(connection, NULL, NULL, NULL);
}
void signal_notification_closed(struct notification *n, enum reason reason)
{
if (!n->dbus_valid) {
LOG_W("Closing notification '%s' not supported. "
"Notification already closed.", n->summary);
return;
}
@ -559,34 +384,11 @@ void signal_notification_closed(struct notification *n, enum reason reason)
body,
&err);
notification_invalidate_actions(n);
n->dbus_valid = false;
if (err) {
LOG_W("Unable to close notification: %s", err->message);
g_error_free(err);
} else {
char* reason_string;
switch (reason) {
case REASON_TIME:
reason_string="time";
break;
case REASON_USER:
reason_string="user";
break;
case REASON_SIG:
reason_string="signal";
break;
case REASON_UNDEF:
reason_string="undfined";
break;
default:
reason_string="unknown";
}
LOG_D("Queues: Closing notification for reason: %s", reason_string);
}
}
@ -616,106 +418,28 @@ void signal_action_invoked(const struct notification *n, const char *identifier)
}
}
GVariant *dbus_cb_dunst_Properties_Get(GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *property_name,
GError **error,
gpointer user_data)
{
struct dunst_status status = dunst_status_get();
if (STR_EQ(property_name, "paused")) {
return g_variant_new_boolean(!status.running);
} else if (STR_EQ(property_name, "displayedLength")) {
unsigned int displayed = queues_length_displayed();
return g_variant_new_uint32(displayed);
} else if (STR_EQ(property_name, "historyLength")) {
unsigned int history = queues_length_history();
return g_variant_new_uint32(history);
} else if (STR_EQ(property_name, "waitingLength")) {
unsigned int waiting = queues_length_waiting();
return g_variant_new_uint32(waiting);
} else {
LOG_W("Unknown property!\n");
*error = g_error_new(G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
return NULL;
}
}
gboolean dbus_cb_dunst_Properties_Set(GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *property_name,
GVariant *value,
GError **error,
gpointer user_data)
{
if (STR_EQ(property_name, "paused")) {
dunst_status(S_RUNNING, !g_variant_get_boolean(value));
wake_up();
GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
GVariantBuilder *invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
g_variant_builder_add(builder,
"{sv}",
"paused", g_variant_new_boolean(g_variant_get_boolean(value)));
g_dbus_connection_emit_signal(connection,
NULL,
object_path,
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
g_variant_new("(sa{sv}as)",
interface_name,
builder,
invalidated_builder),
NULL);
return true;
}
*error = g_error_new(G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
return false;
}
static const GDBusInterfaceVTable interface_vtable_fdn = {
dbus_cb_fdn_methods
};
static const GDBusInterfaceVTable interface_vtable_dunst = {
dbus_cb_dunst_methods,
dbus_cb_dunst_Properties_Get,
dbus_cb_dunst_Properties_Set,
static const GDBusInterfaceVTable interface_vtable = {
handle_method_call
};
static void dbus_cb_bus_acquired(GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
GError *err = NULL;
if(!g_dbus_connection_register_object(
connection,
FDN_PATH,
introspection_data->interfaces[0],
&interface_vtable_fdn,
NULL,
NULL,
&err)) {
DIE("Unable to register dbus connection interface '%s': %s", introspection_data->interfaces[0]->name, err->message);
}
guint registration_id;
if(!g_dbus_connection_register_object(
connection,
FDN_PATH,
introspection_data->interfaces[1],
&interface_vtable_dunst,
NULL,
NULL,
&err)) {
DIE("Unable to register dbus connection interface '%s': %s", introspection_data->interfaces[1]->name, err->message);
GError *err = NULL;
registration_id = g_dbus_connection_register_object(connection,
FDN_PATH,
introspection_data->interfaces[0],
&interface_vtable,
NULL,
NULL,
&err);
if (registration_id == 0) {
DIE("Unable to register dbus connection: %s", err->message);
}
}
@ -723,9 +447,7 @@ static void dbus_cb_name_acquired(GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
// If we're not able to get org.fd.N bus, we've still got a problem
if (STR_EQ(name, FDN_NAME))
dbus_conn = connection;
dbus_conn = connection;
}
/**
@ -887,4 +609,4 @@ void dbus_teardown(int owner_id)
g_bus_unown_name(owner_id);
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -3,7 +3,6 @@
#ifndef DUNST_DBUS_H
#define DUNST_DBUS_H
#include "dunst.h"
#include "notification.h"
/// The reasons according to the notification spec
@ -22,4 +21,4 @@ void signal_notification_closed(struct notification *n, enum reason reason);
void signal_action_invoked(const struct notification *n, const char *identifier);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -1,6 +1,7 @@
#include "draw.h"
#include <assert.h>
#include <cairo.h>
#include <math.h>
#include <pango/pango-attributes.h>
#include <pango/pangocairo.h>
@ -8,8 +9,6 @@
#include <pango/pango-layout.h>
#include <pango/pango-types.h>
#include <stdlib.h>
#include <inttypes.h>
#include <glib.h>
#include "dunst.h"
#include "icon.h"
@ -17,21 +16,12 @@
#include "markup.h"
#include "notification.h"
#include "queues.h"
#include "output.h"
#include "settings.h"
struct color {
double r;
double g;
double b;
double a;
};
#include "x11/x.h"
struct colored_layout {
PangoLayout *l;
struct color fg;
struct color bg;
struct color highlight;
struct color frame;
char *text;
PangoAttrList *attr;
@ -39,33 +29,24 @@ struct colored_layout {
const struct notification *n;
};
const struct output *output;
window win;
struct window_x11 *win;
PangoFontDescription *pango_fdesc;
#define UINT_MAX_N(bits) ((1 << bits) - 1)
void draw_setup(void)
{
const struct output *out = output_create(settings.force_xwayland);
output = out;
win = out->win_create();
x_setup();
win = x_win_create();
pango_fdesc = pango_font_description_from_string(settings.font);
}
static struct color hex_to_color(uint32_t hexValue, int dpc)
static struct color hex_to_color(int hexValue)
{
const int bpc = 4 * dpc;
const unsigned single_max = UINT_MAX_N(bpc);
struct color ret;
ret.r = ((hexValue >> 3 * bpc) & single_max) / (double)single_max;
ret.g = ((hexValue >> 2 * bpc) & single_max) / (double)single_max;
ret.b = ((hexValue >> 1 * bpc) & single_max) / (double)single_max;
ret.a = ((hexValue) & single_max) / (double)single_max;
ret.r = ((hexValue >> 16) & 0xFF) / 255.0;
ret.g = ((hexValue >> 8) & 0xFF) / 255.0;
ret.b = ((hexValue) & 0xFF) / 255.0;
return ret;
}
@ -73,24 +54,15 @@ static struct color hex_to_color(uint32_t hexValue, int dpc)
static struct color string_to_color(const char *str)
{
char *end;
uint_fast32_t val = strtoul(str+1, &end, 16);
if (end[0] != '\0' && end[1] != '\0') {
long int val = strtol(str+1, &end, 16);
if (*end != '\0' && *(end+1) != '\0') {
LOG_W("Invalid color string: '%s'", str);
}
switch (end - (str+1)) {
case 3: return hex_to_color((val << 4) | 0xF, 1);
case 6: return hex_to_color((val << 8) | 0xFF, 2);
case 4: return hex_to_color(val, 1);
case 8: return hex_to_color(val, 2);
}
/* return black on error */
LOG_W("Invalid color string: '%s'", str);
return hex_to_color(0xF, 1);
return hex_to_color(val);
}
static inline double color_apply_delta(double base, double delta)
static double color_apply_delta(double base, double delta)
{
base += delta;
if (base > 1)
@ -141,11 +113,10 @@ static struct color layout_get_sepcolor(struct colored_layout *cl,
static void layout_setup_pango(PangoLayout *layout, int width)
{
int scale = output->get_scale();
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_width(layout, width * scale * PANGO_SCALE);
pango_layout_set_width(layout, width * PANGO_SCALE);
pango_layout_set_font_description(layout, pango_fdesc);
pango_layout_set_spacing(layout, settings.line_height * scale * PANGO_SCALE);
pango_layout_set_spacing(layout, settings.line_height * PANGO_SCALE);
PangoAlignment align;
switch (settings.align) {
@ -179,36 +150,11 @@ static bool have_dynamic_width(void)
return (settings.geometry.width_set && settings.geometry.w == 0);
}
static int get_text_icon_padding()
{
if (settings.text_icon_padding) {
return settings.text_icon_padding;
} else {
return settings.h_padding;
}
}
static bool have_progress_bar(const struct notification *n)
{
return (n->progress >= 0 && settings.progress_bar == true);
}
static void get_text_size(PangoLayout *l, int *w, int *h, int scale) {
pango_layout_get_pixel_size(l, w, h);
// scale the size down, because it may be rendered at higher DPI
if (w)
*w /= scale;
if (h)
*h /= scale;
}
static struct dimensions calculate_dimensions(GSList *layouts)
{
struct dimensions dim = { 0 };
int scale = output->get_scale();
const struct screen_info *scr = output->get_active_screen();
struct screen_info *scr = get_active_screen();
if (have_dynamic_width()) {
/* dynamic width */
dim.w = 0;
@ -233,10 +179,10 @@ static struct dimensions calculate_dimensions(GSList *layouts)
for (GSList *iter = layouts; iter; iter = iter->next) {
struct colored_layout *cl = iter->data;
int w=0,h=0;
get_text_size(cl->l, &w, &h, scale);
pango_layout_get_pixel_size(cl->l, &w, &h);
if (cl->icon) {
h = MAX(get_icon_height(cl->icon, scale), h);
w += get_icon_width(cl->icon, scale) + settings.h_padding;
h = MAX(cairo_image_surface_get_height(cl->icon), h);
w += cairo_image_surface_get_width(cl->icon) + settings.h_padding;
}
h = MAX(settings.notification_height, h + settings.padding * 2);
dim.h += h;
@ -261,27 +207,20 @@ static struct dimensions calculate_dimensions(GSList *layouts)
w = dim.w;
w -= 2 * settings.h_padding;
w -= 2 * settings.frame_width;
if (cl->icon) {
w -= get_icon_width(cl->icon, scale) + get_text_icon_padding();
}
if (cl->icon) w -= cairo_image_surface_get_width(cl->icon) + settings.h_padding;
layout_setup_pango(cl->l, w);
/* re-read information */
get_text_size(cl->l, &w, &h, scale);
pango_layout_get_pixel_size(cl->l, &w, &h);
if (cl->icon) {
h = MAX(get_icon_height(cl->icon, scale), h);
w += get_icon_width(cl->icon, scale) + settings.h_padding;
h = MAX(cairo_image_surface_get_height(cl->icon), h);
w += cairo_image_surface_get_width(cl->icon) + settings.h_padding;
}
h = MAX(settings.notification_height, h + settings.padding * 2);
dim.h += h;
text_width = MAX(w, text_width);
}
if (have_progress_bar(cl->n)){
dim.h += settings.progress_bar_height + settings.padding;
dim.w = MAX(dim.w, settings.progress_bar_min_width);
}
dim.corner_radius = MIN(dim.corner_radius, h/2);
}
@ -295,10 +234,10 @@ static struct dimensions calculate_dimensions(GSList *layouts)
static PangoLayout *layout_create(cairo_t *c)
{
const struct screen_info *screen = output->get_active_screen();
struct screen_info *screen = get_active_screen();
PangoContext *context = pango_cairo_create_context(c);
pango_cairo_context_set_resolution(context, screen->dpi);
pango_cairo_context_set_resolution(context, screen_dpi_get(screen));
PangoLayout *layout = pango_layout_new(context);
@ -311,7 +250,6 @@ static struct colored_layout *layout_init_shared(cairo_t *c, const struct notifi
{
struct colored_layout *cl = g_malloc(sizeof(struct colored_layout));
cl->l = layout_create(c);
int scale = output->get_scale();
if (!settings.word_wrap) {
PangoEllipsizeMode ellipsize;
@ -345,7 +283,6 @@ static struct colored_layout *layout_init_shared(cairo_t *c, const struct notifi
cl->fg = string_to_color(n->colors.fg);
cl->bg = string_to_color(n->colors.bg);
cl->highlight = string_to_color(n->colors.highlight);
cl->frame = string_to_color(n->colors.frame);
cl->n = n;
@ -358,9 +295,7 @@ static struct colored_layout *layout_init_shared(cairo_t *c, const struct notifi
} else {
width -= 2 * settings.h_padding;
width -= 2 * settings.frame_width;
if (cl->icon) {
width -= get_icon_width(cl->icon, scale) + get_text_icon_padding();
}
if (cl->icon) width -= cairo_image_surface_get_width(cl->icon) + settings.h_padding;
layout_setup_pango(cl->l, width);
}
@ -380,7 +315,6 @@ static struct colored_layout *layout_from_notification(cairo_t *c, struct notifi
{
struct colored_layout *cl = layout_init_shared(c, n);
int scale = output->get_scale();
/* markup */
GError *err = NULL;
@ -402,15 +336,9 @@ static struct colored_layout *layout_from_notification(cairo_t *c, struct notifi
}
get_text_size(cl->l, NULL, &(n->displayed_height), scale);
if (cl->icon) n->displayed_height = MAX(get_icon_height(cl->icon, scale), n->displayed_height);
n->displayed_height = n->displayed_height + settings.padding * 2;
// progress bar
if (have_progress_bar(n)) n->displayed_height += settings.progress_bar_height + settings.padding;
n->displayed_height = MAX(settings.notification_height, n->displayed_height);
pango_layout_get_pixel_size(cl->l, NULL, &(n->displayed_height));
if (cl->icon) n->displayed_height = MAX(cairo_image_surface_get_height(cl->icon), n->displayed_height);
n->displayed_height = MAX(settings.notification_height, n->displayed_height + settings.padding * 2);
n->first_render = false;
return cl;
@ -449,46 +377,15 @@ static GSList *create_layouts(cairo_t *c)
}
static int layout_get_height(struct colored_layout *cl, int scale)
static int layout_get_height(struct colored_layout *cl)
{
int h;
int h_icon = 0;
int h_progress_bar = 0;
get_text_size(cl->l, NULL, &h, scale);
pango_layout_get_pixel_size(cl->l, NULL, &h);
if (cl->icon)
h_icon = get_icon_height(cl->icon, scale);
if (have_progress_bar(cl->n)){
h_progress_bar = settings.progress_bar_height + settings.padding;
}
h_icon = cairo_image_surface_get_height(cl->icon);
int res = MAX(h, h_icon) + h_progress_bar;
return res;
}
/* Attempt to make internal radius more organic.
* Simple r-w is not enough for too small r/w ratio.
* simplifications: r/2 == r - w + w*w / (r * 2) with (w == r)
* r, w - corner radius & frame width,
* h - box height
*/
static int frame_internal_radius (int r, int w, int h)
{
if (r == 0 || h + (w - r) * 2 == 0)
return 0;
// Integer precision scaler, using 1/4 of int size
const int s = 2 << (8 * sizeof(int) / 4);
int r1, r2, ret;
h *= s;
r *= s;
w *= s;
r1 = r - w + w * w / (r * 2); // w < r
r2 = r * h / (h + (w - r) * 2); // w >= r
ret = (r > w) ? r1 : (r / 2 < r2) ? r / 2 : r2;
return ret / s;
return MAX(h, h_icon);
}
/**
@ -496,14 +393,8 @@ static int frame_internal_radius (int r, int w, int h)
* The top corners will get rounded by `corner_radius`, if `first` is set.
* Respectably the same for `last` with the bottom corners.
*/
void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, int scale, bool first, bool last)
static void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, bool first, bool last)
{
width *= scale;
height *= scale;
x *= scale;
y *= scale;
corner_radius *= scale;
const float degrees = M_PI / 180.0;
cairo_new_sub_path(c);
@ -551,13 +442,6 @@ void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corn
cairo_close_path(c);
}
/**
* A small wrapper around cairo_rectange for drawing a scaled rectangle.
*/
void draw_rect(cairo_t *c, int x, int y, int width, int height, int scale) {
cairo_rectangle(c, x * scale, y * scale, width * scale, height * scale);
}
static cairo_surface_t *render_background(cairo_surface_t *srf,
struct colored_layout *cl,
struct colored_layout *cl_next,
@ -567,20 +451,12 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
int corner_radius,
bool first,
bool last,
int *ret_width,
int scale)
int *ret_width)
{
int x = 0;
int radius_int = corner_radius;
cairo_t *c = cairo_create(srf);
/* stroke area doesn't intersect with main area */
cairo_set_fill_rule(c, CAIRO_FILL_RULE_EVEN_ODD);
/* for correct combination of adjacent areas */
cairo_set_operator(c, CAIRO_OPERATOR_ADD);
if (first)
height += settings.frame_width;
if (last)
@ -588,7 +464,9 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
else
height += settings.separator_height;
draw_rounded_rect(c, x, y, width, height, corner_radius, scale, first, last);
cairo_set_source_rgb(c, cl->frame.r, cl->frame.g, cl->frame.b);
draw_rounded_rect(c, x, y, width, height, corner_radius, first, last);
cairo_fill(c);
/* adding frame */
x += settings.frame_width;
@ -604,25 +482,17 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
else
height -= settings.separator_height;
radius_int = frame_internal_radius(corner_radius, settings.frame_width, height);
draw_rounded_rect(c, x, y, width, height, radius_int, scale, first, last);
cairo_set_source_rgba(c, cl->frame.r, cl->frame.g, cl->frame.b, cl->frame.a);
cairo_set_source_rgb(c, cl->bg.r, cl->bg.g, cl->bg.b);
draw_rounded_rect(c, x, y, width, height, corner_radius, first, last);
cairo_fill(c);
draw_rounded_rect(c, x, y, width, height, radius_int, scale, first, last);
cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a);
cairo_fill(c);
cairo_set_operator(c, CAIRO_OPERATOR_SOURCE);
if ( settings.sep_color.type != SEP_FRAME
&& settings.separator_height > 0
&& !last) {
struct color sep_color = layout_get_sepcolor(cl, cl_next);
cairo_set_source_rgba(c, sep_color.r, sep_color.g, sep_color.b, sep_color.a);
cairo_set_source_rgb(c, sep_color.r, sep_color.g, sep_color.b);
draw_rect(c, settings.frame_width, y + height, width, settings.separator_height, scale);
cairo_rectangle(c, settings.frame_width, y + height, width, settings.separator_height);
cairo_fill(c);
}
@ -632,104 +502,48 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
if (ret_width)
*ret_width = width;
return cairo_surface_create_for_rectangle(srf, x * scale, y * scale, width * scale, height * scale);
return cairo_surface_create_for_rectangle(srf, x, y, width, height);
}
static void render_content(cairo_t *c, struct colored_layout *cl, int width, int scale)
static void render_content(cairo_t *c, struct colored_layout *cl, int width)
{
const int h = layout_get_height(cl, scale);
int h_without_progress_bar = h;
if (have_progress_bar(cl->n)){
h_without_progress_bar -= settings.progress_bar_height + settings.padding;
}
const int h = layout_get_height(cl);
int h_text;
get_text_size(cl->l, NULL, &h_text, scale);
pango_layout_get_pixel_size(cl->l, NULL, &h_text);
int text_x = settings.h_padding,
text_y = settings.padding + h_without_progress_bar / 2 - h_text / 2;
// text positioning
if (cl->icon) {
// vertical alignment
if (settings.vertical_alignment == VERTICAL_TOP) {
text_y = settings.padding;
} else if (settings.vertical_alignment == VERTICAL_BOTTOM) {
text_y = h_without_progress_bar + settings.padding - h_text;
if (text_y < 0)
text_y = settings.padding;
} // else VERTICAL_CENTER
// icon position
if (settings.icon_position == ICON_LEFT) {
text_x = get_icon_width(cl->icon, scale) + settings.h_padding + get_text_icon_padding();
} // else ICON_RIGHT
if (cl->icon && settings.icon_position == ICON_LEFT) {
cairo_move_to(c, cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding,
settings.padding + h/2 - h_text/2);
} else if (cl->icon && settings.icon_position == ICON_RIGHT) {
cairo_move_to(c, settings.h_padding, settings.padding + h/2 - h_text/2);
} else {
cairo_move_to(c, settings.h_padding, settings.padding);
}
cairo_move_to(c, text_x * scale, text_y * scale);
cairo_set_source_rgba(c, cl->fg.r, cl->fg.g, cl->fg.b, cl->fg.a);
cairo_set_source_rgb(c, cl->fg.r, cl->fg.g, cl->fg.b);
pango_cairo_update_layout(c, cl->l);
pango_cairo_show_layout(c, cl->l);
// icon positioning
if (cl->icon) {
unsigned int image_width = get_icon_width(cl->icon, scale),
image_height = get_icon_height(cl->icon, scale),
image_x = width - settings.h_padding - image_width,
image_y = settings.padding + h_without_progress_bar/2 - image_height/2;
unsigned int image_width = cairo_image_surface_get_width(cl->icon),
image_height = cairo_image_surface_get_height(cl->icon),
image_x,
image_y = settings.padding + h/2 - image_height/2;
// vertical alignment
if (settings.vertical_alignment == VERTICAL_TOP) {
image_y = settings.padding;
} else if (settings.vertical_alignment == VERTICAL_BOTTOM) {
image_y = h_without_progress_bar + settings.padding - image_height;
if (image_y < settings.padding || image_y > h_without_progress_bar)
image_y = settings.padding;
} // else VERTICAL_CENTER
// icon position
if (settings.icon_position == ICON_LEFT) {
image_x = settings.h_padding;
} // else ICON_RIGHT
} else if (settings.icon_position == ICON_RIGHT){
image_x = width - settings.h_padding - image_width;
} else {
LOG_E("Tried to draw icon but icon position is not valid. %s:%d", __FILE__, __LINE__);
}
cairo_set_source_surface(c, cl->icon, image_x * scale, image_y * scale);
draw_rect(c, image_x, image_y, image_width, image_height, scale);
cairo_set_source_surface(c, cl->icon, image_x, image_y);
cairo_rectangle(c, image_x, image_y, image_width, image_height);
cairo_fill(c);
}
// progress bar positioning
if (have_progress_bar(cl->n)){
int progress = MIN(cl->n->progress, 100);
unsigned int frame_width = settings.progress_bar_frame_width,
progress_width = MIN(width - 2 * settings.h_padding, settings.progress_bar_max_width),
progress_height = settings.progress_bar_height - frame_width,
frame_x = settings.h_padding,
frame_y = settings.padding + h - settings.progress_bar_height,
progress_width_without_frame = progress_width - 2 * frame_width,
progress_width_1 = progress_width_without_frame * progress / 100,
progress_width_2 = progress_width_without_frame - progress_width_1,
x_bar_1 = frame_x + frame_width,
x_bar_2 = x_bar_1 + progress_width_1;
double half_frame_width = frame_width / 2.0;
// draw progress bar
// Note: the bar could be drawn a bit smaller, because the frame is drawn on top
// left side
cairo_set_source_rgba(c, cl->highlight.r, cl->highlight.g, cl->highlight.b, cl->highlight.a);
draw_rect(c, x_bar_1, frame_y, progress_width_1, progress_height, scale);
cairo_fill(c);
// right side
cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a);
draw_rect(c, x_bar_2, frame_y, progress_width_2, progress_height, scale);
cairo_fill(c);
// border
cairo_set_source_rgba(c, cl->frame.r, cl->frame.g, cl->frame.b, cl->frame.a);
// TODO draw_rect instead of cairo_rectangle resulted in blurry lines. Why?
cairo_rectangle(c, (frame_x + half_frame_width) * scale, (frame_y + half_frame_width) * scale, (progress_width - frame_width) * scale, progress_height * scale);
cairo_set_line_width(c, frame_width * scale);
cairo_stroke(c);
}
}
static struct dimensions layout_render(cairo_surface_t *srf,
@ -739,19 +553,18 @@ static struct dimensions layout_render(cairo_surface_t *srf,
bool first,
bool last)
{
int scale = output->get_scale();
const int cl_h = layout_get_height(cl, scale);
const int cl_h = layout_get_height(cl);
int h_text = 0;
get_text_size(cl->l, NULL, &h_text, scale);
pango_layout_get_pixel_size(cl->l, NULL, &h_text);
int bg_width = 0;
int bg_height = MAX(settings.notification_height, (2 * settings.padding) + cl_h);
cairo_surface_t *content = render_background(srf, cl, cl_next, dim.y, dim.w, bg_height, dim.corner_radius, first, last, &bg_width, scale);
cairo_surface_t *content = render_background(srf, cl, cl_next, dim.y, dim.w, bg_height, dim.corner_radius, first, last, &bg_width);
cairo_t *c = cairo_create(content);
render_content(c, cl, bg_width, scale);
render_content(c, cl, bg_width);
/* adding frame */
if (first)
@ -777,7 +590,7 @@ static struct dimensions layout_render(cairo_surface_t *srf,
*/
static void calc_window_pos(int width, int height, int *ret_x, int *ret_y)
{
const struct screen_info *scr = output->get_active_screen();
struct screen_info *scr = get_active_screen();
if (ret_x) {
if (settings.geometry.negative_x) {
@ -800,12 +613,11 @@ void draw(void)
{
assert(queues_length_displayed() > 0);
GSList *layouts = create_layouts(output->win_get_context(win));
GSList *layouts = create_layouts(x_win_get_context(win));
struct dimensions dim = calculate_dimensions(layouts);
int scale = output->get_scale();
cairo_surface_t *image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dim.w * scale, dim.h * scale);
cairo_surface_t *image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dim.w, dim.h);
bool first = true;
for (GSList *iter = layouts; iter; iter = iter->next) {
@ -819,7 +631,7 @@ void draw(void)
}
calc_window_pos(dim.w, dim.h, &dim.x, &dim.y);
output->display_surface(image_surface, win, &dim);
x_display_surface(image_surface, win, &dim);
cairo_surface_destroy(image_surface);
g_slist_free_full(layouts, free_colored_layout);
@ -827,17 +639,7 @@ void draw(void)
void draw_deinit(void)
{
output->win_destroy(win);
output->deinit();
x_win_destroy(win);
x_free();
}
int draw_get_scale(void)
{
if (output) {
return output->get_scale();
} else {
LOG_W("Called draw_get_scale before output init");
return 1;
}
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -1,24 +1,14 @@
#ifndef DUNST_DRAW_H
#define DUNST_DRAW_H
#include <stdbool.h>
#include <cairo.h>
#include "output.h"
extern window win; // Temporary
extern const struct output *output;
#include "x11/x.h"
extern struct window_x11 *win; // Temporary
void draw_setup(void);
void draw(void);
void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, int scale, bool first, bool last);
// TODO get rid of this function by passing scale to everything that needs it.
int draw_get_scale(void);
void draw_deinit(void);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -9,6 +9,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include "dbus.h"
#include "draw.h"
@ -19,12 +20,12 @@
#include "queues.h"
#include "settings.h"
#include "utils.h"
#include "output.h"
#include "x11/screen.h"
#include "x11/x.h"
GMainLoop *mainloop = NULL;
static struct dunst_status status;
static bool setup_done = false;
/* see dunst.h */
void dunst_status(const enum dunst_status_field field,
@ -57,15 +58,6 @@ static gboolean run(void *data);
void wake_up(void)
{
// If wake_up is being called before the output has been setup we should
// return.
if (!setup_done)
{
LOG_D("Ignoring wake up");
return;
}
LOG_D("Waking up");
run(NULL);
}
@ -75,8 +67,8 @@ static gboolean run(void *data)
LOG_D("RUN");
dunst_status(S_FULLSCREEN, output->have_fullscreen_window());
dunst_status(S_IDLE, output->is_idle());
dunst_status(S_FULLSCREEN, have_fullscreen_window());
dunst_status(S_IDLE, x_is_idle());
queues_update(status);
@ -85,9 +77,9 @@ static gboolean run(void *data)
if (active) {
// Call draw before showing the window to avoid flickering
draw();
output->win_show(win);
x_win_show(win);
} else {
output->win_hide(win);
x_win_hide(win);
}
if (active) {
@ -95,8 +87,6 @@ static gboolean run(void *data)
gint64 sleep = queues_get_next_datachange(now);
gint64 timeout_at = now + sleep;
LOG_D("Sleeping for %li ms", sleep/1000);
if (sleep >= 0) {
if (next_timeout < now || timeout_at < next_timeout) {
g_timeout_add(sleep/1000, run, NULL);
@ -206,7 +196,6 @@ int dunst_main(int argc, char *argv[])
// we do not call wakeup now, wake_up does not work here yet
}
setup_done = true;
run(NULL);
g_main_loop_run(mainloop);
g_clear_pointer(&mainloop, g_main_loop_unref);
@ -240,4 +229,4 @@ void print_version(void)
exit(EXIT_SUCCESS);
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -41,4 +41,4 @@ void usage(int exit_status);
void print_version(void);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -86,14 +86,6 @@ static void pixbuf_data_to_cairo_data(
}
}
int get_icon_width(cairo_surface_t *icon, int scale) {
return cairo_image_surface_get_width(icon) / scale;
}
int get_icon_height(cairo_surface_t *icon, int scale) {
return cairo_image_surface_get_height(icon) / scale;
}
cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf)
{
assert(pixbuf);
@ -118,60 +110,25 @@ cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf)
return icon_surface;
}
/**
* Scales the given image dimensions if necessary according to the settings.
*
* @param w a pointer to the image width, to be modified in-place
* @param h a pointer to the image height, to be modified in-place
* @return TRUE if the dimensions were updated, FALSE if they were left unchanged
*/
static bool icon_size_clamp(int *w, int *h) {
int _w = *w, _h = *h;
int landscape = _w > _h;
int orig_larger = landscape ? _w : _h;
double larger = orig_larger;
double smaller = landscape ? _h : _w;
if (settings.min_icon_size && smaller < settings.min_icon_size) {
larger = larger / smaller * settings.min_icon_size;
smaller = settings.min_icon_size;
}
if (settings.max_icon_size && larger > settings.max_icon_size) {
smaller = smaller / larger * settings.max_icon_size;
larger = settings.max_icon_size;
}
if ((int) larger != orig_larger) {
*w = (int) (landscape ? larger : smaller);
*h = (int) (landscape ? smaller : larger);
return TRUE;
}
return FALSE;
}
/**
* Scales the given GdkPixbuf if necessary according to the settings.
*
* @param pixbuf (nullable) The pixbuf, which may be too big.
* Takes ownership of the reference.
* @param dpi_scale An integer for the dpi scaling. That doesn't mean the icon
* is always scaled by dpi_scale.
* @return the scaled version of the pixbuf. If scaling wasn't
* necessary, it returns the same pixbuf. Transfers full
* ownership of the reference.
*/
static GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf, int dpi_scale)
GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf)
{
ASSERT_OR_RET(pixbuf, NULL);
int w = gdk_pixbuf_get_width(pixbuf);
int h = gdk_pixbuf_get_height(pixbuf);
int larger = w > h ? w : h;
if (settings.max_icon_size && larger > settings.max_icon_size) {
int scaled_w = settings.max_icon_size;
int scaled_h = settings.max_icon_size;
if (w >= h)
scaled_h = (settings.max_icon_size * h) / w;
else
scaled_w = (settings.max_icon_size * w) / h;
// TODO immediately rescale icon upon scale changes
if (icon_size_clamp(&w, &h)) {
GdkPixbuf *scaled = gdk_pixbuf_scale_simple(
pixbuf,
w * dpi_scale,
h * dpi_scale,
scaled_w,
scaled_h,
GDK_INTERP_BILINEAR);
g_object_unref(pixbuf);
pixbuf = scaled;
@ -180,24 +137,12 @@ static GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf, int dpi_scale)
return pixbuf;
}
GdkPixbuf *get_pixbuf_from_file(const char *filename, int scale)
GdkPixbuf *get_pixbuf_from_file(const char *filename)
{
char *path = string_to_path(g_strdup(filename));
GError *error = NULL;
gint w, h;
if (!gdk_pixbuf_get_file_info (path, &w, &h)) {
LOG_W("Failed to load image info for %s", filename);
g_free(path);
return NULL;
}
// TODO immediately rescale icon upon scale changes
icon_size_clamp(&w, &h);
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_scale(path,
w * scale,
h * scale,
TRUE,
&error);
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &error);
if (error) {
LOG_W("%s", error->message);
@ -208,14 +153,14 @@ GdkPixbuf *get_pixbuf_from_file(const char *filename, int scale)
return pixbuf;
}
char *get_path_from_icon_name(const char *iconname)
GdkPixbuf *get_pixbuf_from_icon(const char *iconname)
{
if (STR_EMPTY(iconname))
return NULL;
const char *suffixes[] = { ".svg", ".svgz", ".png", ".xpm", NULL };
const char *suffixes[] = { ".svg", ".png", ".xpm", NULL };
GdkPixbuf *pixbuf = NULL;
gchar *uri_path = NULL;
char *new_name = NULL;
if (g_str_has_prefix(iconname, "file://")) {
uri_path = g_filename_from_uri(iconname, NULL, NULL);
@ -225,7 +170,7 @@ char *get_path_from_icon_name(const char *iconname)
/* absolute path? */
if (iconname[0] == '/' || iconname[0] == '~') {
new_name = g_strdup(iconname);
pixbuf = get_pixbuf_from_file(iconname);
} else {
/* search in icon_path */
char *start = settings.icon_path,
@ -237,62 +182,41 @@ char *get_path_from_icon_name(const char *iconname)
current_folder = g_strndup(start, end - start);
for (const char **suf = suffixes; *suf; suf++) {
gchar *name_with_extension = g_strconcat(iconname, *suf, NULL);
maybe_icon_path = g_build_filename(current_folder, name_with_extension, NULL);
if (is_readable_file(maybe_icon_path)) {
new_name = g_strdup(maybe_icon_path);
}
g_free(name_with_extension);
maybe_icon_path = g_strconcat(current_folder, "/", iconname, *suf, NULL);
if (is_readable_file(maybe_icon_path))
pixbuf = get_pixbuf_from_file(maybe_icon_path);
g_free(maybe_icon_path);
if (new_name)
if (pixbuf)
break;
}
g_free(current_folder);
if (new_name)
if (pixbuf)
break;
start = end + 1;
} while (STR_FULL(end));
if (!new_name)
if (!pixbuf)
LOG_W("No icon found in path: '%s'", iconname);
}
g_free(uri_path);
return new_name;
}
GdkPixbuf *get_pixbuf_from_icon(const char *iconname, int scale)
{
char *path = get_path_from_icon_name(iconname);
if (!path) {
return NULL;
}
GdkPixbuf *pixbuf = NULL;
pixbuf = get_pixbuf_from_file(path, scale);
g_free(path);
if (!pixbuf)
LOG_W("No icon found in path: '%s'", iconname);
return pixbuf;
}
GdkPixbuf *icon_get_for_name(const char *name, char **id, int scale)
GdkPixbuf *icon_get_for_name(const char *name, char **id)
{
ASSERT_OR_RET(name, NULL);
ASSERT_OR_RET(id, NULL);
GdkPixbuf *pb = get_pixbuf_from_icon(name, scale);
GdkPixbuf *pb = get_pixbuf_from_icon(name);
if (pb)
*id = g_strdup(name);
return pb;
}
GdkPixbuf *icon_get_for_data(GVariant *data, char **id, int dpi_scale)
GdkPixbuf *icon_get_for_data(GVariant *data, char **id)
{
ASSERT_OR_RET(data, NULL);
ASSERT_OR_RET(id, NULL);
@ -360,13 +284,7 @@ GdkPixbuf *icon_get_for_data(GVariant *data, char **id, int dpi_scale)
return NULL;
}
// g_memdup is deprecated in glib 2.67.4 and higher.
// g_memdup2 is a safer alternative
#if GLIB_CHECK_VERSION(2,67,3)
data_pb = (guchar *) g_memdup2(g_variant_get_data(data_variant), len_actual);
#else
data_pb = (guchar *) g_memdup(g_variant_get_data(data_variant), len_actual);
#endif
pixbuf = gdk_pixbuf_new_from_data(data_pb,
GDK_COLORSPACE_RGB,
@ -402,9 +320,7 @@ GdkPixbuf *icon_get_for_data(GVariant *data, char **id, int dpi_scale)
g_free(data_chk);
g_variant_unref(data_variant);
pixbuf = icon_pixbuf_scale(pixbuf, dpi_scale);
return pixbuf;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -8,54 +8,38 @@
cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf);
/** Retrieve an icon by its full filepath, scaled according to settings.
/**
* Scales the given GdkPixbuf if necessary according to the settings.
*
* @param pixbuf (nullable) The pixbuf, which may be too big.
* Takes ownership of the reference.
* @return the scaled version of the pixbuf. If scaling wasn't
* necessary, it returns the same pixbuf. Transfers full
* ownership of the reference.
*/
GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf);
/** Retrieve an icon by its full filepath.
*
* @param filename A string representing a readable file path
* @param scale An integer representing the output dpi scaling.
*
* @return an instance of `GdkPixbuf`
* @retval NULL: file does not exist, not readable, etc..
*/
GdkPixbuf *get_pixbuf_from_file(const char *filename, int scale);
GdkPixbuf *get_pixbuf_from_file(const char *filename);
/**
* Get the unscaled icon width.
*
* If scale is 2 for example, the icon will render in twice the size, but
* get_icon_width still returns the same size as when scale is 1.
*/
int get_icon_width(cairo_surface_t *icon, int scale);
/**
* Get the unscaled icon height, see get_icon_width.
*/
int get_icon_height(cairo_surface_t *icon, int scale);
/** Retrieve a path from an icon name.
/** Retrieve an icon by its name sent via the notification bus
*
* @param iconname A string describing a `file://` URL, an arbitary filename
* or an icon name, which then gets searched for in the
* settings.icon_path
*
* @return a newly allocated string with the icon path
* @retval NULL: file does not exist, not readable, etc..
*/
char *get_path_from_icon_name(const char *iconname);
/** Retrieve an icon by its name sent via the notification bus, scaled according to settings
*
* @param iconname A string describing a `file://` URL, an arbitary filename
* or an icon name, which then gets searched for in the
* settings.icon_path
* @param scale An integer representing the output dpi scaling.
*
* @return an instance of `GdkPixbuf`
* @retval NULL: file does not exist, not readable, etc..
*/
GdkPixbuf *get_pixbuf_from_icon(const char *iconname, int scale);
GdkPixbuf *get_pixbuf_from_icon(const char *iconname);
/** Read an icon from disk and convert it to a GdkPixbuf, scaled according to settings
/** Read an icon from disk and convert it to a GdkPixbuf.
*
* The returned id will be a unique identifier. To check if two given
* GdkPixbufs are equal, it's sufficient to just compare the id strings.
@ -65,13 +49,12 @@ GdkPixbuf *get_pixbuf_from_icon(const char *iconname, int scale);
* get searched in the folders of the icon_path setting.
* @param id (necessary) A unique identifier of the returned pixbuf. Only filled,
* if the return value is non-NULL.
* @param dpi_scale An integer representing the output dpi scaling.
* @return an instance of `GdkPixbuf`, representing the name's image
* @retval NULL: Invalid path given
*/
GdkPixbuf *icon_get_for_name(const char *name, char **id, int dpi_scale);
GdkPixbuf *icon_get_for_name(const char *name, char **id);
/** Convert a GVariant like described in GdkPixbuf, scaled according to settings
/** Convert a GVariant like described in GdkPixbuf
*
* The returned id will be a unique identifier. To check if two given
* GdkPixbufs are equal, it's sufficient to just compare the id strings.
@ -80,11 +63,10 @@ GdkPixbuf *icon_get_for_name(const char *name, char **id, int dpi_scale);
* like described in the notification spec.
* @param id (necessary) A unique identifier of the returned pixbuf.
* Only filled, if the return value is non-NULL.
* @param scale An integer representing the output dpi scaling.
* @return an instance of `GdkPixbuf` derived from the GVariant
* @retval NULL: GVariant parameter nulled, invalid or in wrong format
*/
GdkPixbuf *icon_get_for_data(GVariant *data, char **id, int scale);
GdkPixbuf *icon_get_for_data(GVariant *data, char **id);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -1,81 +0,0 @@
#include "input.h"
#include "log.h"
#include "menu.h"
#include "settings.h"
#include "queues.h"
#include <stddef.h>
#include <linux/input-event-codes.h>
void input_handle_click(unsigned int button, bool button_down, int mouse_x, int mouse_y){
LOG_I("Pointer handle button %i: %i", button, button_down);
if (button_down) {
// make sure it only reacts on button release
return;
}
enum mouse_action *acts;
switch (button) {
case BTN_LEFT:
acts = settings.mouse_left_click;
break;
case BTN_MIDDLE:
acts = settings.mouse_middle_click;
break;
case BTN_RIGHT:
acts = settings.mouse_right_click;
break;
case BTN_TOUCH:
// TODO Add separate action for touch
acts = settings.mouse_left_click;
break;
default:
LOG_W("Unsupported mouse button: '%d'", button);
return;
}
for (int i = 0; acts[i]; i++) {
enum mouse_action act = acts[i];
if (act == MOUSE_CLOSE_ALL) {
queues_history_push_all();
break;
}
if (act == MOUSE_CONTEXT_ALL) {
context_menu();
continue;
}
if (act == MOUSE_DO_ACTION || act == MOUSE_CLOSE_CURRENT || act == MOUSE_CONTEXT || act == MOUSE_OPEN_URL) {
int y = settings.separator_height;
struct notification *n = NULL;
int first = true;
for (const GList *iter = queues_get_displayed(); iter;
iter = iter->next) {
n = iter->data;
if (mouse_y > y && mouse_y < y + n->displayed_height)
break;
y += n->displayed_height + settings.separator_height;
if (first)
y += settings.frame_width;
}
if (n) {
if (act == MOUSE_CLOSE_CURRENT) {
n->marked_for_closure = REASON_USER;
} else if (act == MOUSE_DO_ACTION) {
notification_do_action(n);
} else if (act == MOUSE_OPEN_URL) {
notification_open_url(n);
} else {
notification_open_context_menu(n);
}
}
}
}
wake_up();
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -1,18 +0,0 @@
#ifndef DUNST_INPUT_H
#define DUNST_INPUT_H
#include <stdbool.h>
/**
* Handle incoming mouse click events
*
* @param button code, A linux input event code
* @param button_down State of the button
* @param mouse_x X-position of the mouse, relative to the window
* @param mouse_y Y-position of the mouse, relative to the window
*
*/
void input_handle_click(unsigned int button, bool button_down, int mouse_x, int mouse_y);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -74,21 +74,19 @@ static void dunst_log_handler(
gpointer testing)
{
if (testing)
log_level = G_LOG_LEVEL_ERROR;
GLogLevelFlags message_level_masked = message_level & G_LOG_LEVEL_MASK;
return;
/* if you want to have a debug build, you want to log anything,
* unconditionally, without specifying debug log level again */
#ifndef DEBUG_BUILD
if (log_level < message_level_masked)
if (log_level < message_level)
return;
#endif
const char *log_level_str =
log_level_to_string(message_level_masked);
log_level_to_string(message_level & G_LOG_LEVEL_MASK);
/* Use stderr for warnings and higher */
if (message_level_masked <= G_LOG_LEVEL_WARNING)
if (message_level <= G_LOG_LEVEL_WARNING)
g_printerr("%s: %s\n", log_level_str, message);
else
g_print("%s: %s\n", log_level_str, message);
@ -100,4 +98,4 @@ void dunst_log_init(bool testing)
g_log_set_default_handler(dunst_log_handler, (void*)testing);
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -45,4 +45,4 @@ void log_set_level_from_string(const char* level);
void dunst_log_init(bool testing);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -338,4 +338,4 @@ char *markup_transform(char *str, enum markup_mode markup_mode)
return str;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -48,4 +48,4 @@ void markup_strip_img(char **str, char **urls);
char *markup_transform(char *str, enum markup_mode markup_mode);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -23,12 +23,12 @@
static bool is_initialized = false;
static regex_t url_regex;
struct notification_lock {
struct notification *n;
gint64 timeout;
};
static gpointer context_menu_thread(gpointer data);
struct {
GList *locked_notifications;
} menu_ctx;
/**
* Initializes regexes needed for matching.
*
@ -290,43 +290,9 @@ char *invoke_dmenu(const char *dmenu_input)
return ret;
}
/**
* Lock and get all notifications with an action or URL.
**/
static GList *get_actionable_notifications(void)
{
GList *locked_notifications = NULL;
for (const GList *iter = queues_get_displayed(); iter;
iter = iter->next) {
struct notification *n = iter->data;
if (n->urls || g_hash_table_size(n->actions)) {
notification_lock(n);
locked_notifications = g_list_prepend(locked_notifications, n);
}
}
return locked_notifications;
}
/* see menu.h */
void context_menu(void)
{
GList *notifications = get_actionable_notifications();
context_menu_for(notifications);
}
/* see menu.h */
void context_menu_for(GList *notifications)
{
if (menu_ctx.locked_notifications) {
LOG_W("Context menu already running, refusing to rerun");
return;
}
menu_ctx.locked_notifications = notifications;
GError *err = NULL;
g_thread_unref(g_thread_try_new("dmenu",
context_menu_thread,
@ -339,41 +305,32 @@ void context_menu_for(GList *notifications)
}
}
static gboolean context_menu_result_dispatch(gpointer user_data)
{
char *dmenu_output = (char*)user_data;
dispatch_menu_result(dmenu_output);
for (GList *iter = menu_ctx.locked_notifications; iter; iter = iter->next) {
struct notification *n = iter->data;
notification_unlock(n);
if (n->marked_for_closure) {
// Don't close notification if context was aborted
if (dmenu_output != NULL)
queues_notification_close(n, n->marked_for_closure);
n->marked_for_closure = 0;
}
}
menu_ctx.locked_notifications = NULL;
g_list_free(menu_ctx.locked_notifications);
g_free(dmenu_output);
wake_up();
return G_SOURCE_REMOVE;
}
static gpointer context_menu_thread(gpointer data)
{
char *dmenu_input = NULL;
char *dmenu_output;
for (GList *iter = menu_ctx.locked_notifications; iter; iter = iter->next) {
GList *locked_notifications = NULL;
for (const GList *iter = queues_get_displayed(); iter;
iter = iter->next) {
struct notification *n = iter->data;
// Reference and lock the notification if we need it
if (n->urls || g_hash_table_size(n->actions)) {
notification_ref(n);
struct notification_lock *nl =
g_malloc(sizeof(struct notification_lock));
nl->n = n;
nl->timeout = n->timeout;
n->timeout = 0;
locked_notifications = g_list_prepend(locked_notifications, nl);
}
char *dmenu_str = notification_dmenu_string(n);
dmenu_input = string_append(dmenu_input, dmenu_str, "\n");
g_free(dmenu_str);
@ -383,10 +340,26 @@ static gpointer context_menu_thread(gpointer data)
}
dmenu_output = invoke_dmenu(dmenu_input);
g_timeout_add(50, context_menu_result_dispatch, dmenu_output);
dispatch_menu_result(dmenu_output);
g_free(dmenu_input);
g_free(dmenu_output);
// unref all notifications
for (GList *iter = locked_notifications;
iter;
iter = iter->next) {
struct notification_lock *nl = iter->data;
struct notification *n = nl->n;
n->timeout = nl->timeout;
g_free(nl);
notification_unref(n);
}
g_list_free(locked_notifications);
return NULL;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -2,8 +2,6 @@
#ifndef DUNST_MENU_H
#define DUNST_MENU_H
#include <glib.h>
/**
* Extract all urls from the given string.
*
@ -18,15 +16,9 @@ void invoke_action(const char *action);
void regex_teardown(void);
/**
* Open the context menu that lets the user select urls/actions/etc for all displayed notifications.
* Open the context menu that lets the user select urls/actions/etc.
*/
void context_menu(void);
/**
* Open the context menu that lets the user select urls/actions/etc for the specified notifications.
* @param notifications (nullable) List of notifications for which the context menu should be opened
*/
void context_menu_for(GList *notifications);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -23,7 +23,6 @@
#include "rules.h"
#include "settings.h"
#include "utils.h"
#include "draw.h"
static void notification_extract_urls(struct notification *n);
static void notification_format_message(struct notification *n);
@ -65,7 +64,6 @@ void notification_print(const struct notification *n)
printf("\tformatted: '%s'\n", n->msg);
printf("\tfg: %s\n", n->colors.fg);
printf("\tbg: %s\n", n->colors.bg);
printf("\thighlight: %s\n", n->colors.highlight);
printf("\tframe: %s\n", n->colors.frame);
printf("\tfullscreen: %s\n", enum_to_string_fullscreen(n->fullscreen));
printf("\tprogress: %d\n", n->progress);
@ -90,21 +88,16 @@ void notification_print(const struct notification *n)
printf("\t\t\"%s\": \"%s\"\n", (char*)p_key, (char*)p_value);
printf("\t}\n");
}
printf("\tscript_count: %d\n", n->script_count);
if (n->script_count > 0) {
printf("\tscripts: ");
for (int i = 0; i < n->script_count; i++) {
printf("'%s' ",n->scripts[i]);
}
printf("\n");
}
printf("\tscript: %s\n", n->script);
printf("}\n");
fflush(stdout);
}
/* see notification.h */
void notification_run_script(struct notification *n)
{
if (STR_EMPTY(n->script))
return;
if (n->script_run && !settings.always_run_script)
return;
@ -117,54 +110,26 @@ void notification_run_script(struct notification *n)
const char *urgency = notification_urgency_to_string(n->urgency);
for(int i = 0; i < n->script_count; i++) {
int pid1 = fork();
const char *script = n->scripts[i];
if (STR_EMPTY(script))
continue;
int pid1 = fork();
if (pid1) {
int status;
waitpid(pid1, &status, 0);
if (pid1) {
int status;
waitpid(pid1, &status, 0);
} else {
int pid2 = fork();
if (pid2) {
exit(0);
} else {
// second fork to prevent zombie processes
int pid2 = fork();
if (pid2) {
exit(0);
} else {
// Set environment variables
gchar *n_id_str = g_strdup_printf("%i", n->id);
gchar *n_progress_str = g_strdup_printf("%i", n->progress);
gchar *n_timeout_str = g_strdup_printf("%li", n->timeout/1000);
gchar *n_timestamp_str = g_strdup_printf("%li", n->timestamp / 1000);
char* icon_path = get_path_from_icon_name(icon);
safe_setenv("DUNST_APP_NAME", appname);
safe_setenv("DUNST_SUMMARY", summary);
safe_setenv("DUNST_BODY", body);
safe_setenv("DUNST_ICON_PATH", icon_path);
safe_setenv("DUNST_URGENCY", urgency);
safe_setenv("DUNST_ID", n_id_str);
safe_setenv("DUNST_PROGRESS", n_progress_str);
safe_setenv("DUNST_CATEGORY", n->category);
safe_setenv("DUNST_STACK_TAG", n->stack_tag);
safe_setenv("DUNST_URLS", n->urls);
safe_setenv("DUNST_TIMEOUT", n_timeout_str);
safe_setenv("DUNST_TIMESTAMP", n_timestamp_str);
safe_setenv("DUNST_STACK_TAG", n->stack_tag);
execlp(script,
script,
appname,
summary,
body,
icon,
urgency,
(char *)NULL);
LOG_W("Unable to run script %s: %s", n->scripts[i], strerror(errno));
int ret = execlp(n->script,
n->script,
appname,
summary,
body,
icon,
urgency,
(char *)NULL);
if (ret != 0) {
LOG_W("Unable to run script: %s", strerror(errno));
exit(EXIT_FAILURE);
}
}
@ -193,7 +158,7 @@ const char *notification_urgency_to_string(const enum urgency urgency)
/* see notification.h */
int notification_cmp(const struct notification *a, const struct notification *b)
{
if (settings.sort && a->urgency != b->urgency) {
if (a->urgency != b->urgency) {
return b->urgency - a->urgency;
} else {
return a->id - b->id;
@ -206,6 +171,8 @@ int notification_cmp_data(const void *va, const void *vb, void *data)
struct notification *a = (struct notification *) va;
struct notification *b = (struct notification *) vb;
ASSERT_OR_RET(settings.sort, 1);
return notification_cmp(a, b);
}
@ -218,30 +185,6 @@ bool notification_is_duplicate(const struct notification *a, const struct notifi
&& a->urgency == b->urgency;
}
bool notification_is_locked(struct notification *n) {
assert(n);
return g_atomic_int_get(&n->locked) != 0;
}
struct notification* notification_lock(struct notification *n) {
assert(n);
g_atomic_int_set(&n->locked, 1);
notification_ref(n);
return n;
}
struct notification* notification_unlock(struct notification *n) {
assert(n);
g_atomic_int_set(&n->locked, 0);
notification_unref(n);
return n;
}
static void notification_private_free(NotificationPrivate *p)
{
g_free(p);
@ -281,13 +224,11 @@ void notification_unref(struct notification *n)
g_free(n->urls);
g_free(n->colors.fg);
g_free(n->colors.bg);
g_free(n->colors.highlight);
g_free(n->colors.frame);
g_free(n->stack_tag);
g_free(n->desktop_entry);
g_hash_table_unref(n->actions);
g_free(n->default_action_name);
if (n->icon)
g_object_unref(n->icon);
@ -295,10 +236,6 @@ void notification_unref(struct notification *n)
notification_private_free(n->priv);
if (n->script_count > 0){
g_free(n->scripts);
}
g_free(n);
}
@ -314,7 +251,8 @@ void notification_icon_replace_path(struct notification *n, const char *new_icon
g_clear_object(&n->icon);
g_clear_pointer(&n->icon_id, g_free);
n->icon = icon_get_for_name(new_icon, &n->icon_id, draw_get_scale());
n->icon = icon_get_for_name(new_icon, &n->icon_id);
n->icon = icon_pixbuf_scale(n->icon);
}
void notification_icon_replace_data(struct notification *n, GVariant *new_icon)
@ -325,7 +263,8 @@ void notification_icon_replace_data(struct notification *n, GVariant *new_icon)
g_clear_object(&n->icon);
g_clear_pointer(&n->icon_id, g_free);
n->icon = icon_get_for_data(new_icon, &n->icon_id, draw_get_scale());
n->icon = icon_get_for_data(new_icon, &n->icon_id);
n->icon = icon_pixbuf_scale(n->icon);
}
/* see notification.h */
@ -386,9 +325,7 @@ struct notification *notification_create(void)
n->fullscreen = FS_SHOW;
n->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
n->default_action_name = g_strdup("default");
n->script_count = 0;
return n;
}
@ -441,8 +378,6 @@ void notification_init(struct notification *n)
n->colors.fg = g_strdup(defcolors.fg);
if (!n->colors.bg)
n->colors.bg = g_strdup(defcolors.bg);
if (!n->colors.highlight)
n->colors.highlight = g_strdup(defcolors.highlight);
if (!n->colors.frame)
n->colors.frame = g_strdup(defcolors.frame);
@ -453,12 +388,6 @@ void notification_init(struct notification *n)
/* Process rules */
rule_apply_all(n);
if (g_str_has_prefix(n->summary, "DUNST_COMMAND_")) {
char *msg = "DUNST_COMMAND_* has been removed, please switch to dunstctl. See #830 for more details. https://github.com/dunst-project/dunst/pull/830";
LOG_W("%s", msg);
n->body = string_append(n->body, msg, "\n");
}
/* UPDATE derived fields */
notification_extract_urls(n);
notification_format_message(n);
@ -648,47 +577,27 @@ void notification_update_text_to_render(struct notification *n)
}
/* see notification.h */
void notification_do_action(struct notification *n)
void notification_do_action(const struct notification *n)
{
assert(n->default_action_name);
if (g_hash_table_size(n->actions)) {
if (g_hash_table_contains(n->actions, n->default_action_name)) {
signal_action_invoked(n, n->default_action_name);
if (g_hash_table_contains(n->actions, "default")) {
signal_action_invoked(n, "default");
return;
}
if (strcmp(n->default_action_name, "default") == 0 && g_hash_table_size(n->actions) == 1) {
if (g_hash_table_size(n->actions) == 1) {
GList *keys = g_hash_table_get_keys(n->actions);
signal_action_invoked(n, keys->data);
g_list_free(keys);
return;
}
notification_open_context_menu(n);
context_menu();
} else if (n->urls) {
if (strstr(n->urls, "\n"))
context_menu();
else
open_browser(n->urls);
}
}
/* see notification.h */
void notification_open_url(struct notification *n)
{
if (strstr(n->urls, "\n"))
notification_open_context_menu(n);
else
open_browser(n->urls);
}
/* see notification.h */
void notification_open_context_menu(struct notification *n)
{
GList *notifications = NULL;
notifications = g_list_append(notifications, n);
notification_lock(n);
context_menu_for(notifications);
}
void notification_invalidate_actions(struct notification *n) {
g_hash_table_remove_all(n->actions);
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -33,7 +33,6 @@ struct notification_colors {
char *frame;
char *bg;
char *fg;
char *highlight;
};
struct notification {
@ -55,18 +54,15 @@ struct notification {
char *iconname; /**< plain icon information (may be a path or just a name)
Use this to compare the icon name with rules.*/
gint64 start; /**< begin of current display (in milliseconds) */
gint64 timestamp; /**< arrival time (in milliseconds) */
gint64 timeout; /**< time to display (in milliseconds) */
int locked; /**< If non-zero the notification is locked **/
gint64 start; /**< begin of current display */
gint64 timestamp; /**< arrival time */
gint64 timeout; /**< time to display */
GHashTable *actions;
char *default_action_name; /**< The name of the action to be invoked on do_action */
enum markup_mode markup;
const char *format;
const char **scripts;
int script_count;
const char *script;
struct notification_colors colors;
char *stack_tag; /**< stack notifications by tag */
@ -84,7 +80,6 @@ struct notification {
int displayed_height;
enum behavior_fullscreen fullscreen; //!< The instruction what to do with it, when desktop enters fullscreen
bool script_run; /**< Has the script been executed already? */
guint8 marked_for_closure;
/* derived fields */
char *msg; /**< formatted message */
@ -142,12 +137,6 @@ int notification_cmp_data(const void *va, const void *vb, void *data);
bool notification_is_duplicate(const struct notification *a, const struct notification *b);
bool notification_is_locked(struct notification *n);
struct notification *notification_lock(struct notification *n);
struct notification *notification_unlock(struct notification *n);
/**Replace the current notification's icon with the icon specified by path.
*
* Removes the reference for the previous icon automatically and will also free the
@ -196,33 +185,11 @@ void notification_replace_single_field(char **haystack,
void notification_update_text_to_render(struct notification *n);
/**
* If the notification has an action named n->default_action_name or there is only one
* action and n->default_action_name is set to "default", invoke it. If there is no
* such action, open the context menu if threre are other actions. Otherwise, do nothing.
* 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. If
* there are no actions, proceed similarly with urls.
*/
void notification_do_action(struct notification *n);
/**
* If the notification has exactly one url, invoke it. If there are multiple,
* open the context menu. If there are no urls, do nothing.
*/
void notification_open_url(struct notification *n);
/**
* Open the context menu for the notification.
*
* Convenience function that creates the GList and passes it to context_menu_for().
*/
void notification_open_context_menu(struct notification *n);
/**
* Remove all client action data from the notification.
*
* This should be called after a notification is closed to avoid showing
* actions that will not work anymore since the client has stopped listening
* for them.
*/
void notification_invalidate_actions(struct notification *n);
void notification_do_action(const struct notification *n);
const char *notification_urgency_to_string(const enum urgency urgency);
@ -235,4 +202,4 @@ const char *notification_urgency_to_string(const enum urgency urgency);
const char *enum_to_string_fullscreen(enum behavior_fullscreen in);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -44,7 +44,7 @@ static int cmdline_find_option(const char *key);
bool string_parse_alignment(const char *s, enum alignment *ret)
{
ASSERT_OR_RET(STR_FULL(s), false);
ASSERT_OR_RET(s, false);
ASSERT_OR_RET(ret, false);
STRING_PARSE_RET("left", ALIGN_LEFT);
@ -56,7 +56,7 @@ bool string_parse_alignment(const char *s, enum alignment *ret)
bool string_parse_ellipsize(const char *s, enum ellipsize *ret)
{
ASSERT_OR_RET(STR_FULL(s), false);
ASSERT_OR_RET(s, false);
ASSERT_OR_RET(ret, false);
STRING_PARSE_RET("start", ELLIPSE_START);
@ -68,7 +68,7 @@ bool string_parse_ellipsize(const char *s, enum ellipsize *ret)
bool string_parse_follow_mode(const char *s, enum follow_mode *ret)
{
ASSERT_OR_RET(STR_FULL(s), false);
ASSERT_OR_RET(s, false);
ASSERT_OR_RET(ret, false);
STRING_PARSE_RET("mouse", FOLLOW_MOUSE);
@ -81,7 +81,7 @@ bool string_parse_follow_mode(const char *s, enum follow_mode *ret)
bool string_parse_fullscreen(const char *s, enum behavior_fullscreen *ret)
{
ASSERT_OR_RET(STR_FULL(s), false);
ASSERT_OR_RET(s, false);
ASSERT_OR_RET(ret, false);
STRING_PARSE_RET("show", FS_SHOW);
@ -93,7 +93,7 @@ bool string_parse_fullscreen(const char *s, enum behavior_fullscreen *ret)
bool string_parse_icon_position(const char *s, enum icon_position *ret)
{
ASSERT_OR_RET(STR_FULL(s), false);
ASSERT_OR_RET(s, false);
ASSERT_OR_RET(ret, false);
STRING_PARSE_RET("left", ICON_LEFT);
@ -103,21 +103,9 @@ bool string_parse_icon_position(const char *s, enum icon_position *ret)
return false;
}
bool string_parse_vertical_alignment(const char *s, enum vertical_alignment *ret)
{
ASSERT_OR_RET(STR_FULL(s), false);
ASSERT_OR_RET(ret, false);
STRING_PARSE_RET("top", VERTICAL_TOP);
STRING_PARSE_RET("center", VERTICAL_CENTER);
STRING_PARSE_RET("bottom", VERTICAL_BOTTOM);
return false;
}
bool string_parse_markup_mode(const char *s, enum markup_mode *ret)
{
ASSERT_OR_RET(STR_FULL(s), false);
ASSERT_OR_RET(s, false);
ASSERT_OR_RET(ret, false);
STRING_PARSE_RET("strip", MARKUP_STRIP);
@ -130,44 +118,20 @@ bool string_parse_markup_mode(const char *s, enum markup_mode *ret)
bool string_parse_mouse_action(const char *s, enum mouse_action *ret)
{
ASSERT_OR_RET(STR_FULL(s), false);
ASSERT_OR_RET(s, false);
ASSERT_OR_RET(ret, false);
STRING_PARSE_RET("none", MOUSE_NONE);
STRING_PARSE_RET("do_action", MOUSE_DO_ACTION);
STRING_PARSE_RET("close_current", MOUSE_CLOSE_CURRENT);
STRING_PARSE_RET("close_all", MOUSE_CLOSE_ALL);
STRING_PARSE_RET("context", MOUSE_CONTEXT);
STRING_PARSE_RET("context_all", MOUSE_CONTEXT_ALL);
STRING_PARSE_RET("open_url", MOUSE_OPEN_URL);
return false;
}
bool string_parse_mouse_action_list(char **s, enum mouse_action **ret)
{
ASSERT_OR_RET(s, false);
ASSERT_OR_RET(ret, false);
int len = 0;
while (s[len])
len++;
*ret = g_malloc_n((len + 1), sizeof(enum mouse_action));
for (int i = 0; i < len; i++) {
if (!string_parse_mouse_action(s[i], *ret + i)) {
LOG_W("Unknown mouse action value: '%s'", s[i]);
g_free(*ret);
return false;
}
}
(*ret)[len] = -1; // sentinel end value
return true;
}
bool string_parse_sepcolor(const char *s, struct separator_color_data *ret)
{
ASSERT_OR_RET(STR_FULL(s), false);
ASSERT_OR_RET(s, false);
ASSERT_OR_RET(ret, false);
STRING_PARSE_RET("auto", (struct separator_color_data){.type = SEP_AUTO});
@ -182,7 +146,7 @@ bool string_parse_sepcolor(const char *s, struct separator_color_data *ret)
bool string_parse_urgency(const char *s, enum urgency *ret)
{
ASSERT_OR_RET(STR_FULL(s), false);
ASSERT_OR_RET(s, false);
ASSERT_OR_RET(ret, false);
STRING_PARSE_RET("low", URG_LOW);
@ -192,18 +156,6 @@ bool string_parse_urgency(const char *s, enum urgency *ret)
return false;
}
bool string_parse_layer(const char *s, enum zwlr_layer_shell_v1_layer *ret)
{
ASSERT_OR_RET(STR_FULL(s), false);
ASSERT_OR_RET(ret, false);
STRING_PARSE_RET("bottom", ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM);
STRING_PARSE_RET("top", ZWLR_LAYER_SHELL_V1_LAYER_TOP);
STRING_PARSE_RET("overlay", ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY);
return false;
}
struct section *new_section(const char *name)
{
for (int i = 0; i < section_count; i++) {
@ -296,15 +248,6 @@ gint64 ini_get_time(const char *section, const char *key, gint64 def)
return val;
}
char **ini_get_list(const char *section, const char *key, const char *def)
{
const char *value = get_value(section, key);
if (value)
return string_to_array(value);
else
return string_to_array(def);
}
int ini_get_int(const char *section, const char *key, int def)
{
const char *value = get_value(section, key);
@ -520,17 +463,6 @@ char *cmdline_get_path(const char *key, const char *def, const char *description
return string_to_path(g_strdup(def));
}
char **cmdline_get_list(const char *key, const char *def, const char *description)
{
cmdline_usage_append(key, "list", description);
const char *str = cmdline_get_value(key);
if (str)
return string_to_array(str);
else
return string_to_array(def);
}
gint64 cmdline_get_time(const char *key, gint64 def, const char *description)
{
cmdline_usage_append(key, "time", description);
@ -630,23 +562,6 @@ gint64 option_get_time(const char *ini_section,
return cmdline_get_time(cmdline_key, ini_val, description);
}
char **option_get_list(const char *ini_section,
const char *ini_key,
const char *cmdline_key,
const char *def,
const char *description)
{
char **val = NULL;
if (cmdline_key)
val = cmdline_get_list(cmdline_key, NULL, description);
if (val)
return val;
else
return ini_get_list(ini_section, ini_key, def);
}
int option_get_int(const char *ini_section,
const char *ini_key,
const char *cmdline_key,
@ -731,4 +646,4 @@ const char *cmdline_create_usage(void)
return usage_str;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -14,19 +14,15 @@ bool string_parse_ellipsize(const char *s, enum ellipsize *ret);
bool string_parse_follow_mode(const char *s, enum follow_mode *ret);
bool string_parse_fullscreen(const char *s, enum behavior_fullscreen *ret);
bool string_parse_icon_position(const char *s, enum icon_position *ret);
bool string_parse_vertical_alignment(const char *s, enum vertical_alignment *ret);
bool string_parse_markup_mode(const char *s, enum markup_mode *ret);
bool string_parse_mouse_action(const char *s, enum mouse_action *ret);
bool string_parse_mouse_action_list(char **s, enum mouse_action **ret);
bool string_parse_sepcolor(const char *s, struct separator_color_data *ret);
bool string_parse_urgency(const char *s, enum urgency *ret);
bool string_parse_layer(const char *s, enum zwlr_layer_shell_v1_layer *ret);
int load_ini_file(FILE *);
char *ini_get_path(const char *section, const char *key, const char *def);
char *ini_get_string(const char *section, const char *key, const char *def);
gint64 ini_get_time(const char *section, const char *key, gint64 def);
char **ini_get_list(const char *section, const char *key, const char *def);
int ini_get_int(const char *section, const char *key, int def);
double ini_get_double(const char *section, const char *key, double def);
int ini_get_bool(const char *section, const char *key, int def);
@ -37,7 +33,6 @@ void cmdline_load(int argc, char *argv[]);
/* for all cmdline_get_* key can be either "-key" or "-key/-longkey" */
char *cmdline_get_string(const char *key, const char *def, const char *description);
char *cmdline_get_path(const char *key, const char *def, const char *description);
char **cmdline_get_list(const char *key, const char *def, const char *description);
int cmdline_get_int(const char *key, int def, const char *description);
double cmdline_get_double(const char *key, double def, const char *description);
int cmdline_get_bool(const char *key, int def, const char *description);
@ -59,11 +54,6 @@ gint64 option_get_time(const char *ini_section,
const char *cmdline_key,
gint64 def,
const char *description);
char **option_get_list(const char *ini_section,
const char *ini_key,
const char *cmdline_key,
const char *def,
const char *description);
int option_get_int(const char *ini_section,
const char *ini_key,
const char *cmdline_key,
@ -87,4 +77,4 @@ int option_get_bool(const char *ini_section,
const char *next_section(const char *section);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -1,96 +0,0 @@
#include "output.h"
#include "log.h"
#include "x11/x.h"
#include "x11/screen.h"
#ifdef ENABLE_WAYLAND
#include "wayland/wl.h"
#endif
bool is_running_wayland(void) {
char* wayland_display = getenv("WAYLAND_DISPLAY");
return !(wayland_display == NULL);
}
const struct output output_x11 = {
x_setup,
x_free,
x_win_create,
x_win_destroy,
x_win_show,
x_win_hide,
x_display_surface,
x_win_get_context,
get_active_screen,
x_is_idle,
have_fullscreen_window,
x_get_scale,
};
#ifdef ENABLE_WAYLAND
const struct output output_wl = {
wl_init,
wl_deinit,
wl_win_create,
wl_win_destroy,
wl_win_show,
wl_win_hide,
wl_display_surface,
wl_win_get_context,
wl_get_active_screen,
wl_is_idle,
wl_have_fullscreen_window,
wl_get_scale,
};
#endif
const struct output* get_x11_output() {
const struct output* output = &output_x11;
if (output->init()) {
return output;
} else {
LOG_E("Couldn't initialize X11 output. Aborting...");
}
}
#ifdef ENABLE_WAYLAND
const struct output* get_wl_output() {
const struct output* output = &output_wl;
if (output->init()) {
return output;
} else {
LOG_W("Couldn't initialize wayland output. Falling back to X11 output.");
output->deinit();
return get_x11_output();
}
}
#endif
const struct output* output_create(bool force_xwayland)
{
#ifdef ENABLE_WAYLAND
if (!force_xwayland && is_running_wayland()) {
LOG_I("Using Wayland output");
return get_wl_output();
} else {
LOG_I("Using X11 output");
return get_x11_output();
}
#else
return get_x11_output();
#endif
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -1,61 +0,0 @@
#ifndef DUNST_OUTPUT_H
#define DUNST_OUTPUT_H
#include <stdbool.h>
#include <glib.h>
#include <cairo.h>
typedef gpointer window;
struct dimensions {
int x;
int y;
int w;
int h;
int corner_radius;
};
struct screen_info {
int id;
int x;
int y;
unsigned int h;
unsigned int mmh;
unsigned int w;
int dpi;
};
struct output {
bool (*init)(void);
void (*deinit)(void);
window (*win_create)(void);
void (*win_destroy)(window);
void (*win_show)(window);
void (*win_hide)(window);
void (*display_surface)(cairo_surface_t *srf, window win, const struct dimensions*);
cairo_t* (*win_get_context)(window);
const struct screen_info* (*get_active_screen)(void);
bool (*is_idle)(void);
bool (*have_fullscreen_window)(void);
int (*get_scale)(void);
};
/**
* return an initialized output, selecting the correct output type from either
* wayland or X11 according to the settings and environment.
* When the wayland output fails to initilize, it falls back to X11 output.
*/
const struct output* output_create(bool force_xwayland);
bool is_running_wayland(void);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -25,7 +25,6 @@
#include "notification.h"
#include "settings.h"
#include "utils.h"
#include "output.h" // For checking if wayland is active.
/* notification lists */
static GQueue *waiting = NULL; /**< all new notifications get into here */
@ -46,7 +45,7 @@ void queues_init(void)
}
/* see queues.h */
GList *queues_get_displayed(void)
const GList *queues_get_displayed(void)
{
return g_queue_peek_head_link(displayed);
}
@ -168,6 +167,19 @@ int queues_notification_insert(struct notification *n)
LOG_M("Skipping notification: '%s' '%s'", n->body, n->summary);
return 0;
}
/* Do not insert the message if it's a command */
if (STR_EQ("DUNST_COMMAND_PAUSE", n->summary)) {
dunst_status(S_RUNNING, false);
return 0;
}
if (STR_EQ("DUNST_COMMAND_RESUME", n->summary)) {
dunst_status(S_RUNNING, true);
return 0;
}
if (STR_EQ("DUNST_COMMAND_TOGGLE", n->summary)) {
dunst_status(S_RUNNING, !dunst_status_get().running);
return 0;
}
bool inserted = false;
if (n->id != 0) {
@ -377,19 +389,6 @@ void queues_update(struct dunst_status status)
struct notification *n = iter->data;
nextiter = iter->next;
if (notification_is_locked(n)) {
iter = nextiter;
continue;
}
if (n->marked_for_closure) {
queues_notification_close(n, n->marked_for_closure);
n->marked_for_closure = 0;
iter = nextiter;
continue;
}
if (queues_notification_is_finished(n, status)){
queues_notification_close(n, REASON_TIME);
iter = nextiter;
@ -507,27 +506,6 @@ gint64 queues_get_next_datachange(gint64 time)
return sleep != G_MAXINT64 ? sleep : -1;
}
/* see queues.h */
struct notification* queues_get_by_id(int id)
{
assert(id > 0);
GQueue *recqueues[] = { displayed, waiting, history };
for (int i = 0; i < sizeof(recqueues)/sizeof(GQueue*); i++) {
for (GList *iter = g_queue_peek_head_link(recqueues[i]); iter;
iter = iter->next) {
struct notification *cur = iter->data;
if (cur->id == id)
return cur;
}
}
return NULL;
}
/**
* Helper function for queues_teardown() to free a single notification
*
@ -549,6 +527,4 @@ void queues_teardown(void)
g_queue_free_full(waiting, teardown_notification);
waiting = NULL;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -24,7 +24,7 @@ void queues_init(void);
*
* @return read only list of notifications
*/
GList *queues_get_displayed(void);
const GList *queues_get_displayed(void);
/**
* Get the highest notification in line
@ -145,17 +145,6 @@ void queues_update(struct dunst_status status);
*/
gint64 queues_get_next_datachange(gint64 time);
/**
* Get the notification which has the given id in the displayed and waiting queue or
* NULL if not found
*
* @param id the id searched for.
*
* @return the `id` notification or NULL
*/
struct notification* queues_get_by_id(int id);
/**
* Remove all notifications from all list and free the notifications
*
@ -164,4 +153,4 @@ struct notification* queues_get_by_id(int id);
void queues_teardown(void);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -26,10 +26,6 @@ void rule_apply(struct rule *r, struct notification *n)
n->transient = r->set_transient;
if (r->skip_display != -1)
n->skip_display = r->skip_display;
if (r->action_name) {
g_free(n->default_action_name);
n->default_action_name = g_strdup(r->action_name);
}
if (r->markup != MARKUP_NULL)
n->markup = r->markup;
if (r->new_icon)
@ -42,22 +38,14 @@ void rule_apply(struct rule *r, struct notification *n)
g_free(n->colors.bg);
n->colors.bg = g_strdup(r->bg);
}
if (r->highlight) {
g_free(n->colors.highlight);
n->colors.highlight = g_strdup(r->highlight);
}
if (r->fc) {
g_free(n->colors.frame);
n->colors.frame = g_strdup(r->fc);
}
if (r->format)
n->format = r->format;
if (r->script){
n->scripts = g_renew(const char*,n->scripts,n->script_count + 1);
n->scripts[n->script_count] = r->script;
n->script_count++;
}
if (r->script)
n->script = r->script;
if (r->set_stack_tag) {
g_free(n->stack_tag);
n->stack_tag = g_strdup(r->set_stack_tag);
@ -86,7 +74,7 @@ struct rule *rule_new(void)
r->urgency = URG_NONE;
r->fullscreen = FS_NULL;
r->markup = MARKUP_NULL;
r->history_ignore = -1;
r->history_ignore = false;
r->match_transient = -1;
r->set_transient = -1;
r->skip_display = -1;
@ -114,4 +102,4 @@ bool rule_matches_notification(struct rule *r, struct notification *n)
&& rule_field_matches_string(n->category, r->category)
&& rule_field_matches_string(n->stack_tag, r->stack_tag);
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -23,7 +23,6 @@ struct rule {
/* actions */
gint64 timeout;
enum urgency urgency;
char *action_name;
enum markup_mode markup;
int history_ignore;
int match_transient;
@ -32,7 +31,6 @@ struct rule {
char *new_icon;
char *fg;
char *bg;
char *highlight;
char *fc;
const char *format;
const char *script;
@ -54,4 +52,4 @@ void rule_apply_all(struct notification *n);
bool rule_matches_notification(struct rule *r, struct notification *n);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -13,7 +13,6 @@
#include "rules.h"
#include "utils.h"
#include "x11/x.h"
#include "output.h"
#include "../config.h"
@ -54,10 +53,6 @@ static FILE *xdg_config(const char *filename)
g_free(path);
}
if (!f) {
f = fopen("/etc/dunst/dunstrc", "r");
}
return f;
}
@ -123,12 +118,6 @@ void load_settings(char *cmdline_config_path)
"Force the use of the Xinerama extension"
);
settings.force_xwayland = option_get_bool(
"global",
"force_xwayland", "-force_xwayland", false,
"Force the use of the xwayland output"
);
settings.font = option_get_string(
"global",
"font", "-font/-fn", defaults.font,
@ -187,11 +176,6 @@ void load_settings(char *cmdline_config_path)
"word_wrap", "-word_wrap", defaults.word_wrap,
"Truncating long lines or do word wrap"
);
settings.ignore_dbusclose = option_get_bool(
"global",
"ignore_dbusclose", "-ignore_dbusclose", defaults.ignore_dbusclose,
"Ignore dbus CloseNotification events"
);
{
char *c = option_get_string(
@ -220,22 +204,6 @@ void load_settings(char *cmdline_config_path)
"Don't timeout notifications if user is longer idle than threshold"
);
#ifndef ENABLE_WAYLAND
if (is_running_wayland()){
/* We are using xwayland now. Setting force_xwayland to make sure
* the idle workaround below is activated */
settings.force_xwayland = true;
}
#endif
if (settings.force_xwayland && is_running_wayland()) {
if (settings.idle_threshold > 0)
LOG_W("Using xwayland. Disabling idle.");
/* There is no way to detect if the user is idle
* on xwayland, so turn this feature off */
settings.idle_threshold = 0;
}
settings.monitor = option_get_int(
"global",
"monitor", "-mon/-monitor", defaults.monitor,
@ -370,12 +338,6 @@ void load_settings(char *cmdline_config_path)
"horizontal padding"
);
settings.text_icon_padding = option_get_int(
"global",
"text_icon_padding", "-text_icon_padding", defaults.text_icon_padding,
"Padding between text and icon"
);
settings.transparency = option_get_int(
"global",
"transparency", "-transparency", defaults.transparency,
@ -388,49 +350,6 @@ void load_settings(char *cmdline_config_path)
"Window corner radius"
);
settings.progress_bar_height = option_get_int(
"global",
"progress_bar_height", "-progress_bar_height", defaults.progress_bar_height,
"Height of the progress bar"
);
settings.progress_bar_min_width = option_get_int(
"global",
"progress_bar_min_width", "-progress_bar_min_width", defaults.progress_bar_min_width,
"Minimum width of the progress bar"
);
settings.progress_bar_max_width = option_get_int(
"global",
"progress_bar_max_width", "-progress_bar_max_width", defaults.progress_bar_max_width,
"Maximum width of the progress bar"
);
settings.progress_bar_frame_width = option_get_int(
"global",
"progress_bar_frame_width", "-progress_bar_frame_width", defaults.progress_bar_frame_width,
"Frame width of the progress bar"
);
settings.progress_bar = option_get_bool(
"global",
"progress_bar", "-progress_bar", true,
"Show the progress bar"
);
// check sanity of the progress bar options
{
if (settings.progress_bar_height < (2 * settings.progress_bar_frame_width)){
LOG_E("setting progress_bar_frame_width is bigger than half of progress_bar_height");
}
if (settings.progress_bar_max_width < (2 * settings.progress_bar_frame_width)){
LOG_E("setting progress_bar_frame_width is bigger than half of progress_bar_max_width");
}
if (settings.progress_bar_max_width < settings.progress_bar_min_width){
LOG_E("setting progress_bar_max_width is smaller than progress_bar_min_width");
}
}
{
char *c = option_get_string(
"global",
@ -492,7 +411,7 @@ void load_settings(char *cmdline_config_path)
{
char *c = option_get_string(
"global",
"icon_position", "-icon_position", "left",
"icon_position", "-icon_position", "off",
"Align icons left/right/off"
);
@ -504,43 +423,6 @@ void load_settings(char *cmdline_config_path)
g_free(c);
}
{
char *c = option_get_string(
"global",
"vertical_alignment", "-vertical_alignment", "center",
"Align icon and text top/center/bottom"
);
if (!string_parse_vertical_alignment(c, &settings.vertical_alignment)) {
if (c)
LOG_W("Unknown vertical alignment: '%s'", c);
settings.vertical_alignment = defaults.vertical_alignment;
}
g_free(c);
}
{
char *c = option_get_string(
"global",
"layer", "-layer", "overlay",
"Select the layer where notifications should be placed"
);
if (!string_parse_layer(c, &settings.layer)) {
if (c)
LOG_W("Unknown layer: '%s'", c);
settings.layer = defaults.layer;
}
g_free(c);
}
settings.min_icon_size = option_get_int(
"global",
"min_icon_size", "-min_icon_size", defaults.min_icon_size,
"Scale smaller icons up to this size, set to 0 to disable. If max_icon_size also specified, that has the final say."
);
settings.max_icon_size = option_get_int(
"global",
"max_icon_size", "-max_icon_size", defaults.max_icon_size,
@ -626,42 +508,48 @@ void load_settings(char *cmdline_config_path)
}
{
char **c = option_get_list(
char *c = option_get_string(
"global",
"mouse_left_click", "-mouse_left_click", NULL,
"mouse_left_click", "-left_click", NULL,
"Action of Left click event"
);
if (!string_parse_mouse_action_list(c, &settings.mouse_left_click)) {
if (!string_parse_mouse_action(c, &settings.mouse_left_click)) {
if (c)
LOG_W("Unknown mouse action value: '%s'", c);
settings.mouse_left_click = defaults.mouse_left_click;
}
free_string_array(c);
g_free(c);
}
{
char **c = option_get_list(
char *c = option_get_string(
"global",
"mouse_middle_click", "-mouse_middle_click", NULL,
"Action of middle click event"
);
if (!string_parse_mouse_action_list(c, &settings.mouse_middle_click)) {
if (!string_parse_mouse_action(c, &settings.mouse_middle_click)) {
if (c)
LOG_W("Unknown mouse action value: '%s'", c);
settings.mouse_middle_click = defaults.mouse_middle_click;
}
free_string_array(c);
g_free(c);
}
{
char **c = option_get_list(
char *c = option_get_string(
"global",
"mouse_right_click", "-mouse_right_click", NULL,
"Action of right click event"
);
if (!string_parse_mouse_action_list(c, &settings.mouse_right_click)) {
if (!string_parse_mouse_action(c, &settings.mouse_right_click)) {
if (c)
LOG_W("Unknown mouse action value: '%s'", c);
settings.mouse_right_click = defaults.mouse_right_click;
}
free_string_array(c);
g_free(c);
}
settings.colors_low.bg = option_get_string(
@ -676,12 +564,6 @@ void load_settings(char *cmdline_config_path)
"Foreground color for notifications with low urgency"
);
settings.colors_low.highlight = option_get_string(
"urgency_low",
"highlight", "-lh", defaults.colors_low.highlight,
"Highlight color for notifications with low urgency"
);
settings.colors_low.frame = option_get_string(
"urgency_low",
"frame_color", "-lfr", settings.frame_color ? settings.frame_color : defaults.colors_low.frame,
@ -712,12 +594,6 @@ void load_settings(char *cmdline_config_path)
"Foreground color for notifications with normal urgency"
);
settings.colors_norm.highlight = option_get_string(
"urgency_normal",
"highlight", "-nh", defaults.colors_norm.highlight,
"Highlight color for notifications with normal urgency"
);
settings.colors_norm.frame = option_get_string(
"urgency_normal",
"frame_color", "-nfr", settings.frame_color ? settings.frame_color : defaults.colors_norm.frame,
@ -748,12 +624,6 @@ void load_settings(char *cmdline_config_path)
"Foreground color for notifications with ciritical urgency"
);
settings.colors_crit.highlight = option_get_string(
"urgency_critical",
"highlight", "-ch", defaults.colors_crit.highlight,
"Highlight color for notifications with ciritical urgency"
);
settings.colors_crit.frame = option_get_string(
"urgency_critical",
"frame_color", "-cfr", settings.frame_color ? settings.frame_color : defaults.colors_crit.frame,
@ -862,12 +732,10 @@ void load_settings(char *cmdline_config_path)
g_free(c);
}
r->action_name = ini_get_string(cur_section, "action_name", NULL);
r->urgency = ini_get_urgency(cur_section, "urgency", r->urgency);
r->msg_urgency = ini_get_urgency(cur_section, "msg_urgency", r->msg_urgency);
r->fg = ini_get_string(cur_section, "foreground", r->fg);
r->bg = ini_get_string(cur_section, "background", r->bg);
r->highlight = ini_get_string(cur_section, "highlight", r->highlight);
r->fc = ini_get_string(cur_section, "frame_color", r->fc);
r->format = ini_get_string(cur_section, "format", r->format);
r->new_icon = ini_get_string(cur_section, "new_icon", r->new_icon);
@ -899,4 +767,4 @@ void load_settings(char *cmdline_config_path)
}
#endif
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -4,10 +4,6 @@
#include <stdbool.h>
#ifdef ENABLE_WAYLAND
#include "wayland/protocols/wlr-layer-shell-unstable-v1-client-header.h"
#endif
#include "markup.h"
#include "notification.h"
#include "x11/x.h"
@ -15,20 +11,9 @@
enum alignment { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT };
enum ellipsize { ELLIPSE_START, ELLIPSE_MIDDLE, ELLIPSE_END };
enum icon_position { ICON_LEFT, ICON_RIGHT, ICON_OFF };
enum vertical_alignment { VERTICAL_TOP, VERTICAL_CENTER, VERTICAL_BOTTOM };
enum separator_color { SEP_FOREGROUND, SEP_AUTO, SEP_FRAME, SEP_CUSTOM };
enum follow_mode { FOLLOW_NONE, FOLLOW_MOUSE, FOLLOW_KEYBOARD };
enum mouse_action { MOUSE_NONE, MOUSE_DO_ACTION, MOUSE_CLOSE_CURRENT, MOUSE_CLOSE_ALL, MOUSE_CONTEXT, MOUSE_CONTEXT_ALL, MOUSE_OPEN_URL };
#ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM
#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM
// Needed for compiling without wayland dependency
enum zwlr_layer_shell_v1_layer {
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0,
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1,
ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2,
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3,
};
#endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */
enum mouse_action { MOUSE_NONE, MOUSE_DO_ACTION, MOUSE_CLOSE_CURRENT, MOUSE_CLOSE_ALL };
struct separator_color_data {
enum separator_color type;
@ -73,7 +58,6 @@ struct settings {
int history_length;
int show_indicators;
int word_wrap;
int ignore_dbusclose;
enum ellipsize ellipsize;
int ignore_newline;
int line_height;
@ -81,7 +65,6 @@ struct settings {
int separator_height;
int padding;
int h_padding;
int text_icon_padding;
struct separator_color_data sep_color;
int frame_width;
char *frame_color;
@ -92,8 +75,6 @@ struct settings {
char *browser;
char **browser_cmd;
enum icon_position icon_position;
enum vertical_alignment vertical_alignment;
int min_icon_size;
int max_icon_size;
char *icon_path;
enum follow_mode f_mode;
@ -103,17 +84,10 @@ struct settings {
struct keyboard_shortcut history_ks;
struct keyboard_shortcut context_ks;
bool force_xinerama;
bool force_xwayland;
int corner_radius;
enum mouse_action *mouse_left_click;
enum mouse_action *mouse_middle_click;
enum mouse_action *mouse_right_click;
int progress_bar_height;
int progress_bar_min_width;
int progress_bar_max_width;
int progress_bar_frame_width;
bool progress_bar;
enum zwlr_layer_shell_v1_layer layer;
enum mouse_action mouse_left_click;
enum mouse_action mouse_middle_click;
enum mouse_action mouse_right_click;
};
extern struct settings settings;
@ -121,4 +95,4 @@ extern struct settings settings;
void load_settings(char *cmdline_config_path);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -5,25 +5,12 @@
#include <ctype.h>
#include <errno.h>
#include <glib.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "log.h"
/* see utils.h */
void free_string_array(char **arr)
{
if (arr){
for (int i = 0; arr[i]; i++){
g_free(arr[i]);
}
}
g_free(arr);
}
/* see utils.h */
char *string_replace_char(char needle, char replacement, char *haystack)
{
@ -146,25 +133,12 @@ void string_strip_delimited(char *str, char a, char b)
str[iwrite] = 0;
}
/* see utils.h */
char **string_to_array(const char *string)
{
char **arr = NULL;
if (string) {
arr = g_strsplit(string, ",", 0);
for (int i = 0; arr[i]; i++){
g_strstrip(arr[i]);
}
}
return arr;
}
/* see utils.h */
char *string_to_path(char *string)
{
if (string && STRN_EQ(string, "~/", 2)) {
char *home = g_strconcat(user_get_home(), "/", NULL);
char *home = g_strconcat(getenv("HOME"), "/", NULL);
string = string_replace_at(string, 0, 2, home);
@ -230,33 +204,4 @@ gint64 time_monotonic_now(void)
#endif
return S2US(tv_now.tv_sec) + tv_now.tv_nsec / 1000;
}
/* see utils.h */
const char *user_get_home(void)
{
static const char *home_directory = NULL;
ASSERT_OR_RET(!home_directory, home_directory);
// Check the HOME variable for the user's home
home_directory = getenv("HOME");
ASSERT_OR_RET(!home_directory, home_directory);
// Check the /etc/passwd entry for the user's home
home_directory = getpwuid(getuid())->pw_dir;
return home_directory;
}
bool safe_setenv(const char* key, const char* value){
if (!key)
return false;
if (!value)
setenv(key, "", 1);
else
setenv(key, value, 1);
return true;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -4,7 +4,6 @@
#include <glib.h>
#include <string.h>
#include <stdbool.h>
//! Test if a string is NULL or empty
#define STR_EMPTY(s) (!s || (*s == '\0'))
@ -23,15 +22,6 @@
//! Convert a second into the internal time representation
#define S2US(s) (((gint64)(s)) * 1000 * 1000)
/**
* Frees an array of strings whose last element is a NULL pointer.
*
* Assumes the last element is a NULL pointer, otherwise will result in a buffer overflow.
* @param arr The array of strings to free
*/
void free_string_array(char **arr);
/**
* Replaces all occurrences of the char \p needle with the char \p replacement in \p haystack.
*
@ -92,17 +82,6 @@ char *string_strip_quotes(const char *value);
*/
void string_strip_delimited(char *str, char a, char b);
/**
* Parse a comma-delimited string into a dynamic array of tokens
*
* The string is split on commas and strips spaces from tokens. The last element
* of the array is NULL in order to avoid passing around a length variable.
*
* @param string The string to convert to an array
* @returns The array of tokens.
*/
char **string_to_array(const char *string);
/**
* Replace tilde and path-specific values with its equivalents
*
@ -131,23 +110,5 @@ gint64 string_to_time(const char *string);
*/
gint64 time_monotonic_now(void);
/**
* Retrieve the HOME directory of the user running dunst
*
* @returns: A string of the current home directory
*/
const char *user_get_home(void);
/**
* Try to set an environment variable safely. If an environment variable with
* name `key` exists, it will be overwritten.
* If `value` is null, `key` will be set to an empty string.
*
* @param key (nullable) The environment variable to change
* @param value (nullable) The value to change it to.
* @returns: A bool that is true when it succeeds
*/
bool safe_setenv(const char* key, const char* value);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -1,192 +0,0 @@
/*
* libgwater-wayland - Wayland GSource
*
* Copyright © 2014-2017 Quentin "Sardem FF7" Glidic
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#ifdef G_LOG_DOMAIN
#undef G_LOG_DOMAIN
#endif /* G_LOG_DOMAIN */
#define G_LOG_DOMAIN "GWaterWayland"
#include <errno.h>
#include <glib.h>
#include <wayland-client.h>
#include "libgwater-wayland.h"
struct _GWaterWaylandSource {
GSource source;
gboolean display_owned;
struct wl_display *display;
gpointer fd;
int error;
};
static gboolean
_g_water_wayland_source_prepare(GSource *source, gint *timeout)
{
GWaterWaylandSource *self = (GWaterWaylandSource *)source;
*timeout = 0;
if ( wl_display_prepare_read(self->display) != 0 )
return TRUE;
else if ( wl_display_flush(self->display) < 0 )
{
self->error = errno;
return TRUE;
}
*timeout = -1;
return FALSE;
}
static gboolean
_g_water_wayland_source_check(GSource *source)
{
GWaterWaylandSource *self = (GWaterWaylandSource *)source;
if ( self->error > 0 )
return TRUE;
GIOCondition revents;
revents = g_source_query_unix_fd(source, self->fd);
if ( revents & G_IO_IN )
{
if ( wl_display_read_events(self->display) < 0 )
self->error = errno;
}
else
wl_display_cancel_read(self->display);
return ( revents > 0 );
}
static gboolean
_g_water_wayland_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
{
GWaterWaylandSource *self = (GWaterWaylandSource *)source;
GIOCondition revents;
revents = g_source_query_unix_fd(source, self->fd);
if ( ( self->error > 0 ) || ( revents & (G_IO_ERR | G_IO_HUP) ) )
{
errno = self->error;
self->error = 0;
if ( callback != NULL )
return callback(user_data);
return G_SOURCE_REMOVE;
}
if ( wl_display_dispatch_pending(self->display) < 0 )
{
if ( callback != NULL )
return callback(user_data);
return G_SOURCE_REMOVE;
}
return G_SOURCE_CONTINUE;
}
static void
_g_water_wayland_source_finalize(GSource *source)
{
GWaterWaylandSource *self = (GWaterWaylandSource *)source;
if ( self->display_owned )
wl_display_disconnect(self->display);
}
static GSourceFuncs _g_water_wayland_source_funcs = {
.prepare = _g_water_wayland_source_prepare,
.check = _g_water_wayland_source_check,
.dispatch = _g_water_wayland_source_dispatch,
.finalize = _g_water_wayland_source_finalize,
};
GWaterWaylandSource *
g_water_wayland_source_new(GMainContext *context, const gchar *name)
{
struct wl_display *display;
GWaterWaylandSource *self;
display = wl_display_connect(name);
if ( display == NULL )
return NULL;
self = g_water_wayland_source_new_for_display(context, display);
self->display_owned = TRUE;
return self;
}
GWaterWaylandSource *
g_water_wayland_source_new_for_display(GMainContext *context, struct wl_display *display)
{
g_return_val_if_fail(display != NULL, NULL);
GSource *source;
GWaterWaylandSource *self;
source = g_source_new(&_g_water_wayland_source_funcs, sizeof(GWaterWaylandSource));
self = (GWaterWaylandSource *)source;
self->display = display;
self->fd = g_source_add_unix_fd(source, wl_display_get_fd(self->display), G_IO_IN | G_IO_ERR | G_IO_HUP);
g_source_attach(source, context);
return self;
}
void
g_water_wayland_source_free(GWaterWaylandSource *self)
{
GSource * source = (GSource *)self;
g_return_if_fail(self != NULL);
g_source_destroy(source);
g_source_unref(source);
}
void
g_water_wayland_source_set_error_callback(GWaterWaylandSource *self, GSourceFunc callback, gpointer user_data, GDestroyNotify destroy_notify)
{
g_return_if_fail(self != NULL);
g_source_set_callback((GSource *)self, callback, user_data, destroy_notify);
}
struct wl_display *
g_water_wayland_source_get_display(GWaterWaylandSource *self)
{
g_return_val_if_fail(self != NULL, NULL);
return self->display;
}

View File

@ -1,42 +0,0 @@
/*
* libgwater-wayland - Wayland GSource
*
* Copyright © 2014-2017 Quentin "Sardem FF7" Glidic
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 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.
*
*/
#ifndef __G_WATER_WAYLAND_H__
#define __G_WATER_WAYLAND_H__
G_BEGIN_DECLS
typedef struct _GWaterWaylandSource GWaterWaylandSource;
GWaterWaylandSource *g_water_wayland_source_new(GMainContext *context, const gchar *name);
GWaterWaylandSource *g_water_wayland_source_new_for_display(GMainContext *context, struct wl_display *display);
void g_water_wayland_source_free(GWaterWaylandSource *self);
void g_water_wayland_source_set_error_callback(GWaterWaylandSource *self, GSourceFunc callback, gpointer user_data, GDestroyNotify destroy_notify);
struct wl_display *g_water_wayland_source_get_display(GWaterWaylandSource *source);
G_END_DECLS
#endif /* __G_WATER_WAYLAND_H__ */

View File

@ -1,150 +0,0 @@
#define _POSIX_C_SOURCE 200112L
#include <cairo/cairo.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <wayland-client.h>
#include <string.h>
#include "pool-buffer.h"
static void randname(char *buf) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
long r = ts.tv_nsec;
for (int i = 0; i < 6; ++i) {
buf[i] = 'A'+(r&15)+(r&16)*2;
r >>= 5;
}
}
static int anonymous_shm_open(void) {
char name[] = "/dunst-XXXXXX";
int retries = 100;
do {
randname(name + strlen(name) - 6);
--retries;
// shm_open guarantees that O_CLOEXEC is set
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd >= 0) {
shm_unlink(name);
return fd;
}
} while (retries > 0 && errno == EEXIST);
return -1;
}
static int create_shm_file(off_t size) {
int fd = anonymous_shm_open();
if (fd < 0) {
return fd;
}
if (ftruncate(fd, size) < 0) {
close(fd);
return -1;
}
return fd;
}
static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) {
struct pool_buffer *buffer = data;
buffer->busy = false;
}
static const struct wl_buffer_listener buffer_listener = {
.release = buffer_handle_release,
};
static struct pool_buffer *create_buffer(struct wl_shm *shm,
struct pool_buffer *buf, int32_t width, int32_t height) {
const enum wl_shm_format wl_fmt = WL_SHM_FORMAT_ARGB8888;
const cairo_format_t cairo_fmt = CAIRO_FORMAT_ARGB32;
uint32_t stride = cairo_format_stride_for_width(cairo_fmt, width);
size_t size = stride * height;
void *data = NULL;
if (size > 0) {
int fd = create_shm_file(size);
if (fd == -1) {
return NULL;
}
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
close(fd);
return NULL;
}
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
buf->buffer =
wl_shm_pool_create_buffer(pool, 0, width, height, stride, wl_fmt);
wl_buffer_add_listener(buf->buffer, &buffer_listener, buf);
wl_shm_pool_destroy(pool);
close(fd);
}
buf->data = data;
buf->size = size;
buf->width = width;
buf->height = height;
buf->surface = cairo_image_surface_create_for_data(data, cairo_fmt, width,
height, stride);
buf->cairo = cairo_create(buf->surface);
buf->pango = pango_cairo_create_context(buf->cairo);
return buf;
}
void finish_buffer(struct pool_buffer *buffer) {
if (buffer->buffer) {
wl_buffer_destroy(buffer->buffer);
}
if (buffer->cairo) {
cairo_destroy(buffer->cairo);
}
if (buffer->surface) {
cairo_surface_destroy(buffer->surface);
}
if (buffer->pango) {
g_object_unref(buffer->pango);
}
if (buffer->data) {
munmap(buffer->data, buffer->size);
}
memset(buffer, 0, sizeof(struct pool_buffer));
}
struct pool_buffer *get_next_buffer(struct wl_shm *shm,
struct pool_buffer pool[static 2], uint32_t width, uint32_t height) {
struct pool_buffer *buffer = NULL;
for (size_t i = 0; i < 2; ++i) {
if (pool[i].busy) {
continue;
}
buffer = &pool[i];
}
if (!buffer) {
return NULL;
}
if (buffer->width != width || buffer->height != height) {
finish_buffer(buffer);
}
if (!buffer->buffer) {
if (!create_buffer(shm, buffer, width, height)) {
return NULL;
}
}
return buffer;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -1,26 +0,0 @@
#ifndef DUNST_POOL_BUFFER_H
#define DUNST_POOL_BUFFER_H
#include <cairo/cairo.h>
#include <pango/pangocairo.h>
#include <stdbool.h>
#include <stdint.h>
#include <wayland-client.h>
struct pool_buffer {
struct wl_buffer *buffer;
cairo_surface_t *surface;
cairo_t *cairo;
PangoContext *pango;
uint32_t width, height;
void *data;
size_t size;
bool busy;
};
struct pool_buffer *get_next_buffer(struct wl_shm *shm,
struct pool_buffer pool[static 2], uint32_t width, uint32_t height);
void finish_buffer(struct pool_buffer *buffer);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -1,233 +0,0 @@
/* Generated by wayland-scanner 1.18.0 */
#ifndef IDLE_CLIENT_PROTOCOL_H
#define IDLE_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_idle The idle protocol
* @section page_ifaces_idle Interfaces
* - @subpage page_iface_org_kde_kwin_idle - User idle time manager
* - @subpage page_iface_org_kde_kwin_idle_timeout -
* @section page_copyright_idle Copyright
* <pre>
*
* Copyright (C) 2015 Martin Gräßlin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* </pre>
*/
struct org_kde_kwin_idle;
struct org_kde_kwin_idle_timeout;
struct wl_seat;
/**
* @page page_iface_org_kde_kwin_idle org_kde_kwin_idle
* @section page_iface_org_kde_kwin_idle_desc Description
*
* This interface allows to monitor user idle time on a given seat. The interface
* allows to register timers which trigger after no user activity was registered
* on the seat for a given interval. It notifies when user activity resumes.
*
* This is useful for applications wanting to perform actions when the user is not
* interacting with the system, e.g. chat applications setting the user as away, power
* management features to dim screen, etc..
* @section page_iface_org_kde_kwin_idle_api API
* See @ref iface_org_kde_kwin_idle.
*/
/**
* @defgroup iface_org_kde_kwin_idle The org_kde_kwin_idle interface
*
* This interface allows to monitor user idle time on a given seat. The interface
* allows to register timers which trigger after no user activity was registered
* on the seat for a given interval. It notifies when user activity resumes.
*
* This is useful for applications wanting to perform actions when the user is not
* interacting with the system, e.g. chat applications setting the user as away, power
* management features to dim screen, etc..
*/
extern const struct wl_interface org_kde_kwin_idle_interface;
/**
* @page page_iface_org_kde_kwin_idle_timeout org_kde_kwin_idle_timeout
* @section page_iface_org_kde_kwin_idle_timeout_api API
* See @ref iface_org_kde_kwin_idle_timeout.
*/
/**
* @defgroup iface_org_kde_kwin_idle_timeout The org_kde_kwin_idle_timeout interface
*/
extern const struct wl_interface org_kde_kwin_idle_timeout_interface;
#define ORG_KDE_KWIN_IDLE_GET_IDLE_TIMEOUT 0
/**
* @ingroup iface_org_kde_kwin_idle
*/
#define ORG_KDE_KWIN_IDLE_GET_IDLE_TIMEOUT_SINCE_VERSION 1
/** @ingroup iface_org_kde_kwin_idle */
static inline void
org_kde_kwin_idle_set_user_data(struct org_kde_kwin_idle *org_kde_kwin_idle, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) org_kde_kwin_idle, user_data);
}
/** @ingroup iface_org_kde_kwin_idle */
static inline void *
org_kde_kwin_idle_get_user_data(struct org_kde_kwin_idle *org_kde_kwin_idle)
{
return wl_proxy_get_user_data((struct wl_proxy *) org_kde_kwin_idle);
}
static inline uint32_t
org_kde_kwin_idle_get_version(struct org_kde_kwin_idle *org_kde_kwin_idle)
{
return wl_proxy_get_version((struct wl_proxy *) org_kde_kwin_idle);
}
/** @ingroup iface_org_kde_kwin_idle */
static inline void
org_kde_kwin_idle_destroy(struct org_kde_kwin_idle *org_kde_kwin_idle)
{
wl_proxy_destroy((struct wl_proxy *) org_kde_kwin_idle);
}
/**
* @ingroup iface_org_kde_kwin_idle
*/
static inline struct org_kde_kwin_idle_timeout *
org_kde_kwin_idle_get_idle_timeout(struct org_kde_kwin_idle *org_kde_kwin_idle, struct wl_seat *seat, uint32_t timeout)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) org_kde_kwin_idle,
ORG_KDE_KWIN_IDLE_GET_IDLE_TIMEOUT, &org_kde_kwin_idle_timeout_interface, NULL, seat, timeout);
return (struct org_kde_kwin_idle_timeout *) id;
}
/**
* @ingroup iface_org_kde_kwin_idle_timeout
* @struct org_kde_kwin_idle_timeout_listener
*/
struct org_kde_kwin_idle_timeout_listener {
/**
* Triggered when there has not been any user activity in the requested idle time interval
*
*
*/
void (*idle)(void *data,
struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout);
/**
* Triggered on the first user activity after an idle event
*
*
*/
void (*resumed)(void *data,
struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout);
};
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
static inline int
org_kde_kwin_idle_timeout_add_listener(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout,
const struct org_kde_kwin_idle_timeout_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) org_kde_kwin_idle_timeout,
(void (**)(void)) listener, data);
}
#define ORG_KDE_KWIN_IDLE_TIMEOUT_RELEASE 0
#define ORG_KDE_KWIN_IDLE_TIMEOUT_SIMULATE_USER_ACTIVITY 1
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
#define ORG_KDE_KWIN_IDLE_TIMEOUT_IDLE_SINCE_VERSION 1
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
#define ORG_KDE_KWIN_IDLE_TIMEOUT_RESUMED_SINCE_VERSION 1
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
#define ORG_KDE_KWIN_IDLE_TIMEOUT_RELEASE_SINCE_VERSION 1
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
#define ORG_KDE_KWIN_IDLE_TIMEOUT_SIMULATE_USER_ACTIVITY_SINCE_VERSION 1
/** @ingroup iface_org_kde_kwin_idle_timeout */
static inline void
org_kde_kwin_idle_timeout_set_user_data(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) org_kde_kwin_idle_timeout, user_data);
}
/** @ingroup iface_org_kde_kwin_idle_timeout */
static inline void *
org_kde_kwin_idle_timeout_get_user_data(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout)
{
return wl_proxy_get_user_data((struct wl_proxy *) org_kde_kwin_idle_timeout);
}
static inline uint32_t
org_kde_kwin_idle_timeout_get_version(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout)
{
return wl_proxy_get_version((struct wl_proxy *) org_kde_kwin_idle_timeout);
}
/** @ingroup iface_org_kde_kwin_idle_timeout */
static inline void
org_kde_kwin_idle_timeout_destroy(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout)
{
wl_proxy_destroy((struct wl_proxy *) org_kde_kwin_idle_timeout);
}
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
static inline void
org_kde_kwin_idle_timeout_release(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout)
{
wl_proxy_marshal((struct wl_proxy *) org_kde_kwin_idle_timeout,
ORG_KDE_KWIN_IDLE_TIMEOUT_RELEASE);
wl_proxy_destroy((struct wl_proxy *) org_kde_kwin_idle_timeout);
}
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
static inline void
org_kde_kwin_idle_timeout_simulate_user_activity(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout)
{
wl_proxy_marshal((struct wl_proxy *) org_kde_kwin_idle_timeout,
ORG_KDE_KWIN_IDLE_TIMEOUT_SIMULATE_USER_ACTIVITY);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,68 +0,0 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright (C) 2015 Martin Gräßlin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface org_kde_kwin_idle_timeout_interface;
extern const struct wl_interface wl_seat_interface;
static const struct wl_interface *idle_types[] = {
&org_kde_kwin_idle_timeout_interface,
&wl_seat_interface,
NULL,
};
static const struct wl_message org_kde_kwin_idle_requests[] = {
{ "get_idle_timeout", "nou", idle_types + 0 },
};
WL_PRIVATE const struct wl_interface org_kde_kwin_idle_interface = {
"org_kde_kwin_idle", 1,
1, org_kde_kwin_idle_requests,
0, NULL,
};
static const struct wl_message org_kde_kwin_idle_timeout_requests[] = {
{ "release", "", idle_types + 0 },
{ "simulate_user_activity", "", idle_types + 0 },
};
static const struct wl_message org_kde_kwin_idle_timeout_events[] = {
{ "idle", "", idle_types + 0 },
{ "resumed", "", idle_types + 0 },
};
WL_PRIVATE const struct wl_interface org_kde_kwin_idle_timeout_interface = {
"org_kde_kwin_idle_timeout", 1,
2, org_kde_kwin_idle_timeout_requests,
2, org_kde_kwin_idle_timeout_events,
};

View File

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="idle">
<copyright><![CDATA[
Copyright (C) 2015 Martin Gräßlin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]]></copyright>
<interface name="org_kde_kwin_idle" version="1">
<description summary="User idle time manager">
This interface allows to monitor user idle time on a given seat. The interface
allows to register timers which trigger after no user activity was registered
on the seat for a given interval. It notifies when user activity resumes.
This is useful for applications wanting to perform actions when the user is not
interacting with the system, e.g. chat applications setting the user as away, power
management features to dim screen, etc..
</description>
<request name="get_idle_timeout">
<arg name="id" type="new_id" interface="org_kde_kwin_idle_timeout"/>
<arg name="seat" type="object" interface="wl_seat"/>
<arg name="timeout" type="uint" summary="The idle timeout in msec"/>
</request>
</interface>
<interface name="org_kde_kwin_idle_timeout" version="1">
<request name="release" type="destructor">
<description summary="release the timeout object"/>
</request>
<request name="simulate_user_activity">
<description summary="Simulates user activity for this timeout, behaves just like real user activity on the seat"/>
</request>
<event name="idle">
<description summary="Triggered when there has not been any user activity in the requested idle time interval"/>
</event>
<event name="resumed">
<description summary="Triggered on the first user activity after an idle event"/>
</event>
</interface>
</protocol>

View File

@ -1,611 +0,0 @@
/* Generated by wayland-scanner 1.18.0 */
#ifndef WLR_FOREIGN_TOPLEVEL_MANAGEMENT_UNSTABLE_V1_CLIENT_PROTOCOL_H
#define WLR_FOREIGN_TOPLEVEL_MANAGEMENT_UNSTABLE_V1_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_wlr_foreign_toplevel_management_unstable_v1 The wlr_foreign_toplevel_management_unstable_v1 protocol
* @section page_ifaces_wlr_foreign_toplevel_management_unstable_v1 Interfaces
* - @subpage page_iface_zwlr_foreign_toplevel_manager_v1 - list and control opened apps
* - @subpage page_iface_zwlr_foreign_toplevel_handle_v1 - an opened toplevel
* @section page_copyright_wlr_foreign_toplevel_management_unstable_v1 Copyright
* <pre>
*
* Copyright © 2018 Ilia Bozhinov
*
* Permission to use, copy, modify, distribute, and sell this
* software and its documentation for any purpose is hereby granted
* without fee, provided that the above copyright notice appear in
* all copies and that both that copyright notice and this permission
* notice appear in supporting documentation, and that the name of
* the copyright holders not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
* THIS SOFTWARE.
* </pre>
*/
struct wl_output;
struct wl_seat;
struct wl_surface;
struct zwlr_foreign_toplevel_handle_v1;
struct zwlr_foreign_toplevel_manager_v1;
/**
* @page page_iface_zwlr_foreign_toplevel_manager_v1 zwlr_foreign_toplevel_manager_v1
* @section page_iface_zwlr_foreign_toplevel_manager_v1_desc Description
*
* The purpose of this protocol is to enable the creation of taskbars
* and docks by providing them with a list of opened applications and
* letting them request certain actions on them, like maximizing, etc.
*
* After a client binds the zwlr_foreign_toplevel_manager_v1, each opened
* toplevel window will be sent via the toplevel event
* @section page_iface_zwlr_foreign_toplevel_manager_v1_api API
* See @ref iface_zwlr_foreign_toplevel_manager_v1.
*/
/**
* @defgroup iface_zwlr_foreign_toplevel_manager_v1 The zwlr_foreign_toplevel_manager_v1 interface
*
* The purpose of this protocol is to enable the creation of taskbars
* and docks by providing them with a list of opened applications and
* letting them request certain actions on them, like maximizing, etc.
*
* After a client binds the zwlr_foreign_toplevel_manager_v1, each opened
* toplevel window will be sent via the toplevel event
*/
extern const struct wl_interface zwlr_foreign_toplevel_manager_v1_interface;
/**
* @page page_iface_zwlr_foreign_toplevel_handle_v1 zwlr_foreign_toplevel_handle_v1
* @section page_iface_zwlr_foreign_toplevel_handle_v1_desc Description
*
* A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel
* window. Each app may have multiple opened toplevels.
*
* Each toplevel has a list of outputs it is visible on, conveyed to the
* client with the output_enter and output_leave events.
* @section page_iface_zwlr_foreign_toplevel_handle_v1_api API
* See @ref iface_zwlr_foreign_toplevel_handle_v1.
*/
/**
* @defgroup iface_zwlr_foreign_toplevel_handle_v1 The zwlr_foreign_toplevel_handle_v1 interface
*
* A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel
* window. Each app may have multiple opened toplevels.
*
* Each toplevel has a list of outputs it is visible on, conveyed to the
* client with the output_enter and output_leave events.
*/
extern const struct wl_interface zwlr_foreign_toplevel_handle_v1_interface;
/**
* @ingroup iface_zwlr_foreign_toplevel_manager_v1
* @struct zwlr_foreign_toplevel_manager_v1_listener
*/
struct zwlr_foreign_toplevel_manager_v1_listener {
/**
* a toplevel has been created
*
* This event is emitted whenever a new toplevel window is
* created. It is emitted for all toplevels, regardless of the app
* that has created them.
*
* All initial details of the toplevel(title, app_id, states, etc.)
* will be sent immediately after this event via the corresponding
* events in zwlr_foreign_toplevel_handle_v1.
*/
void (*toplevel)(void *data,
struct zwlr_foreign_toplevel_manager_v1 *zwlr_foreign_toplevel_manager_v1,
struct zwlr_foreign_toplevel_handle_v1 *toplevel);
/**
* the compositor has finished with the toplevel manager
*
* This event indicates that the compositor is done sending
* events to the zwlr_foreign_toplevel_manager_v1. The server will
* destroy the object immediately after sending this request, so it
* will become invalid and the client should free any resources
* associated with it.
*/
void (*finished)(void *data,
struct zwlr_foreign_toplevel_manager_v1 *zwlr_foreign_toplevel_manager_v1);
};
/**
* @ingroup iface_zwlr_foreign_toplevel_manager_v1
*/
static inline int
zwlr_foreign_toplevel_manager_v1_add_listener(struct zwlr_foreign_toplevel_manager_v1 *zwlr_foreign_toplevel_manager_v1,
const struct zwlr_foreign_toplevel_manager_v1_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) zwlr_foreign_toplevel_manager_v1,
(void (**)(void)) listener, data);
}
#define ZWLR_FOREIGN_TOPLEVEL_MANAGER_V1_STOP 0
/**
* @ingroup iface_zwlr_foreign_toplevel_manager_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_MANAGER_V1_TOPLEVEL_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_manager_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_MANAGER_V1_FINISHED_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_manager_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_MANAGER_V1_STOP_SINCE_VERSION 1
/** @ingroup iface_zwlr_foreign_toplevel_manager_v1 */
static inline void
zwlr_foreign_toplevel_manager_v1_set_user_data(struct zwlr_foreign_toplevel_manager_v1 *zwlr_foreign_toplevel_manager_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwlr_foreign_toplevel_manager_v1, user_data);
}
/** @ingroup iface_zwlr_foreign_toplevel_manager_v1 */
static inline void *
zwlr_foreign_toplevel_manager_v1_get_user_data(struct zwlr_foreign_toplevel_manager_v1 *zwlr_foreign_toplevel_manager_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwlr_foreign_toplevel_manager_v1);
}
static inline uint32_t
zwlr_foreign_toplevel_manager_v1_get_version(struct zwlr_foreign_toplevel_manager_v1 *zwlr_foreign_toplevel_manager_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwlr_foreign_toplevel_manager_v1);
}
/** @ingroup iface_zwlr_foreign_toplevel_manager_v1 */
static inline void
zwlr_foreign_toplevel_manager_v1_destroy(struct zwlr_foreign_toplevel_manager_v1 *zwlr_foreign_toplevel_manager_v1)
{
wl_proxy_destroy((struct wl_proxy *) zwlr_foreign_toplevel_manager_v1);
}
/**
* @ingroup iface_zwlr_foreign_toplevel_manager_v1
*
* Indicates the client no longer wishes to receive events for new toplevels.
* However the compositor may emit further toplevel_created events, until
* the finished event is emitted.
*
* The client must not send any more requests after this one.
*/
static inline void
zwlr_foreign_toplevel_manager_v1_stop(struct zwlr_foreign_toplevel_manager_v1 *zwlr_foreign_toplevel_manager_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_foreign_toplevel_manager_v1,
ZWLR_FOREIGN_TOPLEVEL_MANAGER_V1_STOP);
}
#ifndef ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ENUM
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ENUM
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
* types of states on the toplevel
*
* The different states that a toplevel can have. These have the same meaning
* as the states with the same names defined in xdg-toplevel
*/
enum zwlr_foreign_toplevel_handle_v1_state {
/**
* the toplevel is maximized
*/
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED = 0,
/**
* the toplevel is minimized
*/
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MINIMIZED = 1,
/**
* the toplevel is active
*/
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED = 2,
/**
* the toplevel is fullscreen
* @since 2
*/
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN = 3,
};
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN_SINCE_VERSION 2
#endif /* ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ENUM */
#ifndef ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_ERROR_ENUM
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_ERROR_ENUM
enum zwlr_foreign_toplevel_handle_v1_error {
/**
* the provided rectangle is invalid
*/
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_ERROR_INVALID_RECTANGLE = 0,
};
#endif /* ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_ERROR_ENUM */
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
* @struct zwlr_foreign_toplevel_handle_v1_listener
*/
struct zwlr_foreign_toplevel_handle_v1_listener {
/**
* title change
*
* This event is emitted whenever the title of the toplevel
* changes.
*/
void (*title)(void *data,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1,
const char *title);
/**
* app-id change
*
* This event is emitted whenever the app-id of the toplevel
* changes.
*/
void (*app_id)(void *data,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1,
const char *app_id);
/**
* toplevel entered an output
*
* This event is emitted whenever the toplevel becomes visible on
* the given output. A toplevel may be visible on multiple outputs.
*/
void (*output_enter)(void *data,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1,
struct wl_output *output);
/**
* toplevel left an output
*
* This event is emitted whenever the toplevel stops being
* visible on the given output. It is guaranteed that an
* entered-output event with the same output has been emitted
* before this event.
*/
void (*output_leave)(void *data,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1,
struct wl_output *output);
/**
* the toplevel state changed
*
* This event is emitted immediately after the
* zlw_foreign_toplevel_handle_v1 is created and each time the
* toplevel state changes, either because of a compositor action or
* because of a request in this protocol.
*/
void (*state)(void *data,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1,
struct wl_array *state);
/**
* all information about the toplevel has been sent
*
* This event is sent after all changes in the toplevel state
* have been sent.
*
* This allows changes to the zwlr_foreign_toplevel_handle_v1
* properties to be seen as atomic, even if they happen via
* multiple events.
*/
void (*done)(void *data,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1);
/**
* this toplevel has been destroyed
*
* This event means the toplevel has been destroyed. It is
* guaranteed there won't be any more events for this
* zwlr_foreign_toplevel_handle_v1. The toplevel itself becomes
* inert so any requests will be ignored except the destroy
* request.
*/
void (*closed)(void *data,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1);
/**
* parent change
*
* This event is emitted whenever the parent of the toplevel
* changes.
*
* No event is emitted when the parent handle is destroyed by the
* client.
* @since 3
*/
void (*parent)(void *data,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1,
struct zwlr_foreign_toplevel_handle_v1 *parent);
};
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
static inline int
zwlr_foreign_toplevel_handle_v1_add_listener(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1,
const struct zwlr_foreign_toplevel_handle_v1_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1,
(void (**)(void)) listener, data);
}
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SET_MAXIMIZED 0
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_UNSET_MAXIMIZED 1
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SET_MINIMIZED 2
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_UNSET_MINIMIZED 3
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_ACTIVATE 4
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_CLOSE 5
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SET_RECTANGLE 6
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_DESTROY 7
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SET_FULLSCREEN 8
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_UNSET_FULLSCREEN 9
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_TITLE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_APP_ID_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_OUTPUT_ENTER_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_OUTPUT_LEAVE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_DONE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_CLOSED_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_PARENT_SINCE_VERSION 3
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SET_MAXIMIZED_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_UNSET_MAXIMIZED_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SET_MINIMIZED_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_UNSET_MINIMIZED_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_ACTIVATE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_CLOSE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SET_RECTANGLE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SET_FULLSCREEN_SINCE_VERSION 2
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*/
#define ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_UNSET_FULLSCREEN_SINCE_VERSION 2
/** @ingroup iface_zwlr_foreign_toplevel_handle_v1 */
static inline void
zwlr_foreign_toplevel_handle_v1_set_user_data(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1, user_data);
}
/** @ingroup iface_zwlr_foreign_toplevel_handle_v1 */
static inline void *
zwlr_foreign_toplevel_handle_v1_get_user_data(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1);
}
static inline uint32_t
zwlr_foreign_toplevel_handle_v1_get_version(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1);
}
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*
* Requests that the toplevel be maximized. If the maximized state actually
* changes, this will be indicated by the state event.
*/
static inline void
zwlr_foreign_toplevel_handle_v1_set_maximized(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1,
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SET_MAXIMIZED);
}
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*
* Requests that the toplevel be unmaximized. If the maximized state actually
* changes, this will be indicated by the state event.
*/
static inline void
zwlr_foreign_toplevel_handle_v1_unset_maximized(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1,
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_UNSET_MAXIMIZED);
}
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*
* Requests that the toplevel be minimized. If the minimized state actually
* changes, this will be indicated by the state event.
*/
static inline void
zwlr_foreign_toplevel_handle_v1_set_minimized(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1,
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SET_MINIMIZED);
}
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*
* Requests that the toplevel be unminimized. If the minimized state actually
* changes, this will be indicated by the state event.
*/
static inline void
zwlr_foreign_toplevel_handle_v1_unset_minimized(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1,
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_UNSET_MINIMIZED);
}
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*
* Request that this toplevel be activated on the given seat.
* There is no guarantee the toplevel will be actually activated.
*/
static inline void
zwlr_foreign_toplevel_handle_v1_activate(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1, struct wl_seat *seat)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1,
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_ACTIVATE, seat);
}
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*
* Send a request to the toplevel to close itself. The compositor would
* typically use a shell-specific method to carry out this request, for
* example by sending the xdg_toplevel.close event. However, this gives
* no guarantees the toplevel will actually be destroyed. If and when
* this happens, the zwlr_foreign_toplevel_handle_v1.closed event will
* be emitted.
*/
static inline void
zwlr_foreign_toplevel_handle_v1_close(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1,
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_CLOSE);
}
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*
* The rectangle of the surface specified in this request corresponds to
* the place where the app using this protocol represents the given toplevel.
* It can be used by the compositor as a hint for some operations, e.g
* minimizing. The client is however not required to set this, in which
* case the compositor is free to decide some default value.
*
* If the client specifies more than one rectangle, only the last one is
* considered.
*
* The dimensions are given in surface-local coordinates.
* Setting width=height=0 removes the already-set rectangle.
*/
static inline void
zwlr_foreign_toplevel_handle_v1_set_rectangle(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1, struct wl_surface *surface, int32_t x, int32_t y, int32_t width, int32_t height)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1,
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SET_RECTANGLE, surface, x, y, width, height);
}
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*
* Destroys the zwlr_foreign_toplevel_handle_v1 object.
*
* This request should be called either when the client does not want to
* use the toplevel anymore or after the closed event to finalize the
* destruction of the object.
*/
static inline void
zwlr_foreign_toplevel_handle_v1_destroy(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1,
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1);
}
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*
* Requests that the toplevel be fullscreened on the given output. If the
* fullscreen state and/or the outputs the toplevel is visible on actually
* change, this will be indicated by the state and output_enter/leave
* events.
*
* The output parameter is only a hint to the compositor. Also, if output
* is NULL, the compositor should decide which output the toplevel will be
* fullscreened on, if at all.
*/
static inline void
zwlr_foreign_toplevel_handle_v1_set_fullscreen(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1, struct wl_output *output)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1,
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SET_FULLSCREEN, output);
}
/**
* @ingroup iface_zwlr_foreign_toplevel_handle_v1
*
* Requests that the toplevel be unfullscreened. If the fullscreen state
* actually changes, this will be indicated by the state event.
*/
static inline void
zwlr_foreign_toplevel_handle_v1_unset_fullscreen(struct zwlr_foreign_toplevel_handle_v1 *zwlr_foreign_toplevel_handle_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_foreign_toplevel_handle_v1,
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_UNSET_FULLSCREEN);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,106 +0,0 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2018 Ilia Bozhinov
*
* Permission to use, copy, modify, distribute, and sell this
* software and its documentation for any purpose is hereby granted
* without fee, provided that the above copyright notice appear in
* all copies and that both that copyright notice and this permission
* notice appear in supporting documentation, and that the name of
* the copyright holders not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
* THIS SOFTWARE.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface zwlr_foreign_toplevel_handle_v1_interface;
static const struct wl_interface *wlr_foreign_toplevel_management_unstable_v1_types[] = {
NULL,
&zwlr_foreign_toplevel_handle_v1_interface,
&wl_seat_interface,
&wl_surface_interface,
NULL,
NULL,
NULL,
NULL,
&wl_output_interface,
&wl_output_interface,
&wl_output_interface,
&zwlr_foreign_toplevel_handle_v1_interface,
};
static const struct wl_message zwlr_foreign_toplevel_manager_v1_requests[] = {
{ "stop", "", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
};
static const struct wl_message zwlr_foreign_toplevel_manager_v1_events[] = {
{ "toplevel", "n", wlr_foreign_toplevel_management_unstable_v1_types + 1 },
{ "finished", "", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zwlr_foreign_toplevel_manager_v1_interface = {
"zwlr_foreign_toplevel_manager_v1", 3,
1, zwlr_foreign_toplevel_manager_v1_requests,
2, zwlr_foreign_toplevel_manager_v1_events,
};
static const struct wl_message zwlr_foreign_toplevel_handle_v1_requests[] = {
{ "set_maximized", "", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
{ "unset_maximized", "", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
{ "set_minimized", "", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
{ "unset_minimized", "", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
{ "activate", "o", wlr_foreign_toplevel_management_unstable_v1_types + 2 },
{ "close", "", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
{ "set_rectangle", "oiiii", wlr_foreign_toplevel_management_unstable_v1_types + 3 },
{ "destroy", "", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
{ "set_fullscreen", "2?o", wlr_foreign_toplevel_management_unstable_v1_types + 8 },
{ "unset_fullscreen", "2", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
};
static const struct wl_message zwlr_foreign_toplevel_handle_v1_events[] = {
{ "title", "s", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
{ "app_id", "s", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
{ "output_enter", "o", wlr_foreign_toplevel_management_unstable_v1_types + 9 },
{ "output_leave", "o", wlr_foreign_toplevel_management_unstable_v1_types + 10 },
{ "state", "a", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
{ "done", "", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
{ "closed", "", wlr_foreign_toplevel_management_unstable_v1_types + 0 },
{ "parent", "3?o", wlr_foreign_toplevel_management_unstable_v1_types + 11 },
};
WL_PRIVATE const struct wl_interface zwlr_foreign_toplevel_handle_v1_interface = {
"zwlr_foreign_toplevel_handle_v1", 3,
10, zwlr_foreign_toplevel_handle_v1_requests,
8, zwlr_foreign_toplevel_handle_v1_events,
};

View File

@ -1,270 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wlr_foreign_toplevel_management_unstable_v1">
<copyright>
Copyright © 2018 Ilia Bozhinov
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="zwlr_foreign_toplevel_manager_v1" version="3">
<description summary="list and control opened apps">
The purpose of this protocol is to enable the creation of taskbars
and docks by providing them with a list of opened applications and
letting them request certain actions on them, like maximizing, etc.
After a client binds the zwlr_foreign_toplevel_manager_v1, each opened
toplevel window will be sent via the toplevel event
</description>
<event name="toplevel">
<description summary="a toplevel has been created">
This event is emitted whenever a new toplevel window is created. It
is emitted for all toplevels, regardless of the app that has created
them.
All initial details of the toplevel(title, app_id, states, etc.) will
be sent immediately after this event via the corresponding events in
zwlr_foreign_toplevel_handle_v1.
</description>
<arg name="toplevel" type="new_id" interface="zwlr_foreign_toplevel_handle_v1"/>
</event>
<request name="stop">
<description summary="stop sending events">
Indicates the client no longer wishes to receive events for new toplevels.
However the compositor may emit further toplevel_created events, until
the finished event is emitted.
The client must not send any more requests after this one.
</description>
</request>
<event name="finished">
<description summary="the compositor has finished with the toplevel manager">
This event indicates that the compositor is done sending events to the
zwlr_foreign_toplevel_manager_v1. The server will destroy the object
immediately after sending this request, so it will become invalid and
the client should free any resources associated with it.
</description>
</event>
</interface>
<interface name="zwlr_foreign_toplevel_handle_v1" version="3">
<description summary="an opened toplevel">
A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel
window. Each app may have multiple opened toplevels.
Each toplevel has a list of outputs it is visible on, conveyed to the
client with the output_enter and output_leave events.
</description>
<event name="title">
<description summary="title change">
This event is emitted whenever the title of the toplevel changes.
</description>
<arg name="title" type="string"/>
</event>
<event name="app_id">
<description summary="app-id change">
This event is emitted whenever the app-id of the toplevel changes.
</description>
<arg name="app_id" type="string"/>
</event>
<event name="output_enter">
<description summary="toplevel entered an output">
This event is emitted whenever the toplevel becomes visible on
the given output. A toplevel may be visible on multiple outputs.
</description>
<arg name="output" type="object" interface="wl_output"/>
</event>
<event name="output_leave">
<description summary="toplevel left an output">
This event is emitted whenever the toplevel stops being visible on
the given output. It is guaranteed that an entered-output event
with the same output has been emitted before this event.
</description>
<arg name="output" type="object" interface="wl_output"/>
</event>
<request name="set_maximized">
<description summary="requests that the toplevel be maximized">
Requests that the toplevel be maximized. If the maximized state actually
changes, this will be indicated by the state event.
</description>
</request>
<request name="unset_maximized">
<description summary="requests that the toplevel be unmaximized">
Requests that the toplevel be unmaximized. If the maximized state actually
changes, this will be indicated by the state event.
</description>
</request>
<request name="set_minimized">
<description summary="requests that the toplevel be minimized">
Requests that the toplevel be minimized. If the minimized state actually
changes, this will be indicated by the state event.
</description>
</request>
<request name="unset_minimized">
<description summary="requests that the toplevel be unminimized">
Requests that the toplevel be unminimized. If the minimized state actually
changes, this will be indicated by the state event.
</description>
</request>
<request name="activate">
<description summary="activate the toplevel">
Request that this toplevel be activated on the given seat.
There is no guarantee the toplevel will be actually activated.
</description>
<arg name="seat" type="object" interface="wl_seat"/>
</request>
<enum name="state">
<description summary="types of states on the toplevel">
The different states that a toplevel can have. These have the same meaning
as the states with the same names defined in xdg-toplevel
</description>
<entry name="maximized" value="0" summary="the toplevel is maximized"/>
<entry name="minimized" value="1" summary="the toplevel is minimized"/>
<entry name="activated" value="2" summary="the toplevel is active"/>
<entry name="fullscreen" value="3" summary="the toplevel is fullscreen" since="2"/>
</enum>
<event name="state">
<description summary="the toplevel state changed">
This event is emitted immediately after the zlw_foreign_toplevel_handle_v1
is created and each time the toplevel state changes, either because of a
compositor action or because of a request in this protocol.
</description>
<arg name="state" type="array"/>
</event>
<event name="done">
<description summary="all information about the toplevel has been sent">
This event is sent after all changes in the toplevel state have been
sent.
This allows changes to the zwlr_foreign_toplevel_handle_v1 properties
to be seen as atomic, even if they happen via multiple events.
</description>
</event>
<request name="close">
<description summary="request that the toplevel be closed">
Send a request to the toplevel to close itself. The compositor would
typically use a shell-specific method to carry out this request, for
example by sending the xdg_toplevel.close event. However, this gives
no guarantees the toplevel will actually be destroyed. If and when
this happens, the zwlr_foreign_toplevel_handle_v1.closed event will
be emitted.
</description>
</request>
<request name="set_rectangle">
<description summary="the rectangle which represents the toplevel">
The rectangle of the surface specified in this request corresponds to
the place where the app using this protocol represents the given toplevel.
It can be used by the compositor as a hint for some operations, e.g
minimizing. The client is however not required to set this, in which
case the compositor is free to decide some default value.
If the client specifies more than one rectangle, only the last one is
considered.
The dimensions are given in surface-local coordinates.
Setting width=height=0 removes the already-set rectangle.
</description>
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="x" type="int"/>
<arg name="y" type="int"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
</request>
<enum name="error">
<entry name="invalid_rectangle" value="0"
summary="the provided rectangle is invalid"/>
</enum>
<event name="closed">
<description summary="this toplevel has been destroyed">
This event means the toplevel has been destroyed. It is guaranteed there
won't be any more events for this zwlr_foreign_toplevel_handle_v1. The
toplevel itself becomes inert so any requests will be ignored except the
destroy request.
</description>
</event>
<request name="destroy" type="destructor">
<description summary="destroy the zwlr_foreign_toplevel_handle_v1 object">
Destroys the zwlr_foreign_toplevel_handle_v1 object.
This request should be called either when the client does not want to
use the toplevel anymore or after the closed event to finalize the
destruction of the object.
</description>
</request>
<!-- Version 2 additions -->
<request name="set_fullscreen" since="2">
<description summary="request that the toplevel be fullscreened">
Requests that the toplevel be fullscreened on the given output. If the
fullscreen state and/or the outputs the toplevel is visible on actually
change, this will be indicated by the state and output_enter/leave
events.
The output parameter is only a hint to the compositor. Also, if output
is NULL, the compositor should decide which output the toplevel will be
fullscreened on, if at all.
</description>
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
</request>
<request name="unset_fullscreen" since="2">
<description summary="request that the toplevel be unfullscreened">
Requests that the toplevel be unfullscreened. If the fullscreen state
actually changes, this will be indicated by the state event.
</description>
</request>
<!-- Version 3 additions -->
<event name="parent" since="3">
<description summary="parent change">
This event is emitted whenever the parent of the toplevel changes.
No event is emitted when the parent handle is destroyed by the client.
</description>
<arg name="parent" type="object" interface="zwlr_foreign_toplevel_handle_v1" allow-null="true"/>
</event>
</interface>
</protocol>

View File

@ -1,559 +0,0 @@
/* Generated by wayland-scanner 1.18.0 */
#ifndef WLR_LAYER_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H
#define WLR_LAYER_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_wlr_layer_shell_unstable_v1 The wlr_layer_shell_unstable_v1 protocol
* @section page_ifaces_wlr_layer_shell_unstable_v1 Interfaces
* - @subpage page_iface_zwlr_layer_shell_v1 - create surfaces that are layers of the desktop
* - @subpage page_iface_zwlr_layer_surface_v1 - layer metadata interface
* @section page_copyright_wlr_layer_shell_unstable_v1 Copyright
* <pre>
*
* Copyright © 2017 Drew DeVault
*
* Permission to use, copy, modify, distribute, and sell this
* software and its documentation for any purpose is hereby granted
* without fee, provided that the above copyright notice appear in
* all copies and that both that copyright notice and this permission
* notice appear in supporting documentation, and that the name of
* the copyright holders not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
* THIS SOFTWARE.
* </pre>
*/
struct wl_output;
struct wl_surface;
struct xdg_popup;
struct zwlr_layer_shell_v1;
struct zwlr_layer_surface_v1;
/**
* @page page_iface_zwlr_layer_shell_v1 zwlr_layer_shell_v1
* @section page_iface_zwlr_layer_shell_v1_desc Description
*
* Clients can use this interface to assign the surface_layer role to
* wl_surfaces. Such surfaces are assigned to a "layer" of the output and
* rendered with a defined z-depth respective to each other. They may also be
* anchored to the edges and corners of a screen and specify input handling
* semantics. This interface should be suitable for the implementation of
* many desktop shell components, and a broad number of other applications
* that interact with the desktop.
* @section page_iface_zwlr_layer_shell_v1_api API
* See @ref iface_zwlr_layer_shell_v1.
*/
/**
* @defgroup iface_zwlr_layer_shell_v1 The zwlr_layer_shell_v1 interface
*
* Clients can use this interface to assign the surface_layer role to
* wl_surfaces. Such surfaces are assigned to a "layer" of the output and
* rendered with a defined z-depth respective to each other. They may also be
* anchored to the edges and corners of a screen and specify input handling
* semantics. This interface should be suitable for the implementation of
* many desktop shell components, and a broad number of other applications
* that interact with the desktop.
*/
extern const struct wl_interface zwlr_layer_shell_v1_interface;
/**
* @page page_iface_zwlr_layer_surface_v1 zwlr_layer_surface_v1
* @section page_iface_zwlr_layer_surface_v1_desc Description
*
* An interface that may be implemented by a wl_surface, for surfaces that
* are designed to be rendered as a layer of a stacked desktop-like
* environment.
*
* Layer surface state (size, anchor, exclusive zone, margin, interactivity)
* is double-buffered, and will be applied at the time wl_surface.commit of
* the corresponding wl_surface is called.
* @section page_iface_zwlr_layer_surface_v1_api API
* See @ref iface_zwlr_layer_surface_v1.
*/
/**
* @defgroup iface_zwlr_layer_surface_v1 The zwlr_layer_surface_v1 interface
*
* An interface that may be implemented by a wl_surface, for surfaces that
* are designed to be rendered as a layer of a stacked desktop-like
* environment.
*
* Layer surface state (size, anchor, exclusive zone, margin, interactivity)
* is double-buffered, and will be applied at the time wl_surface.commit of
* the corresponding wl_surface is called.
*/
extern const struct wl_interface zwlr_layer_surface_v1_interface;
#ifndef ZWLR_LAYER_SHELL_V1_ERROR_ENUM
#define ZWLR_LAYER_SHELL_V1_ERROR_ENUM
enum zwlr_layer_shell_v1_error {
/**
* wl_surface has another role
*/
ZWLR_LAYER_SHELL_V1_ERROR_ROLE = 0,
/**
* layer value is invalid
*/
ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER = 1,
/**
* wl_surface has a buffer attached or committed
*/
ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED = 2,
};
#endif /* ZWLR_LAYER_SHELL_V1_ERROR_ENUM */
#ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM
#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM
/**
* @ingroup iface_zwlr_layer_shell_v1
* available layers for surfaces
*
* These values indicate which layers a surface can be rendered in. They
* are ordered by z depth, bottom-most first. Traditional shell surfaces
* will typically be rendered between the bottom and top layers.
* Fullscreen shell surfaces are typically rendered at the top layer.
* Multiple surfaces can share a single layer, and ordering within a
* single layer is undefined.
*/
enum zwlr_layer_shell_v1_layer {
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0,
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1,
ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2,
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3,
};
#endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */
#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE 0
/**
* @ingroup iface_zwlr_layer_shell_v1
*/
#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE_SINCE_VERSION 1
/** @ingroup iface_zwlr_layer_shell_v1 */
static inline void
zwlr_layer_shell_v1_set_user_data(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwlr_layer_shell_v1, user_data);
}
/** @ingroup iface_zwlr_layer_shell_v1 */
static inline void *
zwlr_layer_shell_v1_get_user_data(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwlr_layer_shell_v1);
}
static inline uint32_t
zwlr_layer_shell_v1_get_version(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwlr_layer_shell_v1);
}
/** @ingroup iface_zwlr_layer_shell_v1 */
static inline void
zwlr_layer_shell_v1_destroy(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1)
{
wl_proxy_destroy((struct wl_proxy *) zwlr_layer_shell_v1);
}
/**
* @ingroup iface_zwlr_layer_shell_v1
*
* Create a layer surface for an existing surface. This assigns the role of
* layer_surface, or raises a protocol error if another role is already
* assigned.
*
* Creating a layer surface from a wl_surface which has a buffer attached
* or committed is a client error, and any attempts by a client to attach
* or manipulate a buffer prior to the first layer_surface.configure call
* must also be treated as errors.
*
* You may pass NULL for output to allow the compositor to decide which
* output to use. Generally this will be the one that the user most
* recently interacted with.
*
* Clients can specify a namespace that defines the purpose of the layer
* surface.
*/
static inline struct zwlr_layer_surface_v1 *
zwlr_layer_shell_v1_get_layer_surface(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1, struct wl_surface *surface, struct wl_output *output, uint32_t layer, const char *namespace)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) zwlr_layer_shell_v1,
ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE, &zwlr_layer_surface_v1_interface, NULL, surface, output, layer, namespace);
return (struct zwlr_layer_surface_v1 *) id;
}
#ifndef ZWLR_LAYER_SURFACE_V1_ERROR_ENUM
#define ZWLR_LAYER_SURFACE_V1_ERROR_ENUM
enum zwlr_layer_surface_v1_error {
/**
* provided surface state is invalid
*/
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE = 0,
/**
* size is invalid
*/
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE = 1,
/**
* anchor bitfield is invalid
*/
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR = 2,
};
#endif /* ZWLR_LAYER_SURFACE_V1_ERROR_ENUM */
#ifndef ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM
#define ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM
enum zwlr_layer_surface_v1_anchor {
/**
* the top edge of the anchor rectangle
*/
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP = 1,
/**
* the bottom edge of the anchor rectangle
*/
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM = 2,
/**
* the left edge of the anchor rectangle
*/
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT = 4,
/**
* the right edge of the anchor rectangle
*/
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT = 8,
};
#endif /* ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM */
/**
* @ingroup iface_zwlr_layer_surface_v1
* @struct zwlr_layer_surface_v1_listener
*/
struct zwlr_layer_surface_v1_listener {
/**
* suggest a surface change
*
* The configure event asks the client to resize its surface.
*
* Clients should arrange their surface for the new states, and
* then send an ack_configure request with the serial sent in this
* configure event at some point before committing the new surface.
*
* The client is free to dismiss all but the last configure event
* it received.
*
* The width and height arguments specify the size of the window in
* surface-local coordinates.
*
* The size is a hint, in the sense that the client is free to
* ignore it if it doesn't resize, pick a smaller size (to satisfy
* aspect ratio or resize in steps of NxM pixels). If the client
* picks a smaller size and is anchored to two opposite anchors
* (e.g. 'top' and 'bottom'), the surface will be centered on this
* axis.
*
* If the width or height arguments are zero, it means the client
* should decide its own window dimension.
*/
void (*configure)(void *data,
struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1,
uint32_t serial,
uint32_t width,
uint32_t height);
/**
* surface should be closed
*
* The closed event is sent by the compositor when the surface
* will no longer be shown. The output may have been destroyed or
* the user may have asked for it to be removed. Further changes to
* the surface will be ignored. The client should destroy the
* resource after receiving this event, and create a new surface if
* they so choose.
*/
void (*closed)(void *data,
struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1);
};
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
static inline int
zwlr_layer_surface_v1_add_listener(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1,
const struct zwlr_layer_surface_v1_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) zwlr_layer_surface_v1,
(void (**)(void)) listener, data);
}
#define ZWLR_LAYER_SURFACE_V1_SET_SIZE 0
#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR 1
#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE 2
#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN 3
#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY 4
#define ZWLR_LAYER_SURFACE_V1_GET_POPUP 5
#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE 6
#define ZWLR_LAYER_SURFACE_V1_DESTROY 7
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_CONFIGURE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_CLOSED_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_SIZE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_GET_POPUP_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_DESTROY_SINCE_VERSION 1
/** @ingroup iface_zwlr_layer_surface_v1 */
static inline void
zwlr_layer_surface_v1_set_user_data(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwlr_layer_surface_v1, user_data);
}
/** @ingroup iface_zwlr_layer_surface_v1 */
static inline void *
zwlr_layer_surface_v1_get_user_data(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwlr_layer_surface_v1);
}
static inline uint32_t
zwlr_layer_surface_v1_get_version(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Sets the size of the surface in surface-local coordinates. The
* compositor will display the surface centered with respect to its
* anchors.
*
* If you pass 0 for either value, the compositor will assign it and
* inform you of the assignment in the configure event. You must set your
* anchor to opposite edges in the dimensions you omit; not doing so is a
* protocol error. Both values are 0 by default.
*
* Size is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_size(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t width, uint32_t height)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_SIZE, width, height);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Requests that the compositor anchor the surface to the specified edges
* and corners. If two orthoginal edges are specified (e.g. 'top' and
* 'left'), then the anchor point will be the intersection of the edges
* (e.g. the top left corner of the output); otherwise the anchor point
* will be centered on that edge, or in the center if none is specified.
*
* Anchor is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_anchor(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t anchor)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_ANCHOR, anchor);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Requests that the compositor avoids occluding an area of the surface
* with other surfaces. The compositor's use of this information is
* implementation-dependent - do not assume that this region will not
* actually be occluded.
*
* A positive value is only meaningful if the surface is anchored to an
* edge, rather than a corner. The zone is the number of surface-local
* coordinates from the edge that are considered exclusive.
*
* Surfaces that do not wish to have an exclusive zone may instead specify
* how they should interact with surfaces that do. If set to zero, the
* surface indicates that it would like to be moved to avoid occluding
* surfaces with a positive excluzive zone. If set to -1, the surface
* indicates that it would not like to be moved to accomodate for other
* surfaces, and the compositor should extend it all the way to the edges
* it is anchored to.
*
* For example, a panel might set its exclusive zone to 10, so that
* maximized shell surfaces are not shown on top of it. A notification
* might set its exclusive zone to 0, so that it is moved to avoid
* occluding the panel, but shell surfaces are shown underneath it. A
* wallpaper or lock screen might set their exclusive zone to -1, so that
* they stretch below or over the panel.
*
* The default value is 0.
*
* Exclusive zone is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_exclusive_zone(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, int32_t zone)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE, zone);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Requests that the surface be placed some distance away from the anchor
* point on the output, in surface-local coordinates. Setting this value
* for edges you are not anchored to has no effect.
*
* The exclusive zone includes the margin.
*
* Margin is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_margin(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, int32_t top, int32_t right, int32_t bottom, int32_t left)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_MARGIN, top, right, bottom, left);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Set to 1 to request that the seat send keyboard events to this layer
* surface. For layers below the shell surface layer, the seat will use
* normal focus semantics. For layers above the shell surface layers, the
* seat will always give exclusive keyboard focus to the top-most layer
* which has keyboard interactivity set to true.
*
* Layer surfaces receive pointer, touch, and tablet events normally. If
* you do not want to receive them, set the input region on your surface
* to an empty region.
*
* Events is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_keyboard_interactivity(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t keyboard_interactivity)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY, keyboard_interactivity);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* This assigns an xdg_popup's parent to this layer_surface. This popup
* should have been created via xdg_surface::get_popup with the parent set
* to NULL, and this request must be invoked before committing the popup's
* initial state.
*
* See the documentation of xdg_popup for more details about what an
* xdg_popup is and how it is used.
*/
static inline void
zwlr_layer_surface_v1_get_popup(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, struct xdg_popup *popup)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_GET_POPUP, popup);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* When a configure event is received, if a client commits the
* surface in response to the configure event, then the client
* must make an ack_configure request sometime before the commit
* request, passing along the serial of the configure event.
*
* If the client receives multiple configure events before it
* can respond to one, it only has to ack the last configure event.
*
* A client is not required to commit immediately after sending
* an ack_configure request - it may even ack_configure several times
* before its next surface commit.
*
* A client may send multiple ack_configure requests before committing, but
* only the last request sent before a commit indicates which configure
* event the client really is responding to.
*/
static inline void
zwlr_layer_surface_v1_ack_configure(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t serial)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE, serial);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* This request destroys the layer surface.
*/
static inline void
zwlr_layer_surface_v1_destroy(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zwlr_layer_surface_v1);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,91 +0,0 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2017 Drew DeVault
*
* Permission to use, copy, modify, distribute, and sell this
* software and its documentation for any purpose is hereby granted
* without fee, provided that the above copyright notice appear in
* all copies and that both that copyright notice and this permission
* notice appear in supporting documentation, and that the name of
* the copyright holders not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
* THIS SOFTWARE.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface zwlr_layer_surface_v1_interface;
static const struct wl_interface *wlr_layer_shell_unstable_v1_types[] = {
NULL,
NULL,
NULL,
NULL,
&zwlr_layer_surface_v1_interface,
&wl_surface_interface,
&wl_output_interface,
NULL,
NULL,
&xdg_popup_interface,
};
static const struct wl_message zwlr_layer_shell_v1_requests[] = {
{ "get_layer_surface", "no?ous", wlr_layer_shell_unstable_v1_types + 4 },
};
WL_PRIVATE const struct wl_interface zwlr_layer_shell_v1_interface = {
"zwlr_layer_shell_v1", 1,
1, zwlr_layer_shell_v1_requests,
0, NULL,
};
static const struct wl_message zwlr_layer_surface_v1_requests[] = {
{ "set_size", "uu", wlr_layer_shell_unstable_v1_types + 0 },
{ "set_anchor", "u", wlr_layer_shell_unstable_v1_types + 0 },
{ "set_exclusive_zone", "i", wlr_layer_shell_unstable_v1_types + 0 },
{ "set_margin", "iiii", wlr_layer_shell_unstable_v1_types + 0 },
{ "set_keyboard_interactivity", "u", wlr_layer_shell_unstable_v1_types + 0 },
{ "get_popup", "o", wlr_layer_shell_unstable_v1_types + 9 },
{ "ack_configure", "u", wlr_layer_shell_unstable_v1_types + 0 },
{ "destroy", "", wlr_layer_shell_unstable_v1_types + 0 },
};
static const struct wl_message zwlr_layer_surface_v1_events[] = {
{ "configure", "uuu", wlr_layer_shell_unstable_v1_types + 0 },
{ "closed", "", wlr_layer_shell_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zwlr_layer_surface_v1_interface = {
"zwlr_layer_surface_v1", 1,
8, zwlr_layer_surface_v1_requests,
2, zwlr_layer_surface_v1_events,
};

View File

@ -1,285 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wlr_layer_shell_unstable_v1">
<copyright>
Copyright © 2017 Drew DeVault
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="zwlr_layer_shell_v1" version="1">
<description summary="create surfaces that are layers of the desktop">
Clients can use this interface to assign the surface_layer role to
wl_surfaces. Such surfaces are assigned to a "layer" of the output and
rendered with a defined z-depth respective to each other. They may also be
anchored to the edges and corners of a screen and specify input handling
semantics. This interface should be suitable for the implementation of
many desktop shell components, and a broad number of other applications
that interact with the desktop.
</description>
<request name="get_layer_surface">
<description summary="create a layer_surface from a surface">
Create a layer surface for an existing surface. This assigns the role of
layer_surface, or raises a protocol error if another role is already
assigned.
Creating a layer surface from a wl_surface which has a buffer attached
or committed is a client error, and any attempts by a client to attach
or manipulate a buffer prior to the first layer_surface.configure call
must also be treated as errors.
You may pass NULL for output to allow the compositor to decide which
output to use. Generally this will be the one that the user most
recently interacted with.
Clients can specify a namespace that defines the purpose of the layer
surface.
</description>
<arg name="id" type="new_id" interface="zwlr_layer_surface_v1"/>
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
<arg name="layer" type="uint" enum="layer" summary="layer to add this surface to"/>
<arg name="namespace" type="string" summary="namespace for the layer surface"/>
</request>
<enum name="error">
<entry name="role" value="0" summary="wl_surface has another role"/>
<entry name="invalid_layer" value="1" summary="layer value is invalid"/>
<entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/>
</enum>
<enum name="layer">
<description summary="available layers for surfaces">
These values indicate which layers a surface can be rendered in. They
are ordered by z depth, bottom-most first. Traditional shell surfaces
will typically be rendered between the bottom and top layers.
Fullscreen shell surfaces are typically rendered at the top layer.
Multiple surfaces can share a single layer, and ordering within a
single layer is undefined.
</description>
<entry name="background" value="0"/>
<entry name="bottom" value="1"/>
<entry name="top" value="2"/>
<entry name="overlay" value="3"/>
</enum>
</interface>
<interface name="zwlr_layer_surface_v1" version="1">
<description summary="layer metadata interface">
An interface that may be implemented by a wl_surface, for surfaces that
are designed to be rendered as a layer of a stacked desktop-like
environment.
Layer surface state (size, anchor, exclusive zone, margin, interactivity)
is double-buffered, and will be applied at the time wl_surface.commit of
the corresponding wl_surface is called.
</description>
<request name="set_size">
<description summary="sets the size of the surface">
Sets the size of the surface in surface-local coordinates. The
compositor will display the surface centered with respect to its
anchors.
If you pass 0 for either value, the compositor will assign it and
inform you of the assignment in the configure event. You must set your
anchor to opposite edges in the dimensions you omit; not doing so is a
protocol error. Both values are 0 by default.
Size is double-buffered, see wl_surface.commit.
</description>
<arg name="width" type="uint"/>
<arg name="height" type="uint"/>
</request>
<request name="set_anchor">
<description summary="configures the anchor point of the surface">
Requests that the compositor anchor the surface to the specified edges
and corners. If two orthoginal edges are specified (e.g. 'top' and
'left'), then the anchor point will be the intersection of the edges
(e.g. the top left corner of the output); otherwise the anchor point
will be centered on that edge, or in the center if none is specified.
Anchor is double-buffered, see wl_surface.commit.
</description>
<arg name="anchor" type="uint" enum="anchor"/>
</request>
<request name="set_exclusive_zone">
<description summary="configures the exclusive geometry of this surface">
Requests that the compositor avoids occluding an area of the surface
with other surfaces. The compositor's use of this information is
implementation-dependent - do not assume that this region will not
actually be occluded.
A positive value is only meaningful if the surface is anchored to an
edge, rather than a corner. The zone is the number of surface-local
coordinates from the edge that are considered exclusive.
Surfaces that do not wish to have an exclusive zone may instead specify
how they should interact with surfaces that do. If set to zero, the
surface indicates that it would like to be moved to avoid occluding
surfaces with a positive excluzive zone. If set to -1, the surface
indicates that it would not like to be moved to accomodate for other
surfaces, and the compositor should extend it all the way to the edges
it is anchored to.
For example, a panel might set its exclusive zone to 10, so that
maximized shell surfaces are not shown on top of it. A notification
might set its exclusive zone to 0, so that it is moved to avoid
occluding the panel, but shell surfaces are shown underneath it. A
wallpaper or lock screen might set their exclusive zone to -1, so that
they stretch below or over the panel.
The default value is 0.
Exclusive zone is double-buffered, see wl_surface.commit.
</description>
<arg name="zone" type="int"/>
</request>
<request name="set_margin">
<description summary="sets a margin from the anchor point">
Requests that the surface be placed some distance away from the anchor
point on the output, in surface-local coordinates. Setting this value
for edges you are not anchored to has no effect.
The exclusive zone includes the margin.
Margin is double-buffered, see wl_surface.commit.
</description>
<arg name="top" type="int"/>
<arg name="right" type="int"/>
<arg name="bottom" type="int"/>
<arg name="left" type="int"/>
</request>
<request name="set_keyboard_interactivity">
<description summary="requests keyboard events">
Set to 1 to request that the seat send keyboard events to this layer
surface. For layers below the shell surface layer, the seat will use
normal focus semantics. For layers above the shell surface layers, the
seat will always give exclusive keyboard focus to the top-most layer
which has keyboard interactivity set to true.
Layer surfaces receive pointer, touch, and tablet events normally. If
you do not want to receive them, set the input region on your surface
to an empty region.
Events is double-buffered, see wl_surface.commit.
</description>
<arg name="keyboard_interactivity" type="uint"/>
</request>
<request name="get_popup">
<description summary="assign this layer_surface as an xdg_popup parent">
This assigns an xdg_popup's parent to this layer_surface. This popup
should have been created via xdg_surface::get_popup with the parent set
to NULL, and this request must be invoked before committing the popup's
initial state.
See the documentation of xdg_popup for more details about what an
xdg_popup is and how it is used.
</description>
<arg name="popup" type="object" interface="xdg_popup"/>
</request>
<request name="ack_configure">
<description summary="ack a configure event">
When a configure event is received, if a client commits the
surface in response to the configure event, then the client
must make an ack_configure request sometime before the commit
request, passing along the serial of the configure event.
If the client receives multiple configure events before it
can respond to one, it only has to ack the last configure event.
A client is not required to commit immediately after sending
an ack_configure request - it may even ack_configure several times
before its next surface commit.
A client may send multiple ack_configure requests before committing, but
only the last request sent before a commit indicates which configure
event the client really is responding to.
</description>
<arg name="serial" type="uint" summary="the serial from the configure event"/>
</request>
<request name="destroy" type="destructor">
<description summary="destroy the layer_surface">
This request destroys the layer surface.
</description>
</request>
<event name="configure">
<description summary="suggest a surface change">
The configure event asks the client to resize its surface.
Clients should arrange their surface for the new states, and then send
an ack_configure request with the serial sent in this configure event at
some point before committing the new surface.
The client is free to dismiss all but the last configure event it
received.
The width and height arguments specify the size of the window in
surface-local coordinates.
The size is a hint, in the sense that the client is free to ignore it if
it doesn't resize, pick a smaller size (to satisfy aspect ratio or
resize in steps of NxM pixels). If the client picks a smaller size and
is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the
surface will be centered on this axis.
If the width or height arguments are zero, it means the client should
decide its own window dimension.
</description>
<arg name="serial" type="uint"/>
<arg name="width" type="uint"/>
<arg name="height" type="uint"/>
</event>
<event name="closed">
<description summary="surface should be closed">
The closed event is sent by the compositor when the surface will no
longer be shown. The output may have been destroyed or the user may
have asked for it to be removed. Further changes to the surface will be
ignored. The client should destroy the resource after receiving this
event, and create a new surface if they so choose.
</description>
</event>
<enum name="error">
<entry name="invalid_surface_state" value="0" summary="provided surface state is invalid"/>
<entry name="invalid_size" value="1" summary="size is invalid"/>
<entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/>
</enum>
<enum name="anchor" bitfield="true">
<entry name="top" value="1" summary="the top edge of the anchor rectangle"/>
<entry name="bottom" value="2" summary="the bottom edge of the anchor rectangle"/>
<entry name="left" value="4" summary="the left edge of the anchor rectangle"/>
<entry name="right" value="8" summary="the right edge of the anchor rectangle"/>
</enum>
</interface>
</protocol>

View File

@ -1,409 +0,0 @@
/* Generated by wayland-scanner 1.18.0 */
#ifndef XDG_OUTPUT_UNSTABLE_V1_CLIENT_PROTOCOL_H
#define XDG_OUTPUT_UNSTABLE_V1_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_xdg_output_unstable_v1 The xdg_output_unstable_v1 protocol
* Protocol to describe output regions
*
* @section page_desc_xdg_output_unstable_v1 Description
*
* This protocol aims at describing outputs in a way which is more in line
* with the concept of an output on desktop oriented systems.
*
* Some information are more specific to the concept of an output for
* a desktop oriented system and may not make sense in other applications,
* such as IVI systems for example.
*
* Typically, the global compositor space on a desktop system is made of
* a contiguous or overlapping set of rectangular regions.
*
* Some of the information provided in this protocol might be identical
* to their counterparts already available from wl_output, in which case
* the information provided by this protocol should be preferred to their
* equivalent in wl_output. The goal is to move the desktop specific
* concepts (such as output location within the global compositor space,
* the connector name and types, etc.) out of the core wl_output protocol.
*
* Warning! The protocol described in this file is experimental and
* backward incompatible changes may be made. Backward compatible
* changes may be added together with the corresponding interface
* version bump.
* Backward incompatible changes are done by bumping the version
* number in the protocol and interface names and resetting the
* interface version. Once the protocol is to be declared stable,
* the 'z' prefix and the version number in the protocol and
* interface names are removed and the interface version number is
* reset.
*
* @section page_ifaces_xdg_output_unstable_v1 Interfaces
* - @subpage page_iface_zxdg_output_manager_v1 - manage xdg_output objects
* - @subpage page_iface_zxdg_output_v1 - compositor logical output region
* @section page_copyright_xdg_output_unstable_v1 Copyright
* <pre>
*
* Copyright © 2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* 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.
* </pre>
*/
struct wl_output;
struct zxdg_output_manager_v1;
struct zxdg_output_v1;
/**
* @page page_iface_zxdg_output_manager_v1 zxdg_output_manager_v1
* @section page_iface_zxdg_output_manager_v1_desc Description
*
* A global factory interface for xdg_output objects.
* @section page_iface_zxdg_output_manager_v1_api API
* See @ref iface_zxdg_output_manager_v1.
*/
/**
* @defgroup iface_zxdg_output_manager_v1 The zxdg_output_manager_v1 interface
*
* A global factory interface for xdg_output objects.
*/
extern const struct wl_interface zxdg_output_manager_v1_interface;
/**
* @page page_iface_zxdg_output_v1 zxdg_output_v1
* @section page_iface_zxdg_output_v1_desc Description
*
* An xdg_output describes part of the compositor geometry.
*
* This typically corresponds to a monitor that displays part of the
* compositor space.
*
* For objects version 3 onwards, after all xdg_output properties have been
* sent (when the object is created and when properties are updated), a
* wl_output.done event is sent. This allows changes to the output
* properties to be seen as atomic, even if they happen via multiple events.
* @section page_iface_zxdg_output_v1_api API
* See @ref iface_zxdg_output_v1.
*/
/**
* @defgroup iface_zxdg_output_v1 The zxdg_output_v1 interface
*
* An xdg_output describes part of the compositor geometry.
*
* This typically corresponds to a monitor that displays part of the
* compositor space.
*
* For objects version 3 onwards, after all xdg_output properties have been
* sent (when the object is created and when properties are updated), a
* wl_output.done event is sent. This allows changes to the output
* properties to be seen as atomic, even if they happen via multiple events.
*/
extern const struct wl_interface zxdg_output_v1_interface;
#define ZXDG_OUTPUT_MANAGER_V1_DESTROY 0
#define ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT 1
/**
* @ingroup iface_zxdg_output_manager_v1
*/
#define ZXDG_OUTPUT_MANAGER_V1_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_output_manager_v1
*/
#define ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT_SINCE_VERSION 1
/** @ingroup iface_zxdg_output_manager_v1 */
static inline void
zxdg_output_manager_v1_set_user_data(struct zxdg_output_manager_v1 *zxdg_output_manager_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zxdg_output_manager_v1, user_data);
}
/** @ingroup iface_zxdg_output_manager_v1 */
static inline void *
zxdg_output_manager_v1_get_user_data(struct zxdg_output_manager_v1 *zxdg_output_manager_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zxdg_output_manager_v1);
}
static inline uint32_t
zxdg_output_manager_v1_get_version(struct zxdg_output_manager_v1 *zxdg_output_manager_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zxdg_output_manager_v1);
}
/**
* @ingroup iface_zxdg_output_manager_v1
*
* Using this request a client can tell the server that it is not
* going to use the xdg_output_manager object anymore.
*
* Any objects already created through this instance are not affected.
*/
static inline void
zxdg_output_manager_v1_destroy(struct zxdg_output_manager_v1 *zxdg_output_manager_v1)
{
wl_proxy_marshal((struct wl_proxy *) zxdg_output_manager_v1,
ZXDG_OUTPUT_MANAGER_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zxdg_output_manager_v1);
}
/**
* @ingroup iface_zxdg_output_manager_v1
*
* This creates a new xdg_output object for the given wl_output.
*/
static inline struct zxdg_output_v1 *
zxdg_output_manager_v1_get_xdg_output(struct zxdg_output_manager_v1 *zxdg_output_manager_v1, struct wl_output *output)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) zxdg_output_manager_v1,
ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT, &zxdg_output_v1_interface, NULL, output);
return (struct zxdg_output_v1 *) id;
}
/**
* @ingroup iface_zxdg_output_v1
* @struct zxdg_output_v1_listener
*/
struct zxdg_output_v1_listener {
/**
* position of the output within the global compositor space
*
* The position event describes the location of the wl_output
* within the global compositor space.
*
* The logical_position event is sent after creating an xdg_output
* (see xdg_output_manager.get_xdg_output) and whenever the
* location of the output changes within the global compositor
* space.
* @param x x position within the global compositor space
* @param y y position within the global compositor space
*/
void (*logical_position)(void *data,
struct zxdg_output_v1 *zxdg_output_v1,
int32_t x,
int32_t y);
/**
* size of the output in the global compositor space
*
* The logical_size event describes the size of the output in the
* global compositor space.
*
* For example, a surface without any buffer scale, transformation
* nor rotation set, with the size matching the logical_size will
* have the same size as the corresponding output when displayed.
*
* Most regular Wayland clients should not pay attention to the
* logical size and would rather rely on xdg_shell interfaces.
*
* Some clients such as Xwayland, however, need this to configure
* their surfaces in the global compositor space as the compositor
* may apply a different scale from what is advertised by the
* output scaling property (to achieve fractional scaling, for
* example).
*
* For example, for a wl_output mode 3840×2160 and a scale factor
* 2:
*
* - A compositor not scaling the surface buffers will advertise a
* logical size of 3840×2160,
*
* - A compositor automatically scaling the surface buffers will
* advertise a logical size of 1920×1080,
*
* - A compositor using a fractional scale of 1.5 will advertise a
* logical size to 2560×1620.
*
* For example, for a wl_output mode 1920×1080 and a 90 degree
* rotation, the compositor will advertise a logical size of
* 1080x1920.
*
* The logical_size event is sent after creating an xdg_output (see
* xdg_output_manager.get_xdg_output) and whenever the logical size
* of the output changes, either as a result of a change in the
* applied scale or because of a change in the corresponding output
* mode(see wl_output.mode) or transform (see wl_output.transform).
* @param width width in global compositor space
* @param height height in global compositor space
*/
void (*logical_size)(void *data,
struct zxdg_output_v1 *zxdg_output_v1,
int32_t width,
int32_t height);
/**
* all information about the output have been sent
*
* This event is sent after all other properties of an xdg_output
* have been sent.
*
* This allows changes to the xdg_output properties to be seen as
* atomic, even if they happen via multiple events.
*
* For objects version 3 onwards, this event is deprecated.
* Compositors are not required to send it anymore and must send
* wl_output.done instead.
*/
void (*done)(void *data,
struct zxdg_output_v1 *zxdg_output_v1);
/**
* name of this output
*
* Many compositors will assign names to their outputs, show them
* to the user, allow them to be configured by name, etc. The
* client may wish to know this name as well to offer the user
* similar behaviors.
*
* The naming convention is compositor defined, but limited to
* alphanumeric characters and dashes (-). Each name is unique
* among all wl_output globals, but if a wl_output global is
* destroyed the same name may be reused later. The names will also
* remain consistent across sessions with the same hardware and
* software configuration.
*
* Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc.
* However, do not assume that the name is a reflection of an
* underlying DRM connector, X11 connection, etc.
*
* The name event is sent after creating an xdg_output (see
* xdg_output_manager.get_xdg_output). This event is only sent once
* per xdg_output, and the name does not change over the lifetime
* of the wl_output global.
* @param name output name
* @since 2
*/
void (*name)(void *data,
struct zxdg_output_v1 *zxdg_output_v1,
const char *name);
/**
* human-readable description of this output
*
* Many compositors can produce human-readable descriptions of
* their outputs. The client may wish to know this description as
* well, to communicate the user for various purposes.
*
* The description is a UTF-8 string with no convention defined for
* its contents. Examples might include 'Foocorp 11" Display' or
* 'Virtual X11 output via :1'.
*
* The description event is sent after creating an xdg_output (see
* xdg_output_manager.get_xdg_output) and whenever the description
* changes. The description is optional, and may not be sent at
* all.
*
* For objects of version 2 and lower, this event is only sent once
* per xdg_output, and the description does not change over the
* lifetime of the wl_output global.
* @param description output description
* @since 2
*/
void (*description)(void *data,
struct zxdg_output_v1 *zxdg_output_v1,
const char *description);
};
/**
* @ingroup iface_zxdg_output_v1
*/
static inline int
zxdg_output_v1_add_listener(struct zxdg_output_v1 *zxdg_output_v1,
const struct zxdg_output_v1_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) zxdg_output_v1,
(void (**)(void)) listener, data);
}
#define ZXDG_OUTPUT_V1_DESTROY 0
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_LOGICAL_POSITION_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_LOGICAL_SIZE_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_DONE_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_NAME_SINCE_VERSION 2
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION 2
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_DESTROY_SINCE_VERSION 1
/** @ingroup iface_zxdg_output_v1 */
static inline void
zxdg_output_v1_set_user_data(struct zxdg_output_v1 *zxdg_output_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zxdg_output_v1, user_data);
}
/** @ingroup iface_zxdg_output_v1 */
static inline void *
zxdg_output_v1_get_user_data(struct zxdg_output_v1 *zxdg_output_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zxdg_output_v1);
}
static inline uint32_t
zxdg_output_v1_get_version(struct zxdg_output_v1 *zxdg_output_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zxdg_output_v1);
}
/**
* @ingroup iface_zxdg_output_v1
*
* Using this request a client can tell the server that it is not
* going to use the xdg_output object anymore.
*/
static inline void
zxdg_output_v1_destroy(struct zxdg_output_v1 *zxdg_output_v1)
{
wl_proxy_marshal((struct wl_proxy *) zxdg_output_v1,
ZXDG_OUTPUT_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zxdg_output_v1);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,78 +0,0 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* 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.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface zxdg_output_v1_interface;
static const struct wl_interface *xdg_output_unstable_v1_types[] = {
NULL,
NULL,
&zxdg_output_v1_interface,
&wl_output_interface,
};
static const struct wl_message zxdg_output_manager_v1_requests[] = {
{ "destroy", "", xdg_output_unstable_v1_types + 0 },
{ "get_xdg_output", "no", xdg_output_unstable_v1_types + 2 },
};
WL_PRIVATE const struct wl_interface zxdg_output_manager_v1_interface = {
"zxdg_output_manager_v1", 3,
2, zxdg_output_manager_v1_requests,
0, NULL,
};
static const struct wl_message zxdg_output_v1_requests[] = {
{ "destroy", "", xdg_output_unstable_v1_types + 0 },
};
static const struct wl_message zxdg_output_v1_events[] = {
{ "logical_position", "ii", xdg_output_unstable_v1_types + 0 },
{ "logical_size", "ii", xdg_output_unstable_v1_types + 0 },
{ "done", "", xdg_output_unstable_v1_types + 0 },
{ "name", "2s", xdg_output_unstable_v1_types + 0 },
{ "description", "2s", xdg_output_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zxdg_output_v1_interface = {
"zxdg_output_v1", 3,
1, zxdg_output_v1_requests,
5, zxdg_output_v1_events,
};

File diff suppressed because it is too large Load Diff

View File

@ -1,181 +0,0 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2008-2013 Kristian Høgsberg
* Copyright © 2013 Rafael Antognolli
* Copyright © 2013 Jasper St. Pierre
* Copyright © 2010-2013 Intel Corporation
* Copyright © 2015-2017 Samsung Electronics Co., Ltd
* Copyright © 2015-2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* 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.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface xdg_positioner_interface;
extern const struct wl_interface xdg_surface_interface;
extern const struct wl_interface xdg_toplevel_interface;
static const struct wl_interface *xdg_shell_types[] = {
NULL,
NULL,
NULL,
NULL,
&xdg_positioner_interface,
&xdg_surface_interface,
&wl_surface_interface,
&xdg_toplevel_interface,
&xdg_popup_interface,
&xdg_surface_interface,
&xdg_positioner_interface,
&xdg_toplevel_interface,
&wl_seat_interface,
NULL,
NULL,
NULL,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&xdg_positioner_interface,
NULL,
};
static const struct wl_message xdg_wm_base_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "create_positioner", "n", xdg_shell_types + 4 },
{ "get_xdg_surface", "no", xdg_shell_types + 5 },
{ "pong", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_wm_base_events[] = {
{ "ping", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
"xdg_wm_base", 3,
4, xdg_wm_base_requests,
1, xdg_wm_base_events,
};
static const struct wl_message xdg_positioner_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_size", "ii", xdg_shell_types + 0 },
{ "set_anchor_rect", "iiii", xdg_shell_types + 0 },
{ "set_anchor", "u", xdg_shell_types + 0 },
{ "set_gravity", "u", xdg_shell_types + 0 },
{ "set_constraint_adjustment", "u", xdg_shell_types + 0 },
{ "set_offset", "ii", xdg_shell_types + 0 },
{ "set_reactive", "3", xdg_shell_types + 0 },
{ "set_parent_size", "3ii", xdg_shell_types + 0 },
{ "set_parent_configure", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
"xdg_positioner", 3,
10, xdg_positioner_requests,
0, NULL,
};
static const struct wl_message xdg_surface_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "get_toplevel", "n", xdg_shell_types + 7 },
{ "get_popup", "n?oo", xdg_shell_types + 8 },
{ "set_window_geometry", "iiii", xdg_shell_types + 0 },
{ "ack_configure", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_surface_events[] = {
{ "configure", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_surface_interface = {
"xdg_surface", 3,
5, xdg_surface_requests,
1, xdg_surface_events,
};
static const struct wl_message xdg_toplevel_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_parent", "?o", xdg_shell_types + 11 },
{ "set_title", "s", xdg_shell_types + 0 },
{ "set_app_id", "s", xdg_shell_types + 0 },
{ "show_window_menu", "ouii", xdg_shell_types + 12 },
{ "move", "ou", xdg_shell_types + 16 },
{ "resize", "ouu", xdg_shell_types + 18 },
{ "set_max_size", "ii", xdg_shell_types + 0 },
{ "set_min_size", "ii", xdg_shell_types + 0 },
{ "set_maximized", "", xdg_shell_types + 0 },
{ "unset_maximized", "", xdg_shell_types + 0 },
{ "set_fullscreen", "?o", xdg_shell_types + 21 },
{ "unset_fullscreen", "", xdg_shell_types + 0 },
{ "set_minimized", "", xdg_shell_types + 0 },
};
static const struct wl_message xdg_toplevel_events[] = {
{ "configure", "iia", xdg_shell_types + 0 },
{ "close", "", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
"xdg_toplevel", 3,
14, xdg_toplevel_requests,
2, xdg_toplevel_events,
};
static const struct wl_message xdg_popup_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "grab", "ou", xdg_shell_types + 22 },
{ "reposition", "3ou", xdg_shell_types + 24 },
};
static const struct wl_message xdg_popup_events[] = {
{ "configure", "iiii", xdg_shell_types + 0 },
{ "popup_done", "", xdg_shell_types + 0 },
{ "repositioned", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_popup_interface = {
"xdg_popup", 3,
3, xdg_popup_requests,
3, xdg_popup_events,
};

View File

@ -1,917 +0,0 @@
#define _POSIX_C_SOURCE 200112L
#include "wl.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <wayland-client.h>
#include <wayland-client-protocol.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <linux/input-event-codes.h>
#include <string.h>
#include "protocols/xdg-shell-client-header.h"
#include "protocols/xdg-shell.h"
#include "protocols/wlr-layer-shell-unstable-v1-client-header.h"
#include "protocols/wlr-layer-shell-unstable-v1.h"
#include "protocols/wlr-foreign-toplevel-management-unstable-v1-client-header.h"
#include "protocols/wlr-foreign-toplevel-management-unstable-v1.h"
#include "protocols/idle-client-header.h"
#include "protocols/idle.h"
#include "pool-buffer.h"
#include "../log.h"
#include "../settings.h"
#include "../queues.h"
#include "../input.h"
#include "libgwater-wayland.h"
#define MAX_TOUCHPOINTS 10
struct window_wl {
cairo_surface_t *c_surface;
cairo_t * c_ctx;
GWaterWaylandSource *esrc;
};
struct wl_ctx {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_shm *shm;
struct zwlr_layer_shell_v1 *layer_shell;
struct wl_seat *seat;
struct wl_list outputs;
struct wl_surface *surface;
struct dunst_output *surface_output;
struct zwlr_layer_surface_v1 *layer_surface;
struct dunst_output *layer_surface_output;
struct wl_callback *frame_callback;
struct org_kde_kwin_idle *idle_handler;
struct org_kde_kwin_idle_timeout *idle_timeout;
struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager;
bool configured;
bool dirty;
bool is_idle;
bool has_idle_monitor;
struct {
struct wl_pointer *wl_pointer;
int32_t x, y;
} pointer;
struct {
struct wl_touch *wl_touch;
struct {
int32_t x, y;
} pts[MAX_TOUCHPOINTS];
} touch;
struct dimensions cur_dim;
int32_t width, height;
struct pool_buffer buffers[2];
struct pool_buffer *current_buffer;
};
struct dunst_output {
uint32_t global_name;
char *name;
struct wl_output *wl_output;
struct wl_list link;
uint32_t scale;
uint32_t subpixel; // TODO do something with it
bool fullscreen;
struct zwlr_foreign_toplevel_handle_v1 *fullscreen_toplevel; // the toplevel that is fullscreened on this output
};
struct wl_ctx ctx;
static void noop() {
// This space intentionally left blank
}
void set_dirty();
static void output_handle_geometry(void *data, struct wl_output *wl_output,
int32_t x, int32_t y, int32_t phy_width, int32_t phy_height,
int32_t subpixel, const char *make, const char *model,
int32_t transform) {
//TODO do something with the subpixel data
struct dunst_output *output = data;
output->subpixel = subpixel;
}
static void output_handle_scale(void *data, struct wl_output *wl_output,
int32_t factor) {
struct dunst_output *output = data;
output->scale = factor;
wake_up();
}
static const struct wl_output_listener output_listener = {
.geometry = output_handle_geometry,
.mode = noop,
.done = noop,
.scale = output_handle_scale,
};
static void create_output( struct wl_output *wl_output, uint32_t global_name) {
struct dunst_output *output = g_malloc0(sizeof(struct dunst_output));
if (output == NULL) {
LOG_E("allocation failed");
return;
}
static int number = 0;
LOG_I("New output found - id %i", number);
output->global_name = global_name;
output->wl_output = wl_output;
output->scale = 1;
output->fullscreen = false;
wl_list_insert(&ctx.outputs, &output->link);
wl_output_set_user_data(wl_output, output);
wl_output_add_listener(wl_output, &output_listener, output);
number++;
}
static void destroy_output(struct dunst_output *output) {
if (ctx.surface_output == output) {
ctx.surface_output = NULL;
}
if (ctx.layer_surface_output == output) {
ctx.layer_surface_output = NULL;
}
wl_list_remove(&output->link);
wl_output_destroy(output->wl_output);
free(output->name);
free(output);
}
static void touch_handle_motion(void *data, struct wl_touch *wl_touch,
uint32_t time, int32_t id,
wl_fixed_t surface_x, wl_fixed_t surface_y) {
if (id >= MAX_TOUCHPOINTS) {
return;
}
ctx.touch.pts[id].x = wl_fixed_to_int(surface_x);
ctx.touch.pts[id].y = wl_fixed_to_int(surface_y);
}
static void touch_handle_down(void *data, struct wl_touch *wl_touch,
uint32_t serial, uint32_t time, struct wl_surface *sfc, int32_t id,
wl_fixed_t surface_x, wl_fixed_t surface_y) {
if (id >= MAX_TOUCHPOINTS) {
return;
}
ctx.touch.pts[id].x = wl_fixed_to_int(surface_x);
ctx.touch.pts[id].y = wl_fixed_to_int(surface_y);
}
static void touch_handle_up(void *data, struct wl_touch *wl_touch,
uint32_t serial, uint32_t time, int32_t id) {
if (id >= MAX_TOUCHPOINTS) {
return;
}
input_handle_click(BTN_TOUCH, false,
ctx.touch.pts[id].x, ctx.touch.pts[id].y);
}
static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
ctx.pointer.x = wl_fixed_to_int(surface_x);
ctx.pointer.y = wl_fixed_to_int(surface_y);
}
static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button,
uint32_t button_state) {
input_handle_click(button, button_state, ctx.pointer.x, ctx.pointer.y);
}
static const struct wl_pointer_listener pointer_listener = {
.enter = noop,
.leave = noop,
.motion = pointer_handle_motion,
.button = pointer_handle_button,
.axis = noop,
};
static const struct wl_touch_listener touch_listener = {
.down = touch_handle_down,
.up = touch_handle_up,
.motion = touch_handle_motion,
.frame = noop,
.cancel = noop,
};
static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
uint32_t capabilities) {
if (ctx.pointer.wl_pointer != NULL) {
wl_pointer_release(ctx.pointer.wl_pointer);
ctx.pointer.wl_pointer = NULL;
}
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
ctx.pointer.wl_pointer = wl_seat_get_pointer(wl_seat);
wl_pointer_add_listener(ctx.pointer.wl_pointer,
&pointer_listener, ctx.seat);
}
if (ctx.touch.wl_touch != NULL) {
wl_touch_release(ctx.touch.wl_touch);
ctx.touch.wl_touch = NULL;
}
if (capabilities & WL_SEAT_CAPABILITY_TOUCH) {
ctx.touch.wl_touch = wl_seat_get_touch(wl_seat);
wl_touch_add_listener(ctx.touch.wl_touch,
&touch_listener, ctx.seat);
}
}
static const struct wl_seat_listener seat_listener = {
.capabilities = seat_handle_capabilities,
.name = noop,
};
static void surface_handle_enter(void *data, struct wl_surface *surface,
struct wl_output *wl_output) {
// Don't bother keeping a list of outputs, a layer surface can only be on
// one output a a time
ctx.surface_output = wl_output_get_user_data(wl_output);
set_dirty();
}
static void surface_handle_leave(void *data, struct wl_surface *surface,
struct wl_output *wl_output) {
ctx.surface_output = NULL;
}
static const struct wl_surface_listener surface_listener = {
.enter = surface_handle_enter,
.leave = surface_handle_leave,
};
static void schedule_frame_and_commit();
static void send_frame();
static void layer_surface_handle_configure(void *data,
struct zwlr_layer_surface_v1 *surface,
uint32_t serial, uint32_t width, uint32_t height) {
ctx.configured = true;
ctx.width = width;
ctx.height = height;
// not needed as it is set somewhere else
/* zwlr_layer_surface_v1_set_size(surface, width, height); */
zwlr_layer_surface_v1_ack_configure(surface, serial);
send_frame();
}
static void layer_surface_handle_closed(void *data,
struct zwlr_layer_surface_v1 *surface) {
LOG_I("Destroying layer");
if (ctx.layer_surface)
zwlr_layer_surface_v1_destroy(ctx.layer_surface);
ctx.layer_surface = NULL;
if (ctx.surface)
wl_surface_destroy(ctx.surface);
ctx.surface = NULL;
if (ctx.frame_callback) {
wl_callback_destroy(ctx.frame_callback);
ctx.frame_callback = NULL;
ctx.dirty = true;
}
if (ctx.configured) {
ctx.configured = false;
ctx.width = ctx.height = 0;
ctx.dirty = true;
}
if (ctx.dirty) {
schedule_frame_and_commit();
}
}
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
.configure = layer_surface_handle_configure,
.closed = layer_surface_handle_closed,
};
static void idle_start (void *data, struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout) {
ctx.is_idle = true;
LOG_D("User went idle");
}
static void idle_stop (void *data, struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout) {
ctx.is_idle = false;
LOG_D("User isn't idle anymore");
}
static const struct org_kde_kwin_idle_timeout_listener idle_timeout_listener = {
.idle = idle_start,
.resumed = idle_stop,
};
static void add_seat_to_idle_handler(struct wl_seat *seat) {
if (!ctx.idle_handler){
return;
}
if (settings.idle_threshold > 0) {
uint32_t timeout_ms = settings.idle_threshold/1000;
ctx.idle_timeout = org_kde_kwin_idle_get_idle_timeout(ctx.idle_handler, seat, timeout_ms);
org_kde_kwin_idle_timeout_add_listener(ctx.idle_timeout, &idle_timeout_listener, 0);
ctx.has_idle_monitor = true;
}
}
// Warning, can return NULL
static struct dunst_output *get_configured_output() {
int n = 0;
int target_monitor = settings.monitor;
struct dunst_output *first_output = NULL, *configured_output = NULL,
*tmp_output = NULL;
wl_list_for_each(tmp_output, &ctx.outputs, link) {
if (n == 0)
first_output = tmp_output;
if (n == target_monitor)
configured_output = tmp_output;
n++;
}
// There's only 1 output, so return that
if (n == 1)
return first_output;
switch (settings.f_mode){
case FOLLOW_NONE: ; // this semicolon is neccesary
if (!configured_output) {
LOG_W("Monitor %i doesn't exist, using focused monitor", settings.monitor);
}
return configured_output;
case FOLLOW_MOUSE:
// fallthrough
case FOLLOW_KEYBOARD:
// fallthrough
default:
return NULL;
}
}
// does not do null checking
static void dunst_output_set_fullscreen(struct dunst_output *output,
struct zwlr_foreign_toplevel_handle_v1 *toplevel,
bool fullscreen) {
output->fullscreen = fullscreen;
if (fullscreen)
output->fullscreen_toplevel = toplevel;
else
output->fullscreen_toplevel = NULL;
LOG_D("Set output %i fullscreen state %i", output->global_name, fullscreen);
wake_up();
}
static void toplevel_output_leave(void *data,
struct zwlr_foreign_toplevel_handle_v1 *toplevel,
struct wl_output *output) {
zwlr_foreign_toplevel_handle_v1_set_user_data(toplevel, NULL);
}
static void toplevel_output_enter(void *data,
struct zwlr_foreign_toplevel_handle_v1 *toplevel,
struct wl_output *output) {
// FIXME toplevel can be on multiple outputs, so a list of outputs should be kept
zwlr_foreign_toplevel_handle_v1_set_user_data(toplevel, output);
}
static void toplevel_closed(void *data,
struct zwlr_foreign_toplevel_handle_v1 *toplevel) {
struct wl_output *output_wl = (struct wl_output*) data;
if (output_wl == NULL) {
return;
}
struct dunst_output *output = (struct dunst_output*) wl_output_get_user_data(output_wl);
if (output == NULL) {
return;
}
dunst_output_set_fullscreen(output, toplevel, false);
}
static void toplevel_state(void *data,
struct zwlr_foreign_toplevel_handle_v1 *toplevel,
struct wl_array *state) {
struct wl_output *output_wl = (struct wl_output*) data;
if (output_wl == NULL) {
return;
}
struct dunst_output *output = (struct dunst_output*) wl_output_get_user_data(output_wl);
if (output == NULL) {
return;
}
bool fullscreen = false;
bool activated = false;
enum zwlr_foreign_toplevel_handle_v1_state* element;
wl_array_for_each(element, state){
if (*element == ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN) {
fullscreen = true;
}
if (*element == ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED) {
activated = true;
}
}
if (fullscreen && activated) {
dunst_output_set_fullscreen(output, toplevel, true);
} else {
if (output->fullscreen_toplevel == toplevel) {
// this toplevel was fullscreen, but isn't anymore
dunst_output_set_fullscreen(output, toplevel, false);
}
}
}
static const struct zwlr_foreign_toplevel_handle_v1_listener foreign_toplevel_handle_listener = {
.title = noop,
.app_id = noop,
.output_enter = toplevel_output_enter,
.output_leave = toplevel_output_leave,
.state = toplevel_state,
.done = noop,
.closed = toplevel_closed,
};
static void toplevel_created(void *data,
struct zwlr_foreign_toplevel_manager_v1 *zwlr_foreign_toplevel_manager_v1,
struct zwlr_foreign_toplevel_handle_v1 *toplevel){
zwlr_foreign_toplevel_handle_v1_add_listener(toplevel, &foreign_toplevel_handle_listener, NULL);
}
static void toplevel_finished(void *data,
struct zwlr_foreign_toplevel_manager_v1 *zwlr_foreign_toplevel_manager_v1){
}
static const struct zwlr_foreign_toplevel_manager_v1_listener foreign_toplevel_manager_listener = {
.toplevel = toplevel_created,
.finished = toplevel_finished,
};
static void handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version) {
int *count = data;
if (*count == 0)
{
if (strcmp(interface, wl_compositor_interface.name) == 0) {
ctx.compositor = wl_registry_bind(registry, name,
&wl_compositor_interface, 4);
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
ctx.shm = wl_registry_bind(registry, name,
&wl_shm_interface, 1);
} else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
ctx.layer_shell = wl_registry_bind(registry, name,
&zwlr_layer_shell_v1_interface, 1);
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
ctx.seat = wl_registry_bind(registry, name, &wl_seat_interface, 3);
wl_seat_add_listener(ctx.seat, &seat_listener, ctx.seat);
add_seat_to_idle_handler(ctx.seat);
} else if (strcmp(interface, wl_output_interface.name) == 0) {
struct wl_output *output =
wl_registry_bind(registry, name, &wl_output_interface, 3);
create_output(output, name);
} else if (strcmp(interface, org_kde_kwin_idle_interface.name) == 0 &&
version >= ORG_KDE_KWIN_IDLE_TIMEOUT_IDLE_SINCE_VERSION) {
ctx.idle_handler = wl_registry_bind(registry, name, &org_kde_kwin_idle_interface, 1);
}
} else {
if (strcmp(interface, zwlr_foreign_toplevel_manager_v1_interface.name) == 0 &&
version >= ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN_SINCE_VERSION) {
// Only bind after the second pass to bind after binding to all the outputs.
// This is because otherwise toplevel_enter evens won't be sent.
ctx.toplevel_manager = wl_registry_bind(registry, name, &zwlr_foreign_toplevel_manager_v1_interface, 2);
zwlr_foreign_toplevel_manager_v1_add_listener(ctx.toplevel_manager, &foreign_toplevel_manager_listener, NULL);
}
}
}
static void handle_global_remove(void *data, struct wl_registry *registry,
uint32_t name) {
struct dunst_output *output, *tmp;
wl_list_for_each_safe(output, tmp, &ctx.outputs, link) {
if (output->global_name == name) {
destroy_output(output);
break;
}
}
}
static const struct wl_registry_listener registry_listener = {
.global = handle_global,
.global_remove = handle_global_remove,
};
bool wl_init() {
wl_list_init(&ctx.outputs);
//wl_list_init(&ctx.seats); // TODO multi-seat support
ctx.display = wl_display_connect(NULL);
if (ctx.display == NULL) {
LOG_W("failed to create display");
return false;
}
int count = 0;
ctx.registry = wl_display_get_registry(ctx.display);
wl_registry_add_listener(ctx.registry, &registry_listener, &count);
wl_display_roundtrip(ctx.display);
count = 1;
// we need a second pass to let for foreign_toplevel (look there for more info)
ctx.registry = wl_display_get_registry(ctx.display);
wl_registry_add_listener(ctx.registry, &registry_listener, &count);
wl_display_roundtrip(ctx.display);
if (ctx.compositor == NULL) {
LOG_W("compositor doesn't support wl_compositor");
return false;
}
if (ctx.shm == NULL) {
LOG_W("compositor doesn't support wl_shm");
return false;
}
if (ctx.layer_shell == NULL) {
LOG_W("compositor doesn't support zwlr_layer_shell_v1");
return false;
}
if (ctx.seat == NULL) {
LOG_W("no seat was found, so dunst cannot see input");
} else {
if (ctx.idle_handler == NULL) {
LOG_I("compositor doesn't support org_kde_kwin_idle_interface");
}
else if (ctx.idle_timeout == NULL) {
// something went wrong in setting the timeout
LOG_W("couldn't set idle timeout");
}
}
if (ctx.toplevel_manager == NULL) {
LOG_W("compositor doesn't support zwlr_foreign_toplevel_v1. Fullscreen detection won't work");
}
return true;
}
void wl_deinit() {
// We need to check if any of these are NULL, since the initialization
// could have been aborted half way through, or the compositor doesn't
// support some of these features.
if (ctx.layer_surface != NULL) {
zwlr_layer_surface_v1_destroy(ctx.layer_surface);
}
if (ctx.surface != NULL) {
wl_surface_destroy(ctx.surface);
}
finish_buffer(&ctx.buffers[0]);
finish_buffer(&ctx.buffers[1]);
// The output list is initialized at the start of init, so no need to
// check for NULL
struct dunst_output *output, *output_tmp;
wl_list_for_each_safe(output, output_tmp, &ctx.outputs, link) {
destroy_output(output);
}
if (ctx.seat) {
if (ctx.pointer.wl_pointer)
wl_pointer_release(ctx.pointer.wl_pointer);
wl_seat_release(ctx.seat);
ctx.seat = NULL;
}
if (ctx.idle_handler)
org_kde_kwin_idle_destroy(ctx.idle_handler);
if (ctx.idle_timeout)
org_kde_kwin_idle_timeout_release(ctx.idle_timeout);
if (ctx.layer_shell)
zwlr_layer_shell_v1_destroy(ctx.layer_shell);
if (ctx.compositor)
wl_compositor_destroy(ctx.compositor);
if (ctx.shm)
wl_shm_destroy(ctx.shm);
if (ctx.registry)
wl_registry_destroy(ctx.registry);
if (ctx.display)
wl_display_disconnect(ctx.display);
}
static void schedule_frame_and_commit();
// Draw and commit a new frame.
static void send_frame() {
int scale = wl_get_scale();
struct dunst_output *output = get_configured_output();
int height = ctx.cur_dim.h;
int width = ctx.cur_dim.w;
// There are two cases where we want to tear down the surface: zero
// notifications (height = 0) or moving between outputs.
if (height == 0 || ctx.layer_surface_output != output) {
if (ctx.layer_surface != NULL) {
zwlr_layer_surface_v1_destroy(ctx.layer_surface);
ctx.layer_surface = NULL;
}
if (ctx.surface != NULL) {
wl_surface_destroy(ctx.surface);
ctx.surface = NULL;
}
ctx.width = ctx.height = 0;
ctx.surface_output = NULL;
ctx.configured = false;
}
// If there are no notifications, there's no point in recreating the
// surface right now.
if (height == 0) {
ctx.dirty = false;
return;
}
// If we've made it here, there is something to draw. If the surface
// doesn't exist (this is the first notification, or we moved to a
// different output), we need to create it.
if (ctx.layer_surface == NULL) {
struct wl_output *wl_output = NULL;
if (output != NULL) {
wl_output = output->wl_output;
}
ctx.layer_surface_output = output;
ctx.surface = wl_compositor_create_surface(ctx.compositor);
wl_surface_add_listener(ctx.surface, &surface_listener, NULL);
ctx.layer_surface = zwlr_layer_shell_v1_get_layer_surface(
ctx.layer_shell, ctx.surface, wl_output,
settings.layer, "notifications");
zwlr_layer_surface_v1_add_listener(ctx.layer_surface,
&layer_surface_listener, NULL);
// Because we're creating a new surface, we aren't going to draw
// anything into it during this call. We don't know what size the
// surface will be until we've asked the compositor for what we want
// and it has responded with what it actually gave us. We also know
// that the height we would _like_ to draw (greater than zero, or we
// would have bailed already) is different from our ctx.height
// (which has to be zero here), so we can fall through to the next
// block to let it set the size for us.
}
assert(ctx.layer_surface);
// We now want to resize the surface if it isn't the right size. If the
// surface is brand new, it doesn't even have a size yet. If it already
// exists, we might need to resize if the list of notifications has changed
// since the last time we drew.
if (ctx.height != height || ctx.width != width) {
struct dimensions dim = ctx.cur_dim;
// Set window size
zwlr_layer_surface_v1_set_size(ctx.layer_surface,
dim.w, dim.h);
// TODO Do this only once
uint32_t anchor = 0;
if (settings.geometry.negative_x) {
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
} else {
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
}
if (settings.geometry.negative_y) {
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
} else {
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
}
// Put the window at the right position
zwlr_layer_surface_v1_set_anchor(ctx.layer_surface,
anchor);
zwlr_layer_surface_v1_set_margin(ctx.layer_surface,
abs(settings.geometry.y), // top
abs(settings.geometry.x), // right
abs(settings.geometry.y), // bottom
abs(settings.geometry.x));// left
wl_surface_commit(ctx.surface);
// Now we're going to bail without drawing anything. This gives the
// compositor a chance to create the surface and tell us what size we
// were actually granted, which may be smaller than what we asked for
// depending on the screen size and layout of other layer surfaces.
// This information is provided in layer_surface_handle_configure,
// which will then call send_frame again. When that call happens, the
// layer surface will exist and the height will hopefully match what
// we asked for. That means we won't return here, and will actually
// draw into the surface down below.
// TODO: If the compositor doesn't send a configure with the size we
// requested, we'll enter an infinite loop. We need to keep track of
// the fact that a request was sent separately from what height we are.
wl_display_roundtrip(ctx.display);
return;
}
assert(ctx.configured);
// Yay we can finally draw something!
wl_surface_set_buffer_scale(ctx.surface, scale);
wl_surface_damage_buffer(ctx.surface, 0, 0, INT32_MAX, INT32_MAX);
wl_surface_attach(ctx.surface, ctx.current_buffer->buffer, 0, 0);
ctx.current_buffer->busy = true;
// Schedule a frame in case the state becomes dirty again
schedule_frame_and_commit();
ctx.dirty = false;
}
static void frame_handle_done(void *data, struct wl_callback *callback,
uint32_t time) {
wl_callback_destroy(ctx.frame_callback);
ctx.frame_callback = NULL;
// Only draw again if we need to
if (ctx.dirty) {
send_frame();
}
}
static const struct wl_callback_listener frame_listener = {
.done = frame_handle_done,
};
static void schedule_frame_and_commit() {
if (ctx.frame_callback) {
return;
}
if (ctx.surface == NULL) {
// We don't yet have a surface, create it immediately
send_frame();
return;
}
ctx.frame_callback = wl_surface_frame(ctx.surface);
wl_callback_add_listener(ctx.frame_callback, &frame_listener, NULL);
wl_surface_commit(ctx.surface);
}
void set_dirty() {
if (ctx.dirty) {
return;
}
ctx.dirty = true;
schedule_frame_and_commit();
}
window wl_win_create(void) {
struct window_wl *win = g_malloc0(sizeof(struct window_wl));
win->esrc = g_water_wayland_source_new_for_display(NULL, ctx.display);
return win;
}
void wl_win_destroy(window winptr) {
struct window_wl *win = (struct window_wl*)winptr;
g_water_wayland_source_free(win->esrc);
// FIXME: Dealloc everything
g_free(win);
}
void wl_win_show(window win) {
// This is here for compatibilty with the X11 output. The window is
// already shown in wl_display_surface.
}
void wl_win_hide(window win) {
LOG_I("Wayland: Hiding window");
ctx.cur_dim.h = 0;
set_dirty();
wl_display_roundtrip(ctx.display);
}
void wl_display_surface(cairo_surface_t *srf, window winptr, const struct dimensions* dim) {
/* struct window_wl *win = (struct window_wl*)winptr; */
int scale = wl_get_scale();
LOG_D("Buffer size (scaled) %ix%i", dim->w * scale, dim->h * scale);
ctx.current_buffer = get_next_buffer(ctx.shm, ctx.buffers,
dim->w * scale, dim->h * scale);
cairo_t *c = ctx.current_buffer->cairo;
cairo_save(c);
cairo_set_source_surface(c, srf, 0, 0);
cairo_rectangle(c, 0, 0, dim->w * scale, dim->h * scale);
cairo_fill(c);
cairo_restore(c);
ctx.cur_dim = *dim;
set_dirty();
wl_display_roundtrip(ctx.display);
}
cairo_t* wl_win_get_context(window winptr) {
struct window_wl *win = (struct window_wl*)winptr;
ctx.current_buffer = get_next_buffer(ctx.shm, ctx.buffers, 500, 500);
win->c_surface = ctx.current_buffer->surface;
win->c_ctx = ctx.current_buffer->cairo;
return win->c_ctx;
}
const struct screen_info* wl_get_active_screen(void) {
// TODO Screen size detection
static struct screen_info scr = {
.w = 1920,
.h = 1080,
.x = 0,
.y = 0,
.id = 0,
.mmh = 500
};
scr.dpi = wl_get_scale() * 96;
return &scr;
}
bool wl_is_idle(void) {
LOG_I("Idle status queried: %i", ctx.is_idle);
// When the user doesn't have a seat, or their compositor doesn't support the idle
// protocol, we'll assume that they are not idle.
if (settings.idle_threshold == 0 || ctx.has_idle_monitor == false) {
return false;
} else {
return ctx.is_idle;
}
}
bool wl_have_fullscreen_window(void) {
bool have_fullscreen = false;
struct dunst_output *current_output = get_configured_output();
if (!current_output) {
// Cannot detect focused output, so return true if any of the
// outputs is fullscreen. This will work even when unfocused
// outputs have fullscreen toplevels, since a toplevel has to
// be fullscreen and activate to consider an output fullscreen.
struct dunst_output *output;
wl_list_for_each(output, &ctx.outputs, link) {
have_fullscreen |= output->fullscreen;
}
} else {
have_fullscreen = current_output->fullscreen;
}
LOG_D("Fullscreen queried: %i", have_fullscreen);
return have_fullscreen;
}
int wl_get_scale(void) {
int scale = 0;
struct dunst_output *output = get_configured_output();
if (output) {
scale = output->scale;
} else {
// return the largest scale
struct dunst_output *output;
wl_list_for_each(output, &ctx.outputs, link) {
scale = MAX(output->scale, scale);
}
}
if (scale <= 0)
scale = 1;
return scale;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -1,32 +0,0 @@
#ifndef DUNST_WL_H
#define DUNST_WL_H
#include <stdbool.h>
#include <cairo.h>
#include <glib.h>
#include "../output.h"
bool wl_init(void);
void wl_deinit(void);
window wl_win_create(void);
void wl_win_destroy(window);
void wl_win_show(window);
void wl_win_hide(window);
void wl_display_surface(cairo_surface_t *srf, window win, const struct dimensions*);
cairo_t* wl_win_get_context(window);
const struct screen_info* wl_get_active_screen(void);
bool wl_is_idle(void);
bool wl_have_fullscreen_window(void);
// Return the dpi scaling of the current output. Everything that's rendered
// should be multiplied by this value, but don't use it to multiply other
// values. All sizes should be in unscaled units.
int wl_get_scale(void);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -69,12 +69,12 @@ static double screen_dpi_get_from_xft(void)
return screen_dpi_xft_cache;
}
static double screen_dpi_get_from_monitor(const struct screen_info *scr)
static double screen_dpi_get_from_monitor(struct screen_info *scr)
{
return (double)scr->h * 25.4 / (double)scr->mmh;
}
double screen_dpi_get(const struct screen_info *scr)
double screen_dpi_get(struct screen_info *scr)
{
if ( ! settings.force_xinerama
&& settings.per_monitor_dpi)
@ -156,7 +156,6 @@ void randr_update(void)
screens[i].w = m[i].width;
screens[i].h = m[i].height;
screens[i].mmh = m[i].mheight;
screens[i].dpi = screen_dpi_get(&screens[i]);
}
XRRFreeMonitors(m);
@ -301,52 +300,28 @@ bool window_is_fullscreen(Window window)
* Select the screen on which the Window
* should be displayed.
*/
const struct screen_info *get_active_screen(void)
struct screen_info *get_active_screen(void)
{
int ret = 0;
bool force_follow_mouse = false;
if (settings.monitor > 0 && settings.monitor < screens_len) {
ret = settings.monitor;
goto sc_cleanup;
}
x_follow_setup_error_handler();
if (settings.f_mode == FOLLOW_NONE) {
if (settings.monitor >= 0 && settings.monitor < screens_len) {
ret = settings.monitor;
}
ret = XDefaultScreen(xctx.dpy);
goto sc_cleanup;
} else {
int x, y;
assert(settings.f_mode == FOLLOW_MOUSE
|| settings.f_mode == FOLLOW_KEYBOARD);
x_follow_setup_error_handler();
Window root =
RootWindow(xctx.dpy, DefaultScreen(xctx.dpy));
if (settings.f_mode == FOLLOW_KEYBOARD) {
Window focused = get_focused_window();
if (!focused) {
/*
* If no window is focused, or the focus is set
* to dynamically change to the root window of
* the screen the pointer is on, force following
* the mouse.
*/
force_follow_mouse = true;
} else {
Window child_return;
/*
* The window with input focus might be on a
* different X screen. Use the mouse location
* in that case.
*/
force_follow_mouse = !XTranslateCoordinates(
xctx.dpy, focused,root,
0, 0, &x, &y,
&child_return);
}
}
if (settings.f_mode == FOLLOW_MOUSE || force_follow_mouse) {
if (settings.f_mode == FOLLOW_MOUSE) {
int dummy;
unsigned int dummy_ui;
Window dummy_win;
@ -362,6 +337,21 @@ const struct screen_info *get_active_screen(void)
&dummy_ui);
}
if (settings.f_mode == FOLLOW_KEYBOARD) {
Window focused = get_focused_window();
if (focused == 0) {
/* something went wrong. Fall back to default */
ret = XDefaultScreen(xctx.dpy);
goto sc_cleanup;
}
Window child_return;
XTranslateCoordinates(xctx.dpy, focused, root,
0, 0, &x, &y, &child_return);
}
for (int i = 0; i < screens_len; i++) {
if (INRECT(x, y, screens[i].x, screens[i].y,
screens[i].w, screens[i].h)) {
@ -373,7 +363,7 @@ const struct screen_info *get_active_screen(void)
goto sc_cleanup;
/* something seems to be wrong. Fall back to default */
ret = 0;
ret = XDefaultScreen(xctx.dpy);
goto sc_cleanup;
}
sc_cleanup:
@ -389,13 +379,32 @@ sc_cleanup:
*/
static Window get_focused_window(void)
{
Window focused;
int ignored;
Window focused = 0;
Atom type;
int format;
unsigned long nitems, bytes_after;
unsigned char *prop_return = NULL;
Window root = RootWindow(xctx.dpy, DefaultScreen(xctx.dpy));
Atom netactivewindow =
XInternAtom(xctx.dpy, "_NET_ACTIVE_WINDOW", false);
XGetInputFocus(xctx.dpy, &focused, &ignored);
XGetWindowProperty(xctx.dpy,
root,
netactivewindow,
0L,
sizeof(Window),
false,
XA_WINDOW,
&type,
&format,
&nitems,
&bytes_after,
&prop_return);
if (prop_return) {
focused = *(Window *)prop_return;
XFree(prop_return);
}
if (focused == None || focused == PointerRoot)
focused = 0;
return focused;
}
@ -424,4 +433,4 @@ static int FollowXErrorHandler(Display *display, XErrorEvent *e)
return 0;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -7,12 +7,21 @@
#define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh))
struct screen_info {
int id;
int x;
int y;
unsigned int h;
unsigned int mmh;
unsigned int w;
};
void init_screens(void);
void screen_dpi_xft_cache_purge(void);
bool screen_check_event(XEvent *ev);
const struct screen_info *get_active_screen(void);
double screen_dpi_get(const struct screen_info *scr);
struct screen_info *get_active_screen(void);
double screen_dpi_get(struct screen_info *scr);
/**
* Find the currently focused window and check if it's in
@ -36,4 +45,4 @@ bool have_fullscreen_window(void);
bool window_is_fullscreen(Window window);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -19,7 +19,6 @@
#include <X11/Xlib.h>
#include <X11/Xresource.h>
#include <X11/Xutil.h>
#include <linux/input-event-codes.h>
#include "../dbus.h"
#include "../draw.h"
@ -31,7 +30,6 @@
#include "../queues.h"
#include "../settings.h"
#include "../utils.h"
#include "../input.h"
#include "screen.h"
@ -69,10 +67,8 @@ static int x_shortcut_tear_down_error_handler(void);
static void setopacity(Window win, unsigned long opacity);
static void x_handle_click(XEvent ev);
static void x_win_move(window winptr, int x, int y, int width, int height)
static void x_win_move(struct window_x11 *win, int x, int y, int width, int height)
{
struct window_x11 *win = (struct window_x11*)winptr;
/* move and resize */
if (x != win->dim.x || y != win->dim.y) {
XMoveWindow(xctx.dpy, win->xwin, x, y);
@ -89,99 +85,97 @@ static void x_win_move(window winptr, int x, int y, int width, int height)
}
}
static void x_win_corners_shape(struct window_x11 *win, const int rad)
static void x_win_round_corners(struct window_x11 *win, const int rad)
{
const int width = win->dim.w;
const int height = win->dim.h;
const int dia = 2 * rad;
const int degrees = 64; // the factor to convert degrees to XFillArc's angle param
Pixmap mask;
cairo_surface_t * cxbm;
cairo_t * cr;
Screen * scr;
Pixmap mask = XCreatePixmap(xctx.dpy, win->xwin, width, height, 1);
XGCValues xgcv;
mask = XCreatePixmap(xctx.dpy, win->xwin, width, height, 1);
scr = ScreenOfDisplay(xctx.dpy, win->cur_screen);
cxbm = cairo_xlib_surface_create_for_bitmap(xctx.dpy, mask, scr, width, height);
cr = cairo_create(cxbm);
GC shape_gc = XCreateGC(xctx.dpy, mask, 0, &xgcv);
cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
XSetForeground(xctx.dpy, shape_gc, 0);
XFillRectangle(xctx.dpy,
mask,
shape_gc,
0,
0,
width,
height);
cairo_set_source_rgba(cr, 0, 0, 0, 0);
cairo_paint(cr);
cairo_set_source_rgba(cr, 1, 1, 1, 1);
XSetForeground(xctx.dpy, shape_gc, 1);
draw_rounded_rect(cr, 0, 0,
width, height,
rad, 1,
true, true);
cairo_fill(cr);
/* To mark all pixels, which should get exposed, we
* use a circle for every corner and two overlapping rectangles */
unsigned const int centercoords[] = {
0, 0,
width - dia - 1, 0,
0, height - dia - 1,
width - dia - 1, height - dia - 1,
};
cairo_show_page(cr);
cairo_destroy(cr);
cairo_surface_flush(cxbm);
cairo_surface_destroy(cxbm);
for (int i = 0; i < sizeof(centercoords)/sizeof(unsigned int); i = i+2) {
XFillArc(xctx.dpy,
mask,
shape_gc,
centercoords[i],
centercoords[i+1],
dia,
dia,
degrees * 0,
degrees * 360);
}
XFillRectangle(xctx.dpy,
mask,
shape_gc,
rad,
0,
width-dia,
height);
XFillRectangle(xctx.dpy,
mask,
shape_gc,
0,
rad,
width,
height-dia);
XShapeCombineMask(xctx.dpy, win->xwin, ShapeBounding, 0, 0, mask, ShapeSet);
XFreeGC(xctx.dpy, shape_gc);
XFreePixmap(xctx.dpy, mask);
XShapeSelectInput(xctx.dpy,
win->xwin, ShapeNotifyMask);
}
static void x_win_corners_unshape(window winptr)
void x_display_surface(cairo_surface_t *srf, struct window_x11 *win, const struct dimensions *dim)
{
struct window_x11 *win = (struct window_x11*)winptr;
XRectangle rect = {
.x = 0,
.y = 0,
.width = win->dim.w,
.height = win->dim.h };
XShapeCombineRectangles(xctx.dpy, win->xwin, ShapeBounding, 0, 0, &rect, 1, ShapeSet, 1);
XShapeSelectInput(xctx.dpy,
win->xwin, ShapeNotifyMask);
}
static bool x_win_composited(struct window_x11 *win)
{
char astr[sizeof("_NET_WM_CM_S") / sizeof(char) + 8];
Atom cm_sel;
sprintf(astr, "_NET_WM_CM_S%i", win->cur_screen);
cm_sel = XInternAtom(xctx.dpy, astr, true);
if (cm_sel == None) {
return false;
} else {
return XGetSelectionOwner(xctx.dpy, cm_sel) != None;
}
}
void x_display_surface(cairo_surface_t *srf, window winptr, const struct dimensions *dim)
{
struct window_x11 *win = (struct window_x11*)winptr;
x_win_move(win, dim->x, dim->y, dim->w, dim->h);
cairo_xlib_surface_set_size(win->root_surface, dim->w, dim->h);
XClearWindow(xctx.dpy, win->xwin);
cairo_set_source_surface(win->c_ctx, srf, 0, 0);
cairo_paint(win->c_ctx);
cairo_show_page(win->c_ctx);
if (settings.corner_radius != 0 && ! x_win_composited(win))
x_win_corners_shape(win, dim->corner_radius);
else
x_win_corners_unshape(win);
if (settings.corner_radius != 0)
x_win_round_corners(win, dim->corner_radius);
XFlush(xctx.dpy);
}
cairo_t* x_win_get_context(window winptr)
bool x_win_visible(struct window_x11 *win)
{
return ((struct window_x11*)win)->c_ctx;
return win->visible;
}
cairo_t* x_win_get_context(struct window_x11 *win)
{
return win->c_ctx;
}
static void setopacity(Window win, unsigned long opacity)
@ -279,7 +273,7 @@ gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, gpointer
struct window_x11 *win = ((struct x11_source*) source)->win;
bool fullscreen_now;
const struct screen_info *scr;
struct screen_info *scr;
XEvent ev;
unsigned int state;
while (XPending(xctx.dpy) > 0) {
@ -400,47 +394,57 @@ bool x_is_idle(void)
return xctx.screensaver_info->idle > settings.idle_threshold / 1000;
}
/*
* Convert x button code to linux event code
* Returns 0 if button is not recognized.
*/
static unsigned int x_mouse_button_to_linux_event_code(unsigned int x_button)
{
switch (x_button) {
case Button1:
return BTN_LEFT;
case Button2:
return BTN_MIDDLE;
case Button3:
return BTN_RIGHT;
default:
LOG_W("Unsupported mouse button: '%d'", x_button);
return 0;
}
}
/* TODO move to x_mainloop_* */
/*
* Handle incoming mouse click events
*/
static void x_handle_click(XEvent ev)
{
unsigned int linux_code = x_mouse_button_to_linux_event_code(ev.xbutton.button);
enum mouse_action act;
switch (ev.xbutton.button) {
case Button1:
act = settings.mouse_left_click;
break;
case Button2:
act = settings.mouse_middle_click;
break;
case Button3:
act = settings.mouse_right_click;
break;
default:
LOG_W("Unsupported mouse button: '%d'", ev.xbutton.button);
return;
}
if (act == MOUSE_CLOSE_ALL) {
queues_history_push_all();
if (linux_code == 0) {
return;
}
bool button_state;
if(ev.type == ButtonRelease) {
button_state = false; // button is up
} else {
// this shouldn't happen, because this function
// is only called when it'a a ButtonRelease event
button_state = true; // button is down
}
if (act == MOUSE_DO_ACTION || act == MOUSE_CLOSE_CURRENT) {
int y = settings.separator_height;
struct notification *n = NULL;
int first = true;
for (const GList *iter = queues_get_displayed(); iter;
iter = iter->next) {
n = iter->data;
if (ev.xbutton.y > y && ev.xbutton.y < y + n->displayed_height)
break;
input_handle_click(linux_code, button_state, ev.xbutton.x, ev.xbutton.y);
y += n->displayed_height + settings.separator_height;
if (first)
y += settings.frame_width;
}
if (n) {
if (act == MOUSE_CLOSE_CURRENT)
queues_notification_close(n, REASON_USER);
else
notification_do_action(n);
}
}
}
void x_free(void)
@ -496,16 +500,14 @@ static void XRM_update_db(void)
/*
* Setup X11 stuff
*/
bool x_setup(void)
void x_setup(void)
{
/* initialize xctx.dc, font, keyboard, colors */
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
LOG_W("No locale support");
if (!(xctx.dpy = XOpenDisplay(NULL))) {
LOG_W("Cannot open X11 display.");
return false;
DIE("Cannot open X11 display.");
}
x_shortcut_init(&settings.close_ks);
@ -524,12 +526,10 @@ bool x_setup(void)
xctx.screensaver_info = XScreenSaverAllocInfo();
XrmInitialize();
XRM_update_db();
init_screens();
x_shortcut_grab(&settings.history_ks);
return true;
XrmInitialize();
}
struct geometry x_parse_geometry(const char *geom_str)
@ -634,37 +634,22 @@ GSource* x_win_reg_source(struct window_x11 *win)
/*
* Setup the window
*/
window x_win_create(void)
struct window_x11 *x_win_create(void)
{
struct window_x11 *win = g_malloc0(sizeof(struct window_x11));
Window root;
int scr_n;
int depth;
Visual * vis;
XVisualInfo vi;
XSetWindowAttributes wa;
scr_n = DefaultScreen(xctx.dpy);
root = RootWindow(xctx.dpy, scr_n);
if (XMatchVisualInfo(xctx.dpy, scr_n, 32, TrueColor, &vi)) {
vis = vi.visual;
depth = vi.depth;
} else {
vis = DefaultVisual(xctx.dpy, scr_n);
depth = DefaultDepth(xctx.dpy, scr_n);
}
root = RootWindow(xctx.dpy, DefaultScreen(xctx.dpy));
wa.override_redirect = true;
wa.background_pixmap = None;
wa.background_pixel = 0;
wa.border_pixel = 0;
wa.colormap = XCreateColormap(xctx.dpy, root, vis, AllocNone);
wa.background_pixmap = ParentRelative;
wa.event_mask =
ExposureMask | KeyPressMask | VisibilityChangeMask |
ButtonReleaseMask | FocusChangeMask| StructureNotifyMask;
const struct screen_info *scr = get_active_screen();
struct screen_info *scr = get_active_screen();
win->xwin = XCreateWindow(xctx.dpy,
root,
scr->x,
@ -672,10 +657,10 @@ window x_win_create(void)
scr->w,
1,
0,
depth,
DefaultDepth(xctx.dpy, DefaultScreen(xctx.dpy)),
CopyFromParent,
vis,
CWOverrideRedirect | CWBackPixmap | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask,
DefaultVisual(xctx.dpy, DefaultScreen(xctx.dpy)),
CWOverrideRedirect | CWBackPixmap | CWEventMask,
&wa);
x_set_wm(win->xwin);
@ -686,7 +671,7 @@ window x_win_create(void)
(0xffffffff / 100)));
win->root_surface = cairo_xlib_surface_create(xctx.dpy, win->xwin,
vis,
DefaultVisual(xctx.dpy, 0),
WIDTH, HEIGHT);
win->c_ctx = cairo_create(win->root_surface);
@ -706,13 +691,11 @@ window x_win_create(void)
}
XSelectInput(xctx.dpy, root, root_event_mask);
return (window)win;
return win;
}
void x_win_destroy(window winptr)
void x_win_destroy(struct window_x11 *win)
{
struct window_x11 *win = (struct window_x11*)winptr;
g_source_destroy(win->esrc);
g_source_unref(win->esrc);
@ -726,15 +709,12 @@ void x_win_destroy(window winptr)
/*
* Show the window and grab shortcuts.
*/
void x_win_show(window winptr)
void x_win_show(struct window_x11 *win)
{
struct window_x11 *win = (struct window_x11*)winptr;
/* window is already mapped or there's nothing to show */
if (win->visible)
return;
x_shortcut_grab(&settings.close_ks);
x_shortcut_grab(&settings.close_all_ks);
x_shortcut_grab(&settings.context_ks);
@ -756,17 +736,13 @@ void x_win_show(window winptr)
XMapRaised(xctx.dpy, win->xwin);
win->visible = true;
x_display_surface(win->root_surface, win, &win->dim);
}
/*
* Hide the window and ungrab unused keyboard_shortcuts
*/
void x_win_hide(window winptr)
void x_win_hide(struct window_x11 *win)
{
LOG_I("X11: Hiding window");
struct window_x11 *win = (struct window_x11*)winptr;
ASSERT_OR_RET(win->visible,);
x_shortcut_ungrab(&settings.close_ks);
@ -942,8 +918,4 @@ static void x_shortcut_init(struct keyboard_shortcut *ks)
g_free(str_begin);
}
int x_get_scale(void) {
return 1;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -11,8 +11,6 @@
#include <X11/X.h>
#include <X11/Xlib.h>
#include "../output.h"
#include "screen.h"
struct keyboard_shortcut {
@ -26,31 +24,48 @@ struct keyboard_shortcut {
// Cyclical dependency
#include "../settings.h"
struct window_x11;
struct dimensions {
int x;
int y;
int w;
int h;
int corner_radius;
};
struct x_context {
Display *dpy;
XScreenSaverInfo *screensaver_info;
};
struct color {
double r;
double g;
double b;
};
extern struct x_context xctx;
/* window */
window x_win_create(void);
void x_win_destroy(window);
struct window_x11 *x_win_create(void);
void x_win_destroy(struct window_x11 *win);
void x_win_show(window);
void x_win_hide(window);
void x_win_show(struct window_x11 *win);
void x_win_hide(struct window_x11 *win);
void x_display_surface(cairo_surface_t *srf, window, const struct dimensions *dim);
void x_display_surface(cairo_surface_t *srf, struct window_x11 *win, const struct dimensions *dim);
cairo_t* x_win_get_context(window);
bool x_win_visible(struct window_x11 *win);
cairo_t* x_win_get_context(struct window_x11 *win);
/* X misc */
bool x_is_idle(void);
bool x_setup(void);
void x_setup(void);
void x_free(void);
struct geometry x_parse_geometry(const char *geom_str);
int x_get_scale(void);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -27,16 +27,6 @@
unquoted_comment = String with a # comment
color_comment = "#ffffff" # comment
[list]
simple = A,simple,list
spaces = A, list, with, spaces
multiword = A list, with, multiword entries
quoted = "A, quoted, list"
quoted_with_quotes = "A, list, "with quotes""
unquoted_with_quotes = A, list, "with quotes"
quoted_comment = "List, with, a" # comment
unquoted_comment = List, with, a # comment
[path]
expand_tilde = ~/.path/to/tilde

View File

@ -6,7 +6,6 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gio/gio.h>
#include "helpers.h"
#include "queues.h"
extern const char *base;
@ -253,13 +252,33 @@ bool dbus_notification_fire(struct dbus_notification *n, uint *id)
void dbus_notification_set_raw_image(struct dbus_notification *n_dbus, const char *path)
{
GVariant *hint = notification_setup_raw_image(path);
if (!hint)
GdkPixbuf *pb = gdk_pixbuf_new_from_file(path, NULL);
if (!pb)
return;
GVariant *hint_data = g_variant_new_from_data(
G_VARIANT_TYPE("ay"),
gdk_pixbuf_read_pixels(pb),
gdk_pixbuf_get_byte_length(pb),
TRUE,
(GDestroyNotify) g_object_unref,
g_object_ref(pb));
GVariant *hint = g_variant_new(
"(iiibii@ay)",
gdk_pixbuf_get_width(pb),
gdk_pixbuf_get_height(pb),
gdk_pixbuf_get_rowstride(pb),
gdk_pixbuf_get_has_alpha(pb),
gdk_pixbuf_get_bits_per_sample(pb),
gdk_pixbuf_get_n_channels(pb),
hint_data);
g_hash_table_insert(n_dbus->hints,
g_strdup("image-data"),
g_variant_ref_sink(hint));
g_object_unref(pb);
}
/////// TESTS
@ -641,34 +660,6 @@ TEST test_hint_raw_image(void)
PASS();
}
/* We didn't process the timeout parameter via DBus correctly
* and it got limited to an int instead of a long int
* See: Issue #646 (The timeout value in dunst wraps around) */
TEST test_timeout_overflow(void)
{
struct notification *n;
struct dbus_notification *n_dbus;
n_dbus = dbus_notification_new();
n_dbus->app_name = "dunstteststack";
n_dbus->app_icon = "NONE";
n_dbus->summary = "test_hint_urgency";
n_dbus->body = "Summary of it";
n_dbus->expire_timeout = 2147484;
gint64 expected_timeout = G_GINT64_CONSTANT(2147484000);
guint id;
ASSERT(dbus_notification_fire(n_dbus, &id));
ASSERT(id != 0);
n = queues_debug_find_notification_by_id(id);
ASSERT_EQ_FMT(expected_timeout, n->timeout, "%" G_GINT64_FORMAT);
dbus_notification_free(n_dbus);
PASS();
}
TEST test_server_caps(enum markup_mode markup)
{
GVariant *reply;
@ -686,7 +677,6 @@ TEST test_server_caps(enum markup_mode markup)
ASSERT(g_strv_contains(capsarray, "actions"));
ASSERT(g_strv_contains(capsarray, "body"));
ASSERT(g_strv_contains(capsarray, "body-hyperlinks"));
ASSERT(g_strv_contains(capsarray, "icon-static"));
ASSERT(g_strv_contains(capsarray, "x-dunst-stack-tag"));
if (settings.markup != MARKUP_NO)
@ -800,12 +790,6 @@ TEST assert_methodlists_sorted(void)
methods_fdn[i+1].method_name));
}
for (size_t i = 0; i+1 < G_N_ELEMENTS(methods_dunst); i++) {
ASSERT(0 > strcmp(
methods_dunst[i].method_name,
methods_dunst[i+1].method_name));
}
PASS();
}
@ -837,7 +821,6 @@ gpointer run_threaded_tests(gpointer data)
RUN_TESTp(test_server_caps, MARKUP_NO);
RUN_TEST(test_close_and_signal);
RUN_TEST(test_signal_actioninvoked);
RUN_TEST(test_timeout_overflow);
RUN_TEST(assert_methodlists_sorted);
@ -857,10 +840,6 @@ SUITE(suite_dbus)
loop = g_main_loop_new(NULL, false);
dbus_bus = g_test_dbus_new(G_TEST_DBUS_NONE);
// workaround bug in glib where stdout output is duplicated
// See https://gitlab.gnome.org/GNOME/glib/-/issues/2322
fflush(stdout);
g_test_dbus_up(dbus_bus);
thread_tests = g_thread_new("testexecutor", run_threaded_tests, loop);

View File

@ -1,15 +1,6 @@
#define dbus_signal_status_changed(status) signal_sent_stub(status)
#include "../src/dunst.c"
#include "greatest.h"
static bool signal_sent = false;
void signal_sent_stub(struct dunst_status status)
{
signal_sent = true;
return;
}
TEST test_dunst_status(void)
{
status = (struct dunst_status) {false, false, false};

View File

@ -1,7 +1,7 @@
[global]
font = Monospace 8
allow_markup = no
format = "%s\n%b"
format = "<b>%s</b>\n<i>%b</i>"
sort = yes
indicate_hidden = yes
alignment = left

View File

@ -1,10 +0,0 @@
[global]
font = Monospace 8
allow_markup = yes
format = "<b>%s</b>\n%b"
geometry = "0x5-30+20"
icon_position = left
progress_bar_min_width = 100
progress_bar_max_width = 200
progress_bar_frame_width = 5
progress_bar_height = 30

View File

@ -80,17 +80,15 @@ function markup {
killall dunst
../../dunst -config dunstrc.markup "200x0+10+10" &
../../dunstify -a "dunst tester" "Markup Tests" -u "c"
../../dunstify -a "dunst tester" "There should be no markup in the title" -u "c"
../../dunstify -a "dunst tester" "Title" "<b>bold</b> <i>italic</i>"
../../dunstify -a "dunst tester" "Title" "<a href="github.com"> Github link </a>"
../../dunstify -a "dunst tester" "Title" "<b>broken markup</i>"
../../dunstify -a "dunst tester" "<b>bold</b> <i>italic</i>"
../../dunstify -a "dunst tester" "<b>broken markup</i>"
keypress
killall dunst
../../dunst -config dunstrc.nomarkup "200x0+10+10" &
../../dunstify -a "dunst tester" -u c "No markup Tests"
../../dunstify -a "dunst tester" "<b>Title</b>" "<b>bold</b><i>italic</i>"
../../dunstify -a "dunst tester" "<b>Title</b>" "<b>broken markup</i>"
../../dunstify -a "dunst tester" -u c "NO Markup Tests"
../../dunstify -a "dunst tester" "<b>bold</b><i>italic</i>"
../../dunstify -a "dunst tester" "<b>broken markup</i>"
keypress
}
@ -162,13 +160,13 @@ function geometry {
killall dunst
../../dunst -config dunstrc.default -geom "-300x1" &
../../dunstify -a "dunst tester" -u c -- "-300x1"
../../dunstify -a "dunst tester" -u c "-300x1"
basic_notifications
keypress
killall dunst
../../dunst -config dunstrc.default -geom "-300x1-20-20" &
../../dunstify -a "dunst tester" -u c -- "-300x1-20-20"
../../dunstify -a "dunst tester" -u c "-300x1-20-20"
basic_notifications
keypress
@ -179,35 +177,12 @@ function geometry {
keypress
}
function progress_bar {
killall dunst
../../dunst -config dunstrc.default &
../../dunstify -h int:value:0 -a "dunst tester" -u c "Progress bar 0%: "
../../dunstify -h int:value:33 -a "dunst tester" -u c "Progress bar 33%: "
../../dunstify -h int:value:66 -a "dunst tester" -u c "Progress bar 66%: "
../../dunstify -h int:value:100 -a "dunst tester" -u c "Progress bar 100%: "
keypress
killall dunst
../../dunst -config dunstrc.default &
../../dunstify -h int:value:33 -a "dunst tester" -u l "Low priority: "
../../dunstify -h int:value:33 -a "dunst tester" -u n "Normal priority: "
../../dunstify -h int:value:33 -a "dunst tester" -u c "Critical priority: "
keypress
killall dunst
../../dunst -config dunstrc.progress_bar &
../../dunstify -h int:value:33 -a "dunst tester" -u n "The progress bar should not be the entire width"
../../dunstify -h int:value:33 -a "dunst tester" -u n "You might also notice height and frame size are changed"
../../dunstify -h int:value:33 -a "dunst tester" -u c "Short"
keypress
}
if [ -n "$1" ]; then
while [ -n "$1" ]; do
$1
shift
done
else
progress_bar
geometry
corners
show_age

View File

@ -1,33 +0,0 @@
#!/usr/bin/awk -f
# Copyright (c) 2016 Scott Vokes <vokes.s@gmail.com>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
BEGIN {
GREEN = "\033[32m"
RED = "\033[31m"
YELLOW = "\033[33m"
RESET = "\033[m"
}
/^PASS/ { sub("PASS", GREEN "PASS" RESET) }
/^SKIP/ { sub("SKIP", YELLOW "SKIP" RESET) }
/^FAIL/ { sub("FAIL", RED "FAIL" RESET) }
# highlight hexdump difference markers
/^[0-9a-f]/ {
sub("X", GREEN "X" RESET, $2)
gsub("<", GREEN "<" RESET, $0)
}
{ print($0) }

View File

@ -1,35 +0,0 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "helpers.h"
GVariant *notification_setup_raw_image(const char *path)
{
GdkPixbuf *pb = gdk_pixbuf_new_from_file(path, NULL);
if (!pb)
return NULL;
GVariant *hint_data = g_variant_new_from_data(
G_VARIANT_TYPE("ay"),
gdk_pixbuf_read_pixels(pb),
gdk_pixbuf_get_byte_length(pb),
TRUE,
(GDestroyNotify) g_object_unref,
g_object_ref(pb));
GVariant *hint = g_variant_new(
"(iiibii@ay)",
gdk_pixbuf_get_width(pb),
gdk_pixbuf_get_height(pb),
gdk_pixbuf_get_rowstride(pb),
gdk_pixbuf_get_has_alpha(pb),
gdk_pixbuf_get_bits_per_sample(pb),
gdk_pixbuf_get_n_channels(pb),
hint_data);
g_object_unref(pb);
return hint;
}
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -1,9 +0,0 @@
#ifndef DUNST_TEST_HELPERS_H
#define DUNST_TEST_HELPERS_H
#include <glib.h>
GVariant *notification_setup_raw_image(const char *path);
#endif
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -12,69 +12,6 @@
extern const char *base;
int scale = 1;
TEST test_get_path_from_icon_null(void){
char *result = get_path_from_icon_name(NULL);
ASSERT_EQ(result, NULL);
PASS();
}
TEST test_get_path_from_icon_sorting(void)
{
const char *iconpath = ICONPREFIX;
const char* icon_names[] = { "onlypng", "onlysvg", "icon1" };
const char* icon_paths[] = { "valid/onlypng.png", "valid/onlysvg.svg", "invalid/icon1.svg" };
ASSERT_EQm("Test is incorrect", G_N_ELEMENTS(icon_names), G_N_ELEMENTS(icon_paths));
for (int i = 0; i < G_N_ELEMENTS(icon_names); i++){
gchar *path = g_build_filename(base, iconpath, icon_paths[i], NULL);
char *result = get_path_from_icon_name(icon_names[i]);
ASSERT(result);
ASSERT_EQ(strcmp(result, path), 0);
g_free(path);
g_free(result);
}
PASS();
}
TEST test_get_path_from_icon_name(void)
{
const char *iconpath = ICONPREFIX;
const char* icon_name = "onlypng";
const char* expected_suffix = ".png";
char* full_name = g_strconcat(icon_name, expected_suffix, NULL);
gchar *path = g_build_filename(base, iconpath, "valid", full_name, NULL);
char *result = get_path_from_icon_name(icon_name);
ASSERT(result);
ASSERT_EQ(strcmp(result, path), 0);
g_free(full_name);
g_free(path);
g_free(result);
PASS();
}
TEST test_get_path_from_icon_name_full(void)
{
const char *iconpath = ICONPREFIX;
gchar *path = g_build_filename(base, iconpath, "valid", "icon1.svg", NULL);
char *result = get_path_from_icon_name(path);
ASSERT(result);
ASSERT_EQ(strcmp(result, path), 0);
g_free(path);
g_free(result);
PASS();
}
TEST test_get_pixbuf_from_file_tilde(void)
{
const char *home = g_get_home_dir();
@ -88,7 +25,7 @@ TEST test_get_pixbuf_from_file_tilde(void)
gchar *path = g_build_filename(base, iconpath, "valid", "icon1.svg", NULL);
path = string_replace_at(path, 0, strlen(home), "~");
GdkPixbuf *pixbuf = get_pixbuf_from_file(path, scale);
GdkPixbuf *pixbuf = get_pixbuf_from_file(path);
g_clear_pointer(&path, g_free);
ASSERT(pixbuf);
@ -103,7 +40,7 @@ TEST test_get_pixbuf_from_file_absolute(void)
gchar *path = g_build_filename(base, iconpath, "valid", "icon1.svg", NULL);
GdkPixbuf *pixbuf = get_pixbuf_from_file(path, scale);
GdkPixbuf *pixbuf = get_pixbuf_from_file(path);
g_clear_pointer(&path, g_free);
ASSERT(pixbuf);
@ -115,7 +52,7 @@ TEST test_get_pixbuf_from_file_absolute(void)
TEST test_get_pixbuf_from_icon_invalid(void)
{
GdkPixbuf *pixbuf = get_pixbuf_from_icon("invalid", scale);
GdkPixbuf *pixbuf = get_pixbuf_from_icon("invalid");
ASSERT(pixbuf == NULL);
g_clear_pointer(&pixbuf, g_object_unref);
@ -124,9 +61,9 @@ TEST test_get_pixbuf_from_icon_invalid(void)
TEST test_get_pixbuf_from_icon_both(void)
{
GdkPixbuf *pixbuf = get_pixbuf_from_icon("icon1", scale);
// the first icon found is invalid, so the pixbuf is empty
ASSERT(!pixbuf);
GdkPixbuf *pixbuf = get_pixbuf_from_icon("icon1");
ASSERT(pixbuf);
ASSERTm("SVG pixbuf hasn't precedence", IS_ICON_SVG(pixbuf));
g_clear_pointer(&pixbuf, g_object_unref);
PASS();
@ -134,7 +71,7 @@ TEST test_get_pixbuf_from_icon_both(void)
TEST test_get_pixbuf_from_icon_onlysvg(void)
{
GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlysvg", scale);
GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlysvg");
ASSERT(pixbuf);
ASSERTm("SVG pixbuf isn't loaded", IS_ICON_SVG(pixbuf));
g_clear_pointer(&pixbuf, g_object_unref);
@ -144,7 +81,7 @@ TEST test_get_pixbuf_from_icon_onlysvg(void)
TEST test_get_pixbuf_from_icon_onlypng(void)
{
GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlypng", scale);
GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlypng");
ASSERT(pixbuf);
ASSERTm("PNG pixbuf isn't loaded", IS_ICON_PNG(pixbuf));
g_clear_pointer(&pixbuf, g_object_unref);
@ -155,7 +92,7 @@ TEST test_get_pixbuf_from_icon_onlypng(void)
TEST test_get_pixbuf_from_icon_filename(void)
{
char *icon = g_strconcat(base, "/data/icons/valid.png", NULL);
GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon, scale);
GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon);
ASSERT(pixbuf);
ASSERTm("PNG pixbuf isn't loaded", IS_ICON_PNG(pixbuf));
g_clear_pointer(&pixbuf, g_object_unref);
@ -167,7 +104,7 @@ TEST test_get_pixbuf_from_icon_filename(void)
TEST test_get_pixbuf_from_icon_fileuri(void)
{
char *icon = g_strconcat("file://", base, "/data/icons/valid.svg", NULL);
GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon, scale);
GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon);
ASSERT(pixbuf);
ASSERTm("SVG pixbuf isn't loaded", IS_ICON_SVG(pixbuf));
g_clear_pointer(&pixbuf, g_object_unref);
@ -176,80 +113,14 @@ TEST test_get_pixbuf_from_icon_fileuri(void)
PASS();
}
TEST test_icon_size_clamp_too_small(void)
{
int w = 12, h = 24;
bool resized = icon_size_clamp(&w, &h);
ASSERT(resized);
ASSERT_EQ(w, 16);
ASSERT_EQ(h, 32);
PASS();
}
TEST test_icon_size_clamp_not_necessary(void)
{
int w = 20, h = 30;
bool resized = icon_size_clamp(&w, &h);
ASSERT(!resized);
ASSERT_EQ(w, 20);
ASSERT_EQ(h, 30);
PASS();
}
TEST test_icon_size_clamp_too_big(void)
{
int w = 75, h = 150;
bool resized = icon_size_clamp(&w, &h);
ASSERT(resized);
ASSERT_EQ(w, 50);
ASSERT_EQ(h, 100);
PASS();
}
TEST test_icon_size_clamp_too_small_then_too_big(void)
{
int w = 8, h = 80;
bool resized = icon_size_clamp(&w, &h);
ASSERT(resized);
ASSERT_EQ(w, 10);
ASSERT_EQ(h, 100);
PASS();
}
TEST test_get_pixbuf_from_icon_both_is_scaled(void)
{
GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlypng", scale);
ASSERT(pixbuf);
ASSERT_EQ(gdk_pixbuf_get_width(pixbuf), 16);
ASSERT_EQ(gdk_pixbuf_get_height(pixbuf), 16);
g_clear_pointer(&pixbuf, g_object_unref);
PASS();
}
SUITE(suite_icon)
{
// set only valid icons in the path
settings.icon_path = g_strconcat(
base, ICONPREFIX "/valid"
":", base, ICONPREFIX "/both",
NULL);
RUN_TEST(test_get_path_from_icon_name);
g_clear_pointer(&settings.icon_path, g_free);
settings.icon_path = g_strconcat(
base, ICONPREFIX "/invalid"
":", base, ICONPREFIX "/valid"
":", base, ICONPREFIX "/both",
NULL);
RUN_TEST(test_get_path_from_icon_null);
RUN_TEST(test_get_path_from_icon_sorting);
RUN_TEST(test_get_path_from_icon_name_full);
RUN_TEST(test_get_pixbuf_from_file_tilde);
RUN_TEST(test_get_pixbuf_from_file_absolute);
RUN_TEST(test_get_pixbuf_from_icon_invalid);
@ -258,31 +129,6 @@ SUITE(suite_icon)
RUN_TEST(test_get_pixbuf_from_icon_onlypng);
RUN_TEST(test_get_pixbuf_from_icon_filename);
RUN_TEST(test_get_pixbuf_from_icon_fileuri);
RUN_TEST(test_icon_size_clamp_not_necessary);
settings.min_icon_size = 16;
settings.max_icon_size = 100;
RUN_TEST(test_get_pixbuf_from_icon_both_is_scaled);
RUN_TEST(test_icon_size_clamp_too_small);
RUN_TEST(test_icon_size_clamp_not_necessary);
RUN_TEST(test_icon_size_clamp_too_big);
RUN_TEST(test_icon_size_clamp_too_small_then_too_big);
settings.min_icon_size = 16;
settings.max_icon_size = 0;
RUN_TEST(test_icon_size_clamp_too_small);
RUN_TEST(test_icon_size_clamp_not_necessary);
settings.min_icon_size = 0;
settings.max_icon_size = 100;
RUN_TEST(test_icon_size_clamp_not_necessary);
RUN_TEST(test_icon_size_clamp_too_big);
settings.min_icon_size = 0;
settings.max_icon_size = 0;
g_clear_pointer(&settings.icon_path, g_free);
}

View File

@ -1,6 +1,5 @@
#include "../src/notification.c"
#include "greatest.h"
#include "helpers.h"
#include "../src/option_parser.h"
#include "../src/settings.h"
@ -125,76 +124,6 @@ TEST test_notification_referencing(void)
PASS();
}
static struct notification *notification_load_icon_with_scaling(int min_icon_size, int max_icon_size)
{
struct notification *n = notification_create();
char *path = g_strconcat(base, "/data/icons/valid.svg", NULL); // 16x16
GVariant *rawIcon = notification_setup_raw_image(path);
settings.min_icon_size = min_icon_size;
settings.max_icon_size = max_icon_size;
notification_icon_replace_data(n, rawIcon);
settings.min_icon_size = 0;
settings.max_icon_size = 0;
g_variant_unref(rawIcon);
g_free(path);
return n;
}
TEST test_notification_icon_scaling_toosmall(void)
{
struct notification *n = notification_load_icon_with_scaling(20, 100);
ASSERT_EQ(gdk_pixbuf_get_width(n->icon), 20);
ASSERT_EQ(gdk_pixbuf_get_height(n->icon), 20);
notification_unref(n);
PASS();
}
TEST test_notification_icon_scaling_toolarge(void)
{
struct notification *n = notification_load_icon_with_scaling(5, 10);
ASSERT_EQ(gdk_pixbuf_get_width(n->icon), 10);
ASSERT_EQ(gdk_pixbuf_get_height(n->icon), 10);
notification_unref(n);
PASS();
}
TEST test_notification_icon_scaling_notconfigured(void)
{
struct notification *n = notification_load_icon_with_scaling(0, 0);
ASSERT_EQ(gdk_pixbuf_get_width(n->icon), 16);
ASSERT_EQ(gdk_pixbuf_get_height(n->icon), 16);
notification_unref(n);
PASS();
}
TEST test_notification_icon_scaling_notneeded(void)
{
struct notification *n = notification_load_icon_with_scaling(10, 20);
ASSERT_EQ(gdk_pixbuf_get_width(n->icon), 16);
ASSERT_EQ(gdk_pixbuf_get_height(n->icon), 16);
notification_unref(n);
PASS();
}
TEST test_notification_format_message(struct notification *n, const char *format, const char *exp)
{
n->format = format;
@ -238,10 +167,6 @@ SUITE(suite_notification)
RUN_TEST(test_notification_is_duplicate);
RUN_TEST(test_notification_replace_single_field);
RUN_TEST(test_notification_referencing);
RUN_TEST(test_notification_icon_scaling_toosmall);
RUN_TEST(test_notification_icon_scaling_toolarge);
RUN_TEST(test_notification_icon_scaling_notconfigured);
RUN_TEST(test_notification_icon_scaling_notneeded);
// TEST notification_format_message
struct notification *a = notification_create();

View File

@ -8,7 +8,6 @@ TEST test_next_section(void)
const char *section = NULL;
ASSERT_STR_EQ("bool", (section = next_section(section)));
ASSERT_STR_EQ("string", (section = next_section(section)));
ASSERT_STR_EQ("list", (section = next_section(section)));
ASSERT_STR_EQ("path", (section = next_section(section)));
ASSERT_STR_EQ("int", (section = next_section(section)));
ASSERT_STR_EQ("double", (section = next_section(section)));
@ -69,55 +68,6 @@ TEST test_ini_get_string(void)
PASS();
}
enum greatest_test_res ARRAY_EQ(char **a, char **b){
ASSERT(a);
ASSERT(b);
int i = 0;
while (a[i] && b[i]){
ASSERT_STR_EQ(a[i], b[i]);
i++;
}
ASSERT_FALSE(a[i]);
ASSERT_FALSE(b[i]);
PASS();
}
TEST test_ini_get_list(void)
{
char *list_section = "list";
char *cmp1[] = {"A", "simple", "list", NULL};
char *cmp2[] = {"A", "list", "with", "spaces", NULL};
char *cmp3[] = {"A list", "with", "multiword entries", NULL};
char *cmp4[] = {"A", "quoted", "list", NULL};
char *cmp5[] = {"A", "list", "\"with quotes\"", NULL};
char *cmp6[] = {"List", "with", "a", NULL};
char **ptr;
CHECK_CALL(ARRAY_EQ(cmp1, (ptr = ini_get_list(list_section, "simple", ""))));
free_string_array(ptr);
CHECK_CALL(ARRAY_EQ(cmp2, (ptr = ini_get_list(list_section, "spaces", ""))));
free_string_array(ptr);
CHECK_CALL(ARRAY_EQ(cmp3, (ptr = ini_get_list(list_section, "multiword", ""))));
free_string_array(ptr);
CHECK_CALL(ARRAY_EQ(cmp4, (ptr = ini_get_list(list_section, "quoted", ""))));
free_string_array(ptr);
CHECK_CALL(ARRAY_EQ(cmp5, (ptr = ini_get_list(list_section, "quoted_with_quotes", ""))));
free_string_array(ptr);
CHECK_CALL(ARRAY_EQ(cmp5, (ptr = ini_get_list(list_section, "unquoted_with_quotes", ""))));
free_string_array(ptr);
CHECK_CALL(ARRAY_EQ(cmp6, (ptr = ini_get_list(list_section, "quoted_comment", ""))));
free_string_array(ptr);
CHECK_CALL(ARRAY_EQ(cmp6, (ptr = ini_get_list(list_section, "unquoted_comment", ""))));
free_string_array(ptr);
PASS();
}
TEST test_ini_get_path(void)
{
char *section = "path";
@ -201,22 +151,6 @@ TEST test_cmdline_get_string(void)
PASS();
}
TEST test_cmdline_get_list(void)
{
char **ptr;
char *cmp1[] = {"A", "simple", "list", "from", "the", "cmdline", NULL};
char *cmp2[] = {"A", "list", "with", "spaces", NULL};
char *cmp3[] = {"A", "default", "list", NULL};
CHECK_CALL(ARRAY_EQ(cmp1, (ptr = cmdline_get_list("-list", "", ""))));
free_string_array(ptr);
CHECK_CALL(ARRAY_EQ(cmp2, (ptr = cmdline_get_list("-list2", "", ""))));
free_string_array(ptr);
CHECK_CALL(ARRAY_EQ(cmp3, (ptr = cmdline_get_list("-nonexistent", "A, default, list", ""))));
free_string_array(ptr);
PASS();
}
TEST test_cmdline_get_int(void)
{
ASSERT_EQ(3, cmdline_get_int("-int", 0, ""));
@ -287,29 +221,6 @@ TEST test_option_get_string(void)
PASS();
}
TEST test_option_get_list(void)
{
char *list_section = "list";
char **ptr;
char *cmp1[] = {"A", "simple", "list", NULL};
char *cmp2[] = {"A", "list", "with", "spaces", NULL};
char *cmp3[] = {"A", "simple", "list", "from", "the", "cmdline", NULL};
char *cmp4[] = {"A", "default", "list", NULL};
CHECK_CALL(ARRAY_EQ(cmp1, (ptr = option_get_list(list_section, "simple", "-nonexistent", "", ""))));
free_string_array(ptr);
CHECK_CALL(ARRAY_EQ(cmp2, (ptr = option_get_list(list_section, "quoted", "-list2", "", ""))));
free_string_array(ptr);
CHECK_CALL(ARRAY_EQ(cmp3, (ptr = option_get_list(list_section, "simple", "-list", "", ""))));
free_string_array(ptr);
CHECK_CALL(ARRAY_EQ(cmp3, (ptr = option_get_list(list_section, "simple", "-list/-l", "", ""))));
free_string_array(ptr);
CHECK_CALL(ARRAY_EQ(cmp4, (ptr = option_get_list(list_section, "nonexistent", "-nonexistent", "A, default, list", ""))));
free_string_array(ptr);
PASS();
}
TEST test_option_get_path(void)
{
char *section = "path";
@ -397,13 +308,11 @@ SUITE(suite_option_parser)
RUN_TEST(test_next_section);
RUN_TEST(test_ini_get_bool);
RUN_TEST(test_ini_get_string);
RUN_TEST(test_ini_get_list);
RUN_TEST(test_ini_get_path);
RUN_TEST(test_ini_get_int);
RUN_TEST(test_ini_get_double);
char cmdline[] = "dunst -bool -b "
"-string \"A simple string from the cmdline\" -s Single_word_string "
"-list A,simple,list,from,the,cmdline -list2 \"A, list, with, spaces\" "
"-int 3 -i 2 -negative -7 -zeroes 04 -intdecim 2.5 "
"-path ~/path/from/cmdline "
"-simple_double 2 -double 5.2"
@ -413,7 +322,6 @@ SUITE(suite_option_parser)
g_shell_parse_argv(&cmdline[0], &argc, &argv, NULL);
cmdline_load(argc, argv);
RUN_TEST(test_cmdline_get_string);
RUN_TEST(test_cmdline_get_list);
RUN_TEST(test_cmdline_get_path);
RUN_TEST(test_cmdline_get_int);
RUN_TEST(test_cmdline_get_double);
@ -421,7 +329,6 @@ SUITE(suite_option_parser)
RUN_TEST(test_cmdline_create_usage);
RUN_TEST(test_option_get_string);
RUN_TEST(test_option_get_list);
RUN_TEST(test_option_get_path);
RUN_TEST(test_option_get_int);
RUN_TEST(test_option_get_double);

View File

@ -740,91 +740,6 @@ TEST test_queues_timeout_before_paused(void)
PASS();
}
TEST test_queue_find_by_id(void)
{
struct notification *n;
int id;
queues_init();
n = test_notification("n", 0);
queues_notification_insert(n);
n = test_notification("n1", 0);
queues_notification_insert(n);
id = n->id;
n = test_notification("n2", 0);
queues_notification_insert(n);
n = queues_get_by_id(id);
ASSERT(n->id == id);
ASSERT(!strncmp(n->summary, "n1", 2));
queues_teardown();
PASS();
}
void print_queues() {
printf("\nQueues:\n");
for (GList *iter = g_queue_peek_head_link(QUEUE_WAIT); iter;
iter = iter->next) {
struct notification *notif = iter->data;
printf("waiting %s\n", notif->summary);
}
}
// Test if notifications are correctly sorted, even if dunst is paused in
// between. See #838 for the issue.
TEST test_queue_no_sort_and_pause(void)
{
// Setting sort to false, this means that notifications will only be
// sorted based on time
settings.sort = false;
settings.geometry.h = 0;
struct notification *n;
queues_init();
n = test_notification("n0", 0);
queues_notification_insert(n);
queues_update(STATUS_NORMAL);
n = test_notification("n1", 0);
queues_notification_insert(n);
queues_update(STATUS_NORMAL);
n = test_notification("n2", 0);
queues_notification_insert(n);
queues_update(STATUS_PAUSE);
n = test_notification("n3", 0);
queues_notification_insert(n);
queues_update(STATUS_PAUSE);
/* queues_update(STATUS_NORMAL); */
n = test_notification("n4", 0);
queues_notification_insert(n);
queues_update(STATUS_NORMAL);
QUEUE_LEN_ALL(0, 5, 0);
const char* order[] = {
"n0",
"n1",
"n2",
"n3",
"n4",
};
for (int i = 0; i < g_queue_get_length(QUEUE_DISP); i++) {
struct notification *notif = g_queue_peek_nth(QUEUE_DISP, i);
ASSERTm("Notifications are not in the right order",
STR_EQ(notif->summary, order[i]));
}
queues_teardown();
PASS();
}
SUITE(suite_queues)
{
settings.icon_path = "";
@ -855,8 +770,6 @@ SUITE(suite_queues)
RUN_TEST(test_queues_update_seeping);
RUN_TEST(test_queues_update_xmore);
RUN_TEST(test_queues_timeout_before_paused);
RUN_TEST(test_queue_find_by_id);
RUN_TEST(test_queue_no_sort_and_pause);
settings.icon_path = NULL;
}

View File

@ -1,32 +1,24 @@
#!/usr/bin/env bash
# Throw error any time a command fails
set -euo pipefail
BASE="$(dirname "$(dirname "$(readlink -f "$0")")")"
DESTDIR="${BASE}/install"
PREFIX="/testprefix"
SYSCONFDIR="/sysconfdir"
PREFIX="${BASE}/install"
make -C "${BASE}" SYSTEMD=1 DESTDIR="${DESTDIR}" PREFIX="${PREFIX}" SYSCONFDIR="${SYSCONFDIR}" SERVICEDIR_SYSTEMD="/systemd" SERVICEDIR_DBUS="/dbus" install
make -C "${BASE}" SYSTEMD=1 SERVICEDIR_SYSTEMD="${PREFIX}/systemd" SERVICEDIR_DBUS="${PREFIX}/dbus" PREFIX="${PREFIX}" install
diff -u <(find "${DESTDIR}" -type f -printf "%P\n" | sort) - <<EOF
diff -u <(find "${PREFIX}" -type f -printf "%P\n" | sort) - <<EOF
bin/dunst
dbus/org.knopwob.dunst.service
sysconfdir/dunst/dunstrc
share/dunst/dunstrc
share/man/man1/dunst.1
systemd/dunst.service
testprefix/bin/dunst
testprefix/bin/dunstctl
testprefix/bin/dunstify
testprefix/share/man/man1/dunst.1
testprefix/share/man/man1/dunstctl.1
testprefix/share/man/man5/dunst.5
EOF
# make sure to manually sort the above values
make -C "${BASE}" SYSTEMD=1 DESTDIR="${DESTDIR}" PREFIX="${PREFIX}" SYSCONFDIR="${SYSCONFDIR}" SERVICEDIR_SYSTEMD="/systemd" SERVICEDIR_DBUS="/dbus" uninstall
make -C "${BASE}" SYSTEMD=1 SERVICEDIR_SYSTEMD="${PREFIX}/systemd" SERVICEDIR_DBUS="${PREFIX}/dbus" PREFIX="${PREFIX}" uninstall
if ! [ -z "$(find "${DESTDIR}" -type f)" ]; then
if ! [ -z "$(find "${PREFIX}" -type f)" ]; then
echo "Uninstall failed, following files weren't removed"
find "${DESTDIR}" -type f
find "${PREFIX}" -type f
exit 1
fi