Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ee460335d | ||
|
|
988b8d2747 | ||
|
|
9f4f110c53 | ||
|
|
e898fa589a | ||
|
|
702abc7a03 | ||
|
|
b77f76f02e | ||
|
|
cf091bea37 | ||
|
|
1040febfb9 | ||
|
|
652cb7efb4 | ||
|
|
7d91f978eb | ||
|
|
0994c57b3e | ||
|
|
cb6f2ca3b3 | ||
|
|
bd6abfcc5d | ||
|
|
1d3822ee8b | ||
|
|
ea531ca9ae | ||
|
|
e69adcefea | ||
|
|
f2017eb3d6 | ||
|
|
d9282b7f86 | ||
|
|
efac6e70b0 | ||
|
|
0dfc4ed738 | ||
|
|
b49925c86d | ||
|
|
8e80871c50 | ||
|
|
d5ee1febca | ||
|
|
941c527af9 | ||
|
|
b66f8f362d | ||
|
|
85ff05062c | ||
|
|
db5e6ce8f4 | ||
|
|
aad4dbaf3d | ||
|
|
98a61f0896 | ||
|
|
7c6620c92d | ||
|
|
75af42c83a | ||
|
|
c4e428e9d5 | ||
|
|
5c0d7ea662 | ||
|
|
176aad4f3c | ||
|
|
af49b76586 | ||
|
|
6c61f3e5e2 | ||
|
|
bec5e9d25a | ||
|
|
790342b913 | ||
|
|
4234813417 | ||
|
|
d65f69b4db | ||
|
|
b75d35adb4 | ||
|
|
3acffdb194 | ||
|
|
7e22272ebb | ||
|
|
7292bfcd89 | ||
|
|
8413ade9d7 | ||
|
|
54b665898f | ||
|
|
f8a2ff48b3 | ||
|
|
a8b2058fcf | ||
|
|
ceca7cfcc7 | ||
|
|
598ec5797e | ||
|
|
0f588998fe | ||
|
|
500b00b344 | ||
|
|
36186d37ea | ||
|
|
d7f93a3a69 |
1
.github/workflows/main.yml
vendored
@ -25,6 +25,7 @@ jobs:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
CC: ${{ matrix.CC }}
|
CC: ${{ matrix.CC }}
|
||||||
|
EXTRA_CFLAGS: "-Werror"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
|
|||||||
@ -1,5 +1,11 @@
|
|||||||
# Dunst changelog
|
# Dunst changelog
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
### Changed
|
||||||
|
### Fixed
|
||||||
|
|
||||||
## 1.6.1 - 2021-02-21:
|
## 1.6.1 - 2021-02-21:
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@ -15,6 +15,10 @@
|
|||||||
- Add the comments to the prototype. Doxygen will merge the protoype and implementation documentation anyways.
|
- 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*.
|
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
|
- 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
|
## Log messages
|
||||||
|
|
||||||
|
|||||||
8
Makefile
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
include config.mk
|
include config.mk
|
||||||
|
|
||||||
VERSION := "1.6.1 (2021-02-21)"
|
VERSION := "1.6.1-non-git"
|
||||||
ifneq ($(wildcard ./.git/),)
|
ifneq ($(wildcard ./.git/),)
|
||||||
VERSION := $(shell ${GIT} describe --tags)
|
VERSION := $(shell ${GIT} describe --tags)
|
||||||
endif
|
endif
|
||||||
@ -148,7 +148,8 @@ service-systemd:
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq (0,${WAYLAND})
|
ifneq (0,${WAYLAND})
|
||||||
wayland-protocols: src/wayland/protocols/wlr-layer-shell-unstable-v1.xml
|
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
|
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 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}/stable/xdg-shell/xdg-shell.xml src/wayland/protocols/xdg-shell-client-header.h
|
||||||
@ -158,6 +159,8 @@ wayland-protocols: src/wayland/protocols/wlr-layer-shell-unstable-v1.xml
|
|||||||
wayland-scanner private-code src/wayland/protocols/wlr-layer-shell-unstable-v1.xml src/wayland/protocols/wlr-layer-shell-unstable-v1.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 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 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
|
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-wayland-protocols
|
||||||
@ -175,6 +178,7 @@ clean-dunstify:
|
|||||||
|
|
||||||
clean-doc:
|
clean-doc:
|
||||||
rm -f docs/dunst.1
|
rm -f docs/dunst.1
|
||||||
|
rm -f docs/dunst.5
|
||||||
rm -f docs/dunstctl.1
|
rm -f docs/dunstctl.1
|
||||||
rm -fr docs/internal/html
|
rm -fr docs/internal/html
|
||||||
rm -fr docs/internal/coverage
|
rm -fr docs/internal/coverage
|
||||||
|
|||||||
106
README.md
@ -1,34 +1,95 @@
|
|||||||
[](https://github.com/dunst-project/dunst/actions?query=workflow%3Amain) [](https://codecov.io/gh/dunst-project/dunst)
|
[](https://github.com/dunst-project/dunst/actions?query=workflow%3Amain) [](https://codecov.io/gh/dunst-project/dunst)
|
||||||
|
|
||||||
## Dunst
|
# Dunst
|
||||||
|
|
||||||
* [Wiki][wiki]
|
<i>A highly configurable and lightweight notification daemon.</i>
|
||||||
* [Description](#description)
|
|
||||||
* [Compiling](#compiling)
|

|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
* [Features](#features)
|
||||||
|
* [Building](#building)
|
||||||
|
* [Documentation](#documentation)
|
||||||
* [Copyright](#copyright)
|
* [Copyright](#copyright)
|
||||||
|
|
||||||
## Description
|
# Features
|
||||||
|
|
||||||
Dunst is a highly configurable and lightweight notification daemon.
|
## ⚙️ Highly customizable
|
||||||
|
|
||||||
|
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
|
## 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
|
### Dependencies
|
||||||
|
|
||||||
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 (runtime)
|
||||||
|
|
||||||
- dbus
|
|
||||||
- libxinerama
|
- libxinerama
|
||||||
- libxrandr
|
- libxrandr
|
||||||
- libxss
|
- libxss
|
||||||
- glib
|
- glib
|
||||||
- pango/cairo
|
- pango/cairo
|
||||||
- libgtk-3-dev
|
- libnotify (optional, for dunstify)
|
||||||
- libnotify (for dunstify only)
|
|
||||||
- wayland-client (can build without, see [make parameters](#make-parameters))
|
- wayland-client (can build without, see [make parameters](#make-parameters))
|
||||||
- wayland-protocols (optional, for recompiling protocols)
|
- wayland-protocols (optional, for recompiling protocols)
|
||||||
|
|
||||||
|
The names will be different depending on your [distribution](https://github.com/dunst-project/dunst/wiki/Dependencies).
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -49,14 +110,23 @@ sudo make install
|
|||||||
- `WAYLAND=(0|1)`: Disable/Enable wayland support. (Default: 1 (enabled))
|
- `WAYLAND=(0|1)`: Disable/Enable wayland support. (Default: 1 (enabled))
|
||||||
- `SERVICEDIR_SYSTEMD=<PATH>`: The path to put the systemd user service file. Unused, if `SYSTEMD=0`. (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`)
|
- `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.**
|
**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
|
## Bug reports
|
||||||
|
|
||||||
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.
|
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>
|
||||||
|
|
||||||
## Maintainers
|
## Maintainers
|
||||||
|
|
||||||
@ -65,13 +135,13 @@ Please use the [issue tracker][issue-tracker] provided by GitHub to send us bug
|
|||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
written by Sascha Kruse <dunst@knopwob.de>
|
Written by Sascha Kruse <dunst@knopwob.de>
|
||||||
|
|
||||||
## Copyright
|
## 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
|
[issue-tracker]: https://github.com/dunst-project/dunst/issues
|
||||||
[wiki]: https://github.com/dunst-project/dunst/wiki
|
[wiki]: https://github.com/dunst-project/dunst/wiki
|
||||||
|
[website]: https://dunst-project.org
|
||||||
|
[FAQ]: https://dunst-project.org/faq
|
||||||
|
|||||||
@ -6,6 +6,7 @@ DATADIR ?= ${PREFIX}/share
|
|||||||
# around for backwards compatibility
|
# around for backwards compatibility
|
||||||
MANPREFIX ?= ${DATADIR}/man
|
MANPREFIX ?= ${DATADIR}/man
|
||||||
MANDIR ?= ${MANPREFIX}
|
MANDIR ?= ${MANPREFIX}
|
||||||
|
EXTRA_CFLAGS ?=
|
||||||
|
|
||||||
DOXYGEN ?= doxygen
|
DOXYGEN ?= doxygen
|
||||||
FIND ?= find
|
FIND ?= find
|
||||||
@ -36,7 +37,7 @@ endif
|
|||||||
|
|
||||||
# flags
|
# flags
|
||||||
DEFAULT_CPPFLAGS = -D_DEFAULT_SOURCE -DVERSION=\"${VERSION}\"
|
DEFAULT_CPPFLAGS = -D_DEFAULT_SOURCE -DVERSION=\"${VERSION}\"
|
||||||
DEFAULT_CFLAGS = -g --std=gnu99 -pedantic -Wall -Wno-overlength-strings -Os ${STATIC} ${ENABLE_WAYLAND}
|
DEFAULT_CFLAGS = -g --std=gnu99 -pedantic -Wall -Wno-overlength-strings -Os ${STATIC} ${ENABLE_WAYLAND} ${EXTRA_CFLAGS}
|
||||||
DEFAULT_LDFLAGS = -lm -lrt
|
DEFAULT_LDFLAGS = -lm -lrt
|
||||||
|
|
||||||
CPPFLAGS_DEBUG := -DDEBUG_BUILD
|
CPPFLAGS_DEBUG := -DDEBUG_BUILD
|
||||||
|
|||||||
BIN
contrib/screenshots/default_config.png
Normal file
|
After Width: | Height: | Size: 388 KiB |
BIN
contrib/screenshots/music.png
Normal file
|
After Width: | Height: | Size: 406 KiB |
BIN
contrib/screenshots/screenshot1.png
Normal file
|
After Width: | Height: | Size: 672 KiB |
BIN
contrib/screenshots/screenshot1_cut.png
Normal file
|
After Width: | Height: | Size: 214 KiB |
BIN
contrib/screenshots/screenshot2.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
contrib/screenshots/screenshot2_cut.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
contrib/screenshots/screenshot3.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
contrib/screenshots/screenshot3_cut.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
contrib/screenshots/screenshot_urgency.png
Normal file
|
After Width: | Height: | Size: 393 KiB |
@ -10,6 +10,15 @@ dunst [-conf file] [-font font] [-geometry geom] [-format fmt] [-follow mode] [-
|
|||||||
|
|
||||||
Dunst is a highly configurable and lightweight notification daemon.
|
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
|
=head1 COMMAND LINE OPTIONS
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
@ -160,4 +169,4 @@ If you feel that copyrights are violated, please send me an email.
|
|||||||
|
|
||||||
=head1 SEE ALSO
|
=head1 SEE ALSO
|
||||||
|
|
||||||
dunst(5), dunstctl(1), dwm(1), dmenu(1), twmn(1), notify-send(1)
|
dunst(5), dunstctl(1), dmenu(1), notify-send(1)
|
||||||
|
|||||||
@ -249,9 +249,6 @@ Place dunst notifications on the selected layer. Using overlay
|
|||||||
will cause notifications to be displayed above fullscreen windows, though
|
will cause notifications to be displayed above fullscreen windows, though
|
||||||
this may also occur at top depending on your compositor.
|
this may also occur at top depending on your compositor.
|
||||||
|
|
||||||
In Wayland, Notifications won't be delayed when in fullscreen (like when
|
|
||||||
setting B<fullscreen> to pushback in X11). This is a Wayland limitation.
|
|
||||||
|
|
||||||
The bottom layer is below all windows and above the background.
|
The bottom layer is below all windows and above the background.
|
||||||
|
|
||||||
Default: overlay
|
Default: overlay
|
||||||
@ -514,9 +511,10 @@ single notification.
|
|||||||
To avoid the corners clipping the icon or text the corner radius will be
|
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.
|
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])
|
=item B<mouse_left/middle/right_click> (values: [none/do_action/close_current/close_all/context/context_all])
|
||||||
|
|
||||||
Defines action of mouse click.
|
Defines action of mouse click. A touch input in Wayland acts as a mouse left
|
||||||
|
click.
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
@ -526,7 +524,13 @@ Don't do anything.
|
|||||||
|
|
||||||
=item B<do_action> (default for mouse_middle_click)
|
=item B<do_action> (default for mouse_middle_click)
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
=item B<close_current> (default for mouse_left_click)
|
=item B<close_current> (default for mouse_left_click)
|
||||||
|
|
||||||
@ -536,6 +540,14 @@ Close current notification.
|
|||||||
|
|
||||||
Close all notifications.
|
Close all notifications.
|
||||||
|
|
||||||
|
=item B<context>
|
||||||
|
|
||||||
|
Open context menu for the notification.
|
||||||
|
|
||||||
|
=item B<context_all>
|
||||||
|
|
||||||
|
Open context menu for all notifications.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|
||||||
@ -662,9 +674,15 @@ 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
|
is more focused on security, some things that are possible in X11 are not
|
||||||
possible in Wayland. Those differences are reflected in the configuration.
|
possible in Wayland. Those differences are reflected in the configuration.
|
||||||
The main things that change are that dunst on Wayland cannot use global
|
The main things that change are that dunst on Wayland cannot use global
|
||||||
hotkeys (they are deprecated anyways, use dunstctl) and it cannot detect
|
hotkeys (they are deprecated anyways, use dunstctl).
|
||||||
if an application is fullscreen. If you want to see notifications when in
|
|
||||||
fullscreen, set B<layer = overlay> in the global options.
|
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.
|
Note that the same limitations exist when using xwayland.
|
||||||
If something doesn't quite work in Wayland, please file a bug report. In the
|
If something doesn't quite work in Wayland, please file a bug report. In the
|
||||||
@ -791,7 +809,7 @@ Equivalent to the C<format> setting.
|
|||||||
|
|
||||||
The frame color color of the notification. See COLORS for possible values.
|
The frame color color of the notification. See COLORS for possible values.
|
||||||
|
|
||||||
=item C<fullscreen> (X11 only)
|
=item C<fullscreen>
|
||||||
|
|
||||||
One of show, delay, or pushback.
|
One of show, delay, or pushback.
|
||||||
|
|
||||||
@ -806,7 +824,13 @@ Or pushback which is equivalent to delay with the difference that already
|
|||||||
existing notifications are paused and hidden until the focus to the fullscreen
|
existing notifications are paused and hidden until the focus to the fullscreen
|
||||||
window is lost.
|
window is lost.
|
||||||
|
|
||||||
See B<layer> to change fullscreen behavior in Wayland
|
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
|
Default: show
|
||||||
|
|
||||||
@ -850,6 +874,13 @@ later. Use C<msg_urgency> to match it.
|
|||||||
Setting this to true will prevent the notification from being displayed
|
Setting this to true will prevent the notification from being displayed
|
||||||
initially but will be saved in history for later viewing.
|
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
|
=back
|
||||||
|
|
||||||
As with the filtering attributes, each one corresponds to
|
As with the filtering attributes, each one corresponds to
|
||||||
@ -910,6 +941,46 @@ 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.
|
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.
|
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
|
=over 4
|
||||||
|
|
||||||
=item notify-send -h string:fgcolor:#ff4444
|
=item notify-send -h string:fgcolor:#ff4444
|
||||||
@ -1010,4 +1081,4 @@ If you feel that copyrights are violated, please send me an email.
|
|||||||
|
|
||||||
=head1 SEE ALSO
|
=head1 SEE ALSO
|
||||||
|
|
||||||
dunstctl(1), dwm(1), dmenu(1), twmn(1), notify-send(1)
|
dunst(1), dunstctl(1), dmenu(1), notify-send(1)
|
||||||
|
|||||||
33
docs/internal/release-checklist.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# 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
|
||||||
9
dunstrc
@ -277,10 +277,14 @@
|
|||||||
# Defines list of actions for each mouse event
|
# Defines list of actions for each mouse event
|
||||||
# Possible values are:
|
# Possible values are:
|
||||||
# * none: Don't do anything.
|
# * none: Don't do anything.
|
||||||
# * do_action: If the notification has exactly one action, or one is marked as default,
|
# * do_action: Invoke the action determined by the action_name rule. If there is no
|
||||||
# invoke it. If there are multiple and no default, open the context menu.
|
# 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.
|
||||||
# * close_current: Close current notification.
|
# * close_current: Close current notification.
|
||||||
# * close_all: Close all notifications.
|
# * 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
|
# These values can be strung together for each mouse event, and
|
||||||
# will be executed in sequence.
|
# will be executed in sequence.
|
||||||
mouse_left_click = close_current
|
mouse_left_click = close_current
|
||||||
@ -373,6 +377,7 @@
|
|||||||
# set_transient
|
# set_transient
|
||||||
# timeout
|
# timeout
|
||||||
# urgency
|
# urgency
|
||||||
|
# action_name
|
||||||
#
|
#
|
||||||
# Shell-like globbing will get expanded.
|
# Shell-like globbing will get expanded.
|
||||||
#
|
#
|
||||||
|
|||||||
@ -307,6 +307,7 @@ static void dbus_cb_GetCapabilities(
|
|||||||
g_variant_builder_add(builder, "s", "actions");
|
g_variant_builder_add(builder, "s", "actions");
|
||||||
g_variant_builder_add(builder, "s", "body");
|
g_variant_builder_add(builder, "s", "body");
|
||||||
g_variant_builder_add(builder, "s", "body-hyperlinks");
|
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)
|
for (int i = 0; i < sizeof(stack_tag_hints)/sizeof(*stack_tag_hints); ++i)
|
||||||
g_variant_builder_add(builder, "s", stack_tag_hints[i]);
|
g_variant_builder_add(builder, "s", stack_tag_hints[i]);
|
||||||
@ -385,6 +386,11 @@ static struct notification *dbus_message_to_notification(const gchar *sender, GV
|
|||||||
g_variant_unref(dict_value);
|
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))) {
|
if ((dict_value = g_variant_lookup_value(hints, "category", G_VARIANT_TYPE_STRING))) {
|
||||||
n->category = g_variant_dup_string(dict_value, NULL);
|
n->category = g_variant_dup_string(dict_value, NULL);
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
|
|||||||
122
src/draw.c
@ -51,7 +51,6 @@ void draw_setup(void)
|
|||||||
const struct output *out = output_create(settings.force_xwayland);
|
const struct output *out = output_create(settings.force_xwayland);
|
||||||
output = out;
|
output = out;
|
||||||
|
|
||||||
out->init();
|
|
||||||
win = out->win_create();
|
win = out->win_create();
|
||||||
|
|
||||||
pango_fdesc = pango_font_description_from_string(settings.font);
|
pango_fdesc = pango_font_description_from_string(settings.font);
|
||||||
@ -142,10 +141,11 @@ static struct color layout_get_sepcolor(struct colored_layout *cl,
|
|||||||
|
|
||||||
static void layout_setup_pango(PangoLayout *layout, int width)
|
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_wrap(layout, PANGO_WRAP_WORD_CHAR);
|
||||||
pango_layout_set_width(layout, width * PANGO_SCALE);
|
pango_layout_set_width(layout, width * scale * PANGO_SCALE);
|
||||||
pango_layout_set_font_description(layout, pango_fdesc);
|
pango_layout_set_font_description(layout, pango_fdesc);
|
||||||
pango_layout_set_spacing(layout, settings.line_height * PANGO_SCALE);
|
pango_layout_set_spacing(layout, settings.line_height * scale * PANGO_SCALE);
|
||||||
|
|
||||||
PangoAlignment align;
|
PangoAlignment align;
|
||||||
switch (settings.align) {
|
switch (settings.align) {
|
||||||
@ -193,9 +193,20 @@ static bool have_progress_bar(const struct notification *n)
|
|||||||
return (n->progress >= 0 && settings.progress_bar == true);
|
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)
|
static struct dimensions calculate_dimensions(GSList *layouts)
|
||||||
{
|
{
|
||||||
struct dimensions dim = { 0 };
|
struct dimensions dim = { 0 };
|
||||||
|
int scale = output->get_scale();
|
||||||
|
|
||||||
const struct screen_info *scr = output->get_active_screen();
|
const struct screen_info *scr = output->get_active_screen();
|
||||||
if (have_dynamic_width()) {
|
if (have_dynamic_width()) {
|
||||||
@ -222,10 +233,10 @@ static struct dimensions calculate_dimensions(GSList *layouts)
|
|||||||
for (GSList *iter = layouts; iter; iter = iter->next) {
|
for (GSList *iter = layouts; iter; iter = iter->next) {
|
||||||
struct colored_layout *cl = iter->data;
|
struct colored_layout *cl = iter->data;
|
||||||
int w=0,h=0;
|
int w=0,h=0;
|
||||||
pango_layout_get_pixel_size(cl->l, &w, &h);
|
get_text_size(cl->l, &w, &h, scale);
|
||||||
if (cl->icon) {
|
if (cl->icon) {
|
||||||
h = MAX(cairo_image_surface_get_height(cl->icon), h);
|
h = MAX(get_icon_height(cl->icon, scale), h);
|
||||||
w += cairo_image_surface_get_width(cl->icon) + settings.h_padding;
|
w += get_icon_width(cl->icon, scale) + settings.h_padding;
|
||||||
}
|
}
|
||||||
h = MAX(settings.notification_height, h + settings.padding * 2);
|
h = MAX(settings.notification_height, h + settings.padding * 2);
|
||||||
dim.h += h;
|
dim.h += h;
|
||||||
@ -251,15 +262,15 @@ static struct dimensions calculate_dimensions(GSList *layouts)
|
|||||||
w -= 2 * settings.h_padding;
|
w -= 2 * settings.h_padding;
|
||||||
w -= 2 * settings.frame_width;
|
w -= 2 * settings.frame_width;
|
||||||
if (cl->icon) {
|
if (cl->icon) {
|
||||||
w -= cairo_image_surface_get_width(cl->icon) + get_text_icon_padding();
|
w -= get_icon_width(cl->icon, scale) + get_text_icon_padding();
|
||||||
}
|
}
|
||||||
layout_setup_pango(cl->l, w);
|
layout_setup_pango(cl->l, w);
|
||||||
|
|
||||||
/* re-read information */
|
/* re-read information */
|
||||||
pango_layout_get_pixel_size(cl->l, &w, &h);
|
get_text_size(cl->l, &w, &h, scale);
|
||||||
if (cl->icon) {
|
if (cl->icon) {
|
||||||
h = MAX(cairo_image_surface_get_height(cl->icon), h);
|
h = MAX(get_icon_height(cl->icon, scale), h);
|
||||||
w += cairo_image_surface_get_width(cl->icon) + settings.h_padding;
|
w += get_icon_width(cl->icon, scale) + settings.h_padding;
|
||||||
}
|
}
|
||||||
h = MAX(settings.notification_height, h + settings.padding * 2);
|
h = MAX(settings.notification_height, h + settings.padding * 2);
|
||||||
dim.h += h;
|
dim.h += h;
|
||||||
@ -300,6 +311,7 @@ static struct colored_layout *layout_init_shared(cairo_t *c, const struct notifi
|
|||||||
{
|
{
|
||||||
struct colored_layout *cl = g_malloc(sizeof(struct colored_layout));
|
struct colored_layout *cl = g_malloc(sizeof(struct colored_layout));
|
||||||
cl->l = layout_create(c);
|
cl->l = layout_create(c);
|
||||||
|
int scale = output->get_scale();
|
||||||
|
|
||||||
if (!settings.word_wrap) {
|
if (!settings.word_wrap) {
|
||||||
PangoEllipsizeMode ellipsize;
|
PangoEllipsizeMode ellipsize;
|
||||||
@ -347,7 +359,7 @@ static struct colored_layout *layout_init_shared(cairo_t *c, const struct notifi
|
|||||||
width -= 2 * settings.h_padding;
|
width -= 2 * settings.h_padding;
|
||||||
width -= 2 * settings.frame_width;
|
width -= 2 * settings.frame_width;
|
||||||
if (cl->icon) {
|
if (cl->icon) {
|
||||||
width -= cairo_image_surface_get_width(cl->icon) + get_text_icon_padding();
|
width -= get_icon_width(cl->icon, scale) + get_text_icon_padding();
|
||||||
}
|
}
|
||||||
layout_setup_pango(cl->l, width);
|
layout_setup_pango(cl->l, width);
|
||||||
}
|
}
|
||||||
@ -368,6 +380,7 @@ static struct colored_layout *layout_from_notification(cairo_t *c, struct notifi
|
|||||||
{
|
{
|
||||||
|
|
||||||
struct colored_layout *cl = layout_init_shared(c, n);
|
struct colored_layout *cl = layout_init_shared(c, n);
|
||||||
|
int scale = output->get_scale();
|
||||||
|
|
||||||
/* markup */
|
/* markup */
|
||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
@ -389,8 +402,8 @@ static struct colored_layout *layout_from_notification(cairo_t *c, struct notifi
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pango_layout_get_pixel_size(cl->l, NULL, &(n->displayed_height));
|
get_text_size(cl->l, NULL, &(n->displayed_height), scale);
|
||||||
if (cl->icon) n->displayed_height = MAX(cairo_image_surface_get_height(cl->icon), n->displayed_height);
|
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;
|
n->displayed_height = n->displayed_height + settings.padding * 2;
|
||||||
|
|
||||||
@ -436,14 +449,14 @@ static GSList *create_layouts(cairo_t *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int layout_get_height(struct colored_layout *cl)
|
static int layout_get_height(struct colored_layout *cl, int scale)
|
||||||
{
|
{
|
||||||
int h;
|
int h;
|
||||||
int h_icon = 0;
|
int h_icon = 0;
|
||||||
int h_progress_bar = 0;
|
int h_progress_bar = 0;
|
||||||
pango_layout_get_pixel_size(cl->l, NULL, &h);
|
get_text_size(cl->l, NULL, &h, scale);
|
||||||
if (cl->icon)
|
if (cl->icon)
|
||||||
h_icon = cairo_image_surface_get_height(cl->icon);
|
h_icon = get_icon_height(cl->icon, scale);
|
||||||
if (have_progress_bar(cl->n)){
|
if (have_progress_bar(cl->n)){
|
||||||
h_progress_bar = settings.progress_bar_height + settings.padding;
|
h_progress_bar = settings.progress_bar_height + settings.padding;
|
||||||
}
|
}
|
||||||
@ -483,8 +496,14 @@ static int frame_internal_radius (int r, int w, int h)
|
|||||||
* The top corners will get rounded by `corner_radius`, if `first` is set.
|
* The top corners will get rounded by `corner_radius`, if `first` is set.
|
||||||
* Respectably the same for `last` with the bottom corners.
|
* 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, bool first, bool last)
|
void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, int scale, bool first, bool last)
|
||||||
{
|
{
|
||||||
|
width *= scale;
|
||||||
|
height *= scale;
|
||||||
|
x *= scale;
|
||||||
|
y *= scale;
|
||||||
|
corner_radius *= scale;
|
||||||
|
|
||||||
const float degrees = M_PI / 180.0;
|
const float degrees = M_PI / 180.0;
|
||||||
|
|
||||||
cairo_new_sub_path(c);
|
cairo_new_sub_path(c);
|
||||||
@ -532,6 +551,13 @@ void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corn
|
|||||||
cairo_close_path(c);
|
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,
|
static cairo_surface_t *render_background(cairo_surface_t *srf,
|
||||||
struct colored_layout *cl,
|
struct colored_layout *cl,
|
||||||
struct colored_layout *cl_next,
|
struct colored_layout *cl_next,
|
||||||
@ -541,7 +567,8 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
|
|||||||
int corner_radius,
|
int corner_radius,
|
||||||
bool first,
|
bool first,
|
||||||
bool last,
|
bool last,
|
||||||
int *ret_width)
|
int *ret_width,
|
||||||
|
int scale)
|
||||||
{
|
{
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int radius_int = corner_radius;
|
int radius_int = corner_radius;
|
||||||
@ -561,7 +588,7 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
|
|||||||
else
|
else
|
||||||
height += settings.separator_height;
|
height += settings.separator_height;
|
||||||
|
|
||||||
draw_rounded_rect(c, x, y, width, height, corner_radius, first, last);
|
draw_rounded_rect(c, x, y, width, height, corner_radius, scale, first, last);
|
||||||
|
|
||||||
/* adding frame */
|
/* adding frame */
|
||||||
x += settings.frame_width;
|
x += settings.frame_width;
|
||||||
@ -579,11 +606,11 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
|
|||||||
|
|
||||||
radius_int = frame_internal_radius(corner_radius, settings.frame_width, height);
|
radius_int = frame_internal_radius(corner_radius, settings.frame_width, height);
|
||||||
|
|
||||||
draw_rounded_rect(c, x, y, width, height, radius_int, first, last);
|
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_rgba(c, cl->frame.r, cl->frame.g, cl->frame.b, cl->frame.a);
|
||||||
cairo_fill(c);
|
cairo_fill(c);
|
||||||
|
|
||||||
draw_rounded_rect(c, x, y, width, height, radius_int, first, last);
|
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_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a);
|
||||||
cairo_fill(c);
|
cairo_fill(c);
|
||||||
|
|
||||||
@ -595,7 +622,7 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
|
|||||||
struct color sep_color = layout_get_sepcolor(cl, cl_next);
|
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_rgba(c, sep_color.r, sep_color.g, sep_color.b, sep_color.a);
|
||||||
|
|
||||||
cairo_rectangle(c, settings.frame_width, y + height, width, settings.separator_height);
|
draw_rect(c, settings.frame_width, y + height, width, settings.separator_height, scale);
|
||||||
|
|
||||||
cairo_fill(c);
|
cairo_fill(c);
|
||||||
}
|
}
|
||||||
@ -605,18 +632,18 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
|
|||||||
if (ret_width)
|
if (ret_width)
|
||||||
*ret_width = width;
|
*ret_width = width;
|
||||||
|
|
||||||
return cairo_surface_create_for_rectangle(srf, x, y, width, height);
|
return cairo_surface_create_for_rectangle(srf, x * scale, y * scale, width * scale, height * scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void render_content(cairo_t *c, struct colored_layout *cl, int width)
|
static void render_content(cairo_t *c, struct colored_layout *cl, int width, int scale)
|
||||||
{
|
{
|
||||||
const int h = layout_get_height(cl);
|
const int h = layout_get_height(cl, scale);
|
||||||
int h_without_progress_bar = h;
|
int h_without_progress_bar = h;
|
||||||
if (have_progress_bar(cl->n)){
|
if (have_progress_bar(cl->n)){
|
||||||
h_without_progress_bar -= settings.progress_bar_height + settings.padding;
|
h_without_progress_bar -= settings.progress_bar_height + settings.padding;
|
||||||
}
|
}
|
||||||
int h_text;
|
int h_text;
|
||||||
pango_layout_get_pixel_size(cl->l, NULL, &h_text);
|
get_text_size(cl->l, NULL, &h_text, scale);
|
||||||
|
|
||||||
int text_x = settings.h_padding,
|
int text_x = settings.h_padding,
|
||||||
text_y = settings.padding + h_without_progress_bar / 2 - h_text / 2;
|
text_y = settings.padding + h_without_progress_bar / 2 - h_text / 2;
|
||||||
@ -634,10 +661,10 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width)
|
|||||||
|
|
||||||
// icon position
|
// icon position
|
||||||
if (settings.icon_position == ICON_LEFT) {
|
if (settings.icon_position == ICON_LEFT) {
|
||||||
text_x = cairo_image_surface_get_width(cl->icon) + settings.h_padding + get_text_icon_padding();
|
text_x = get_icon_width(cl->icon, scale) + settings.h_padding + get_text_icon_padding();
|
||||||
} // else ICON_RIGHT
|
} // else ICON_RIGHT
|
||||||
}
|
}
|
||||||
cairo_move_to(c, text_x, text_y);
|
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_rgba(c, cl->fg.r, cl->fg.g, cl->fg.b, cl->fg.a);
|
||||||
pango_cairo_update_layout(c, cl->l);
|
pango_cairo_update_layout(c, cl->l);
|
||||||
@ -646,8 +673,8 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width)
|
|||||||
|
|
||||||
// icon positioning
|
// icon positioning
|
||||||
if (cl->icon) {
|
if (cl->icon) {
|
||||||
unsigned int image_width = cairo_image_surface_get_width(cl->icon),
|
unsigned int image_width = get_icon_width(cl->icon, scale),
|
||||||
image_height = cairo_image_surface_get_height(cl->icon),
|
image_height = get_icon_height(cl->icon, scale),
|
||||||
image_x = width - settings.h_padding - image_width,
|
image_x = width - settings.h_padding - image_width,
|
||||||
image_y = settings.padding + h_without_progress_bar/2 - image_height/2;
|
image_y = settings.padding + h_without_progress_bar/2 - image_height/2;
|
||||||
|
|
||||||
@ -665,8 +692,8 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width)
|
|||||||
image_x = settings.h_padding;
|
image_x = settings.h_padding;
|
||||||
} // else ICON_RIGHT
|
} // else ICON_RIGHT
|
||||||
|
|
||||||
cairo_set_source_surface(c, cl->icon, image_x, image_y);
|
cairo_set_source_surface(c, cl->icon, image_x * scale, image_y * scale);
|
||||||
cairo_rectangle(c, image_x, image_y, image_width, image_height);
|
draw_rect(c, image_x, image_y, image_width, image_height, scale);
|
||||||
cairo_fill(c);
|
cairo_fill(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,16 +717,17 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width)
|
|||||||
// Note: the bar could be drawn a bit smaller, because the frame is drawn on top
|
// Note: the bar could be drawn a bit smaller, because the frame is drawn on top
|
||||||
// left side
|
// left side
|
||||||
cairo_set_source_rgba(c, cl->highlight.r, cl->highlight.g, cl->highlight.b, cl->highlight.a);
|
cairo_set_source_rgba(c, cl->highlight.r, cl->highlight.g, cl->highlight.b, cl->highlight.a);
|
||||||
cairo_rectangle(c, x_bar_1, frame_y, progress_width_1, progress_height);
|
draw_rect(c, x_bar_1, frame_y, progress_width_1, progress_height, scale);
|
||||||
cairo_fill(c);
|
cairo_fill(c);
|
||||||
// right side
|
// right side
|
||||||
cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a);
|
cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a);
|
||||||
cairo_rectangle(c, x_bar_2, frame_y, progress_width_2, progress_height);
|
draw_rect(c, x_bar_2, frame_y, progress_width_2, progress_height, scale);
|
||||||
cairo_fill(c);
|
cairo_fill(c);
|
||||||
// border
|
// border
|
||||||
cairo_set_source_rgba(c, cl->frame.r, cl->frame.g, cl->frame.b, cl->frame.a);
|
cairo_set_source_rgba(c, cl->frame.r, cl->frame.g, cl->frame.b, cl->frame.a);
|
||||||
cairo_rectangle(c, frame_x + half_frame_width, frame_y + half_frame_width, progress_width - frame_width, progress_height);
|
// TODO draw_rect instead of cairo_rectangle resulted in blurry lines. Why?
|
||||||
cairo_set_line_width(c, frame_width);
|
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);
|
cairo_stroke(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -711,18 +739,19 @@ static struct dimensions layout_render(cairo_surface_t *srf,
|
|||||||
bool first,
|
bool first,
|
||||||
bool last)
|
bool last)
|
||||||
{
|
{
|
||||||
const int cl_h = layout_get_height(cl);
|
int scale = output->get_scale();
|
||||||
|
const int cl_h = layout_get_height(cl, scale);
|
||||||
|
|
||||||
int h_text = 0;
|
int h_text = 0;
|
||||||
pango_layout_get_pixel_size(cl->l, NULL, &h_text);
|
get_text_size(cl->l, NULL, &h_text, scale);
|
||||||
|
|
||||||
int bg_width = 0;
|
int bg_width = 0;
|
||||||
int bg_height = MAX(settings.notification_height, (2 * settings.padding) + cl_h);
|
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);
|
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_t *c = cairo_create(content);
|
cairo_t *c = cairo_create(content);
|
||||||
|
|
||||||
render_content(c, cl, bg_width);
|
render_content(c, cl, bg_width, scale);
|
||||||
|
|
||||||
/* adding frame */
|
/* adding frame */
|
||||||
if (first)
|
if (first)
|
||||||
@ -774,8 +803,9 @@ void draw(void)
|
|||||||
GSList *layouts = create_layouts(output->win_get_context(win));
|
GSList *layouts = create_layouts(output->win_get_context(win));
|
||||||
|
|
||||||
struct dimensions dim = calculate_dimensions(layouts);
|
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, dim.h);
|
cairo_surface_t *image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dim.w * scale, dim.h * scale);
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (GSList *iter = layouts; iter; iter = iter->next) {
|
for (GSList *iter = layouts; iter; iter = iter->next) {
|
||||||
@ -800,4 +830,14 @@ void draw_deinit(void)
|
|||||||
output->win_destroy(win);
|
output->win_destroy(win);
|
||||||
output->deinit();
|
output->deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
|||||||
@ -12,9 +12,13 @@ void draw_setup(void);
|
|||||||
|
|
||||||
void draw(void);
|
void draw(void);
|
||||||
|
|
||||||
void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, bool first, bool last);
|
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);
|
void draw_deinit(void);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
|||||||
10
src/dunst.c
@ -24,6 +24,7 @@
|
|||||||
GMainLoop *mainloop = NULL;
|
GMainLoop *mainloop = NULL;
|
||||||
|
|
||||||
static struct dunst_status status;
|
static struct dunst_status status;
|
||||||
|
static bool setup_done = false;
|
||||||
|
|
||||||
/* see dunst.h */
|
/* see dunst.h */
|
||||||
void dunst_status(const enum dunst_status_field field,
|
void dunst_status(const enum dunst_status_field field,
|
||||||
@ -56,6 +57,14 @@ static gboolean run(void *data);
|
|||||||
|
|
||||||
void wake_up(void)
|
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");
|
LOG_D("Waking up");
|
||||||
run(NULL);
|
run(NULL);
|
||||||
}
|
}
|
||||||
@ -197,6 +206,7 @@ int dunst_main(int argc, char *argv[])
|
|||||||
// we do not call wakeup now, wake_up does not work here yet
|
// we do not call wakeup now, wake_up does not work here yet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_done = true;
|
||||||
run(NULL);
|
run(NULL);
|
||||||
g_main_loop_run(mainloop);
|
g_main_loop_run(mainloop);
|
||||||
g_clear_pointer(&mainloop, g_main_loop_unref);
|
g_clear_pointer(&mainloop, g_main_loop_unref);
|
||||||
|
|||||||
43
src/icon.c
@ -86,6 +86,14 @@ 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)
|
cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf)
|
||||||
{
|
{
|
||||||
assert(pixbuf);
|
assert(pixbuf);
|
||||||
@ -144,22 +152,26 @@ static bool icon_size_clamp(int *w, int *h) {
|
|||||||
*
|
*
|
||||||
* @param pixbuf (nullable) The pixbuf, which may be too big.
|
* @param pixbuf (nullable) The pixbuf, which may be too big.
|
||||||
* Takes ownership of the reference.
|
* 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
|
* @return the scaled version of the pixbuf. If scaling wasn't
|
||||||
* necessary, it returns the same pixbuf. Transfers full
|
* necessary, it returns the same pixbuf. Transfers full
|
||||||
* ownership of the reference.
|
* ownership of the reference.
|
||||||
*/
|
*/
|
||||||
static GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf)
|
static GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf, int dpi_scale)
|
||||||
{
|
{
|
||||||
ASSERT_OR_RET(pixbuf, NULL);
|
ASSERT_OR_RET(pixbuf, NULL);
|
||||||
|
|
||||||
int w = gdk_pixbuf_get_width(pixbuf);
|
int w = gdk_pixbuf_get_width(pixbuf);
|
||||||
int h = gdk_pixbuf_get_height(pixbuf);
|
int h = gdk_pixbuf_get_height(pixbuf);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO immediately rescale icon upon scale changes
|
||||||
if (icon_size_clamp(&w, &h)) {
|
if (icon_size_clamp(&w, &h)) {
|
||||||
GdkPixbuf *scaled = gdk_pixbuf_scale_simple(
|
GdkPixbuf *scaled = gdk_pixbuf_scale_simple(
|
||||||
pixbuf,
|
pixbuf,
|
||||||
w,
|
w * dpi_scale,
|
||||||
h,
|
h * dpi_scale,
|
||||||
GDK_INTERP_BILINEAR);
|
GDK_INTERP_BILINEAR);
|
||||||
g_object_unref(pixbuf);
|
g_object_unref(pixbuf);
|
||||||
pixbuf = scaled;
|
pixbuf = scaled;
|
||||||
@ -168,7 +180,7 @@ static GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf)
|
|||||||
return pixbuf;
|
return pixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
GdkPixbuf *get_pixbuf_from_file(const char *filename)
|
GdkPixbuf *get_pixbuf_from_file(const char *filename, int scale)
|
||||||
{
|
{
|
||||||
char *path = string_to_path(g_strdup(filename));
|
char *path = string_to_path(g_strdup(filename));
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
@ -179,10 +191,11 @@ GdkPixbuf *get_pixbuf_from_file(const char *filename)
|
|||||||
g_free(path);
|
g_free(path);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
// TODO immediately rescale icon upon scale changes
|
||||||
icon_size_clamp(&w, &h);
|
icon_size_clamp(&w, &h);
|
||||||
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_scale(path,
|
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_scale(path,
|
||||||
w,
|
w * scale,
|
||||||
h,
|
h * scale,
|
||||||
TRUE,
|
TRUE,
|
||||||
&error);
|
&error);
|
||||||
|
|
||||||
@ -250,7 +263,7 @@ char *get_path_from_icon_name(const char *iconname)
|
|||||||
return new_name;
|
return new_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
GdkPixbuf *get_pixbuf_from_icon(const char *iconname)
|
GdkPixbuf *get_pixbuf_from_icon(const char *iconname, int scale)
|
||||||
{
|
{
|
||||||
char *path = get_path_from_icon_name(iconname);
|
char *path = get_path_from_icon_name(iconname);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
@ -259,7 +272,7 @@ GdkPixbuf *get_pixbuf_from_icon(const char *iconname)
|
|||||||
|
|
||||||
GdkPixbuf *pixbuf = NULL;
|
GdkPixbuf *pixbuf = NULL;
|
||||||
|
|
||||||
pixbuf = get_pixbuf_from_file(path);
|
pixbuf = get_pixbuf_from_file(path, scale);
|
||||||
g_free(path);
|
g_free(path);
|
||||||
|
|
||||||
if (!pixbuf)
|
if (!pixbuf)
|
||||||
@ -268,18 +281,18 @@ GdkPixbuf *get_pixbuf_from_icon(const char *iconname)
|
|||||||
return pixbuf;
|
return pixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
GdkPixbuf *icon_get_for_name(const char *name, char **id)
|
GdkPixbuf *icon_get_for_name(const char *name, char **id, int scale)
|
||||||
{
|
{
|
||||||
ASSERT_OR_RET(name, NULL);
|
ASSERT_OR_RET(name, NULL);
|
||||||
ASSERT_OR_RET(id, NULL);
|
ASSERT_OR_RET(id, NULL);
|
||||||
|
|
||||||
GdkPixbuf *pb = get_pixbuf_from_icon(name);
|
GdkPixbuf *pb = get_pixbuf_from_icon(name, scale);
|
||||||
if (pb)
|
if (pb)
|
||||||
*id = g_strdup(name);
|
*id = g_strdup(name);
|
||||||
return pb;
|
return pb;
|
||||||
}
|
}
|
||||||
|
|
||||||
GdkPixbuf *icon_get_for_data(GVariant *data, char **id)
|
GdkPixbuf *icon_get_for_data(GVariant *data, char **id, int dpi_scale)
|
||||||
{
|
{
|
||||||
ASSERT_OR_RET(data, NULL);
|
ASSERT_OR_RET(data, NULL);
|
||||||
ASSERT_OR_RET(id, NULL);
|
ASSERT_OR_RET(id, NULL);
|
||||||
@ -347,7 +360,13 @@ GdkPixbuf *icon_get_for_data(GVariant *data, char **id)
|
|||||||
return NULL;
|
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);
|
data_pb = (guchar *) g_memdup(g_variant_get_data(data_variant), len_actual);
|
||||||
|
#endif
|
||||||
|
|
||||||
pixbuf = gdk_pixbuf_new_from_data(data_pb,
|
pixbuf = gdk_pixbuf_new_from_data(data_pb,
|
||||||
GDK_COLORSPACE_RGB,
|
GDK_COLORSPACE_RGB,
|
||||||
@ -383,7 +402,7 @@ GdkPixbuf *icon_get_for_data(GVariant *data, char **id)
|
|||||||
g_free(data_chk);
|
g_free(data_chk);
|
||||||
g_variant_unref(data_variant);
|
g_variant_unref(data_variant);
|
||||||
|
|
||||||
pixbuf = icon_pixbuf_scale(pixbuf);
|
pixbuf = icon_pixbuf_scale(pixbuf, dpi_scale);
|
||||||
|
|
||||||
return pixbuf;
|
return pixbuf;
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/icon.h
@ -11,11 +11,26 @@ cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf);
|
|||||||
/** Retrieve an icon by its full filepath, scaled according to settings.
|
/** Retrieve an icon by its full filepath, scaled according to settings.
|
||||||
*
|
*
|
||||||
* @param filename A string representing a readable file path
|
* @param filename A string representing a readable file path
|
||||||
|
* @param scale An integer representing the output dpi scaling.
|
||||||
*
|
*
|
||||||
* @return an instance of `GdkPixbuf`
|
* @return an instance of `GdkPixbuf`
|
||||||
* @retval NULL: file does not exist, not readable, etc..
|
* @retval NULL: file does not exist, not readable, etc..
|
||||||
*/
|
*/
|
||||||
GdkPixbuf *get_pixbuf_from_file(const char *filename);
|
GdkPixbuf *get_pixbuf_from_file(const char *filename, int scale);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 a path from an icon name.
|
||||||
*
|
*
|
||||||
@ -33,11 +48,12 @@ char *get_path_from_icon_name(const char *iconname);
|
|||||||
* @param iconname A string describing a `file://` URL, an arbitary filename
|
* @param iconname A string describing a `file://` URL, an arbitary filename
|
||||||
* or an icon name, which then gets searched for in the
|
* or an icon name, which then gets searched for in the
|
||||||
* settings.icon_path
|
* settings.icon_path
|
||||||
|
* @param scale An integer representing the output dpi scaling.
|
||||||
*
|
*
|
||||||
* @return an instance of `GdkPixbuf`
|
* @return an instance of `GdkPixbuf`
|
||||||
* @retval NULL: file does not exist, not readable, etc..
|
* @retval NULL: file does not exist, not readable, etc..
|
||||||
*/
|
*/
|
||||||
GdkPixbuf *get_pixbuf_from_icon(const char *iconname);
|
GdkPixbuf *get_pixbuf_from_icon(const char *iconname, int scale);
|
||||||
|
|
||||||
/** 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, scaled according to settings
|
||||||
*
|
*
|
||||||
@ -49,10 +65,11 @@ GdkPixbuf *get_pixbuf_from_icon(const char *iconname);
|
|||||||
* get searched in the folders of the icon_path setting.
|
* get searched in the folders of the icon_path setting.
|
||||||
* @param id (necessary) A unique identifier of the returned pixbuf. Only filled,
|
* @param id (necessary) A unique identifier of the returned pixbuf. Only filled,
|
||||||
* if the return value is non-NULL.
|
* 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
|
* @return an instance of `GdkPixbuf`, representing the name's image
|
||||||
* @retval NULL: Invalid path given
|
* @retval NULL: Invalid path given
|
||||||
*/
|
*/
|
||||||
GdkPixbuf *icon_get_for_name(const char *name, char **id);
|
GdkPixbuf *icon_get_for_name(const char *name, char **id, int dpi_scale);
|
||||||
|
|
||||||
/** Convert a GVariant like described in GdkPixbuf, scaled according to settings
|
/** Convert a GVariant like described in GdkPixbuf, scaled according to settings
|
||||||
*
|
*
|
||||||
@ -63,10 +80,11 @@ GdkPixbuf *icon_get_for_name(const char *name, char **id);
|
|||||||
* like described in the notification spec.
|
* like described in the notification spec.
|
||||||
* @param id (necessary) A unique identifier of the returned pixbuf.
|
* @param id (necessary) A unique identifier of the returned pixbuf.
|
||||||
* Only filled, if the return value is non-NULL.
|
* 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
|
* @return an instance of `GdkPixbuf` derived from the GVariant
|
||||||
* @retval NULL: GVariant parameter nulled, invalid or in wrong format
|
* @retval NULL: GVariant parameter nulled, invalid or in wrong format
|
||||||
*/
|
*/
|
||||||
GdkPixbuf *icon_get_for_data(GVariant *data, char **id);
|
GdkPixbuf *icon_get_for_data(GVariant *data, char **id, int scale);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
|||||||
20
src/input.c
@ -1,5 +1,6 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "menu.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "queues.h"
|
#include "queues.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@ -25,6 +26,10 @@ void input_handle_click(unsigned int button, bool button_down, int mouse_x, int
|
|||||||
case BTN_RIGHT:
|
case BTN_RIGHT:
|
||||||
acts = settings.mouse_right_click;
|
acts = settings.mouse_right_click;
|
||||||
break;
|
break;
|
||||||
|
case BTN_TOUCH:
|
||||||
|
// TODO Add separate action for touch
|
||||||
|
acts = settings.mouse_left_click;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_W("Unsupported mouse button: '%d'", button);
|
LOG_W("Unsupported mouse button: '%d'", button);
|
||||||
return;
|
return;
|
||||||
@ -34,10 +39,15 @@ void input_handle_click(unsigned int button, bool button_down, int mouse_x, int
|
|||||||
enum mouse_action act = acts[i];
|
enum mouse_action act = acts[i];
|
||||||
if (act == MOUSE_CLOSE_ALL) {
|
if (act == MOUSE_CLOSE_ALL) {
|
||||||
queues_history_push_all();
|
queues_history_push_all();
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (act == MOUSE_DO_ACTION || act == MOUSE_CLOSE_CURRENT) {
|
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;
|
int y = settings.separator_height;
|
||||||
struct notification *n = NULL;
|
struct notification *n = NULL;
|
||||||
int first = true;
|
int first = true;
|
||||||
@ -55,8 +65,12 @@ void input_handle_click(unsigned int button, bool button_down, int mouse_x, int
|
|||||||
if (n) {
|
if (n) {
|
||||||
if (act == MOUSE_CLOSE_CURRENT) {
|
if (act == MOUSE_CLOSE_CURRENT) {
|
||||||
n->marked_for_closure = REASON_USER;
|
n->marked_for_closure = REASON_USER;
|
||||||
} else {
|
} else if (act == MOUSE_DO_ACTION) {
|
||||||
notification_do_action(n);
|
notification_do_action(n);
|
||||||
|
} else if (act == MOUSE_OPEN_URL) {
|
||||||
|
notification_open_url(n);
|
||||||
|
} else {
|
||||||
|
notification_open_context_menu(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/log.c
@ -74,19 +74,21 @@ static void dunst_log_handler(
|
|||||||
gpointer testing)
|
gpointer testing)
|
||||||
{
|
{
|
||||||
if (testing)
|
if (testing)
|
||||||
return;
|
log_level = G_LOG_LEVEL_ERROR;
|
||||||
|
|
||||||
|
GLogLevelFlags message_level_masked = message_level & G_LOG_LEVEL_MASK;
|
||||||
|
|
||||||
/* if you want to have a debug build, you want to log anything,
|
/* if you want to have a debug build, you want to log anything,
|
||||||
* unconditionally, without specifying debug log level again */
|
* unconditionally, without specifying debug log level again */
|
||||||
#ifndef DEBUG_BUILD
|
#ifndef DEBUG_BUILD
|
||||||
if (log_level < message_level)
|
if (log_level < message_level_masked)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
const char *log_level_str =
|
const char *log_level_str =
|
||||||
log_level_to_string(message_level & G_LOG_LEVEL_MASK);
|
log_level_to_string(message_level_masked);
|
||||||
|
|
||||||
/* Use stderr for warnings and higher */
|
/* Use stderr for warnings and higher */
|
||||||
if (message_level <= G_LOG_LEVEL_WARNING)
|
if (message_level_masked <= G_LOG_LEVEL_WARNING)
|
||||||
g_printerr("%s: %s\n", log_level_str, message);
|
g_printerr("%s: %s\n", log_level_str, message);
|
||||||
else
|
else
|
||||||
g_print("%s: %s\n", log_level_str, message);
|
g_print("%s: %s\n", log_level_str, message);
|
||||||
|
|||||||
@ -312,13 +312,19 @@ static GList *get_actionable_notifications(void)
|
|||||||
|
|
||||||
/* see menu.h */
|
/* see menu.h */
|
||||||
void context_menu(void)
|
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) {
|
if (menu_ctx.locked_notifications) {
|
||||||
LOG_W("Context menu already running, refusing to rerun");
|
LOG_W("Context menu already running, refusing to rerun");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GList *notifications = get_actionable_notifications();
|
|
||||||
menu_ctx.locked_notifications = notifications;
|
menu_ctx.locked_notifications = notifications;
|
||||||
|
|
||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
|
|||||||
10
src/menu.h
@ -2,6 +2,8 @@
|
|||||||
#ifndef DUNST_MENU_H
|
#ifndef DUNST_MENU_H
|
||||||
#define DUNST_MENU_H
|
#define DUNST_MENU_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract all urls from the given string.
|
* Extract all urls from the given string.
|
||||||
*
|
*
|
||||||
@ -16,9 +18,15 @@ void invoke_action(const char *action);
|
|||||||
void regex_teardown(void);
|
void regex_teardown(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the context menu that lets the user select urls/actions/etc.
|
* Open the context menu that lets the user select urls/actions/etc for all displayed notifications.
|
||||||
*/
|
*/
|
||||||
void context_menu(void);
|
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
|
#endif
|
||||||
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
#include "rules.h"
|
#include "rules.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "draw.h"
|
||||||
|
|
||||||
static void notification_extract_urls(struct notification *n);
|
static void notification_extract_urls(struct notification *n);
|
||||||
static void notification_format_message(struct notification *n);
|
static void notification_format_message(struct notification *n);
|
||||||
@ -192,7 +193,7 @@ const char *notification_urgency_to_string(const enum urgency urgency)
|
|||||||
/* see notification.h */
|
/* see notification.h */
|
||||||
int notification_cmp(const struct notification *a, const struct notification *b)
|
int notification_cmp(const struct notification *a, const struct notification *b)
|
||||||
{
|
{
|
||||||
if (a->urgency != b->urgency) {
|
if (settings.sort && a->urgency != b->urgency) {
|
||||||
return b->urgency - a->urgency;
|
return b->urgency - a->urgency;
|
||||||
} else {
|
} else {
|
||||||
return a->id - b->id;
|
return a->id - b->id;
|
||||||
@ -205,8 +206,6 @@ int notification_cmp_data(const void *va, const void *vb, void *data)
|
|||||||
struct notification *a = (struct notification *) va;
|
struct notification *a = (struct notification *) va;
|
||||||
struct notification *b = (struct notification *) vb;
|
struct notification *b = (struct notification *) vb;
|
||||||
|
|
||||||
ASSERT_OR_RET(settings.sort, 1);
|
|
||||||
|
|
||||||
return notification_cmp(a, b);
|
return notification_cmp(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,6 +287,7 @@ void notification_unref(struct notification *n)
|
|||||||
g_free(n->desktop_entry);
|
g_free(n->desktop_entry);
|
||||||
|
|
||||||
g_hash_table_unref(n->actions);
|
g_hash_table_unref(n->actions);
|
||||||
|
g_free(n->default_action_name);
|
||||||
|
|
||||||
if (n->icon)
|
if (n->icon)
|
||||||
g_object_unref(n->icon);
|
g_object_unref(n->icon);
|
||||||
@ -314,7 +314,7 @@ void notification_icon_replace_path(struct notification *n, const char *new_icon
|
|||||||
g_clear_object(&n->icon);
|
g_clear_object(&n->icon);
|
||||||
g_clear_pointer(&n->icon_id, g_free);
|
g_clear_pointer(&n->icon_id, g_free);
|
||||||
|
|
||||||
n->icon = icon_get_for_name(new_icon, &n->icon_id);
|
n->icon = icon_get_for_name(new_icon, &n->icon_id, draw_get_scale());
|
||||||
}
|
}
|
||||||
|
|
||||||
void notification_icon_replace_data(struct notification *n, GVariant *new_icon)
|
void notification_icon_replace_data(struct notification *n, GVariant *new_icon)
|
||||||
@ -325,7 +325,7 @@ void notification_icon_replace_data(struct notification *n, GVariant *new_icon)
|
|||||||
g_clear_object(&n->icon);
|
g_clear_object(&n->icon);
|
||||||
g_clear_pointer(&n->icon_id, g_free);
|
g_clear_pointer(&n->icon_id, g_free);
|
||||||
|
|
||||||
n->icon = icon_get_for_data(new_icon, &n->icon_id);
|
n->icon = icon_get_for_data(new_icon, &n->icon_id, draw_get_scale());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see notification.h */
|
/* see notification.h */
|
||||||
@ -386,6 +386,7 @@ struct notification *notification_create(void)
|
|||||||
n->fullscreen = FS_SHOW;
|
n->fullscreen = FS_SHOW;
|
||||||
|
|
||||||
n->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
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;
|
n->script_count = 0;
|
||||||
return n;
|
return n;
|
||||||
@ -647,27 +648,43 @@ void notification_update_text_to_render(struct notification *n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* see notification.h */
|
/* see notification.h */
|
||||||
void notification_do_action(const struct notification *n)
|
void notification_do_action(struct notification *n)
|
||||||
{
|
{
|
||||||
|
assert(n->default_action_name);
|
||||||
|
|
||||||
if (g_hash_table_size(n->actions)) {
|
if (g_hash_table_size(n->actions)) {
|
||||||
if (g_hash_table_contains(n->actions, "default")) {
|
if (g_hash_table_contains(n->actions, n->default_action_name)) {
|
||||||
signal_action_invoked(n, "default");
|
signal_action_invoked(n, n->default_action_name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (g_hash_table_size(n->actions) == 1) {
|
if (strcmp(n->default_action_name, "default") == 0 && g_hash_table_size(n->actions) == 1) {
|
||||||
GList *keys = g_hash_table_get_keys(n->actions);
|
GList *keys = g_hash_table_get_keys(n->actions);
|
||||||
signal_action_invoked(n, keys->data);
|
signal_action_invoked(n, keys->data);
|
||||||
g_list_free(keys);
|
g_list_free(keys);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context_menu();
|
notification_open_context_menu(n);
|
||||||
|
|
||||||
} else if (n->urls) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* see notification.h */
|
||||||
|
void notification_open_url(struct notification *n)
|
||||||
|
{
|
||||||
if (strstr(n->urls, "\n"))
|
if (strstr(n->urls, "\n"))
|
||||||
context_menu();
|
notification_open_context_menu(n);
|
||||||
else
|
else
|
||||||
open_browser(n->urls);
|
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) {
|
void notification_invalidate_actions(struct notification *n) {
|
||||||
|
|||||||
@ -61,6 +61,7 @@ struct notification {
|
|||||||
int locked; /**< If non-zero the notification is locked **/
|
int locked; /**< If non-zero the notification is locked **/
|
||||||
|
|
||||||
GHashTable *actions;
|
GHashTable *actions;
|
||||||
|
char *default_action_name; /**< The name of the action to be invoked on do_action */
|
||||||
|
|
||||||
enum markup_mode markup;
|
enum markup_mode markup;
|
||||||
const char *format;
|
const char *format;
|
||||||
@ -195,11 +196,24 @@ void notification_replace_single_field(char **haystack,
|
|||||||
void notification_update_text_to_render(struct notification *n);
|
void notification_update_text_to_render(struct notification *n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the notification has exactly one action, or one is marked as default,
|
* If the notification has an action named n->default_action_name or there is only one
|
||||||
* invoke it. If there are multiple and no default, open the context menu. If
|
* action and n->default_action_name is set to "default", invoke it. If there is no
|
||||||
* there are no actions, proceed similarly with urls.
|
* such action, open the context menu if threre are other actions. Otherwise, do nothing.
|
||||||
*/
|
*/
|
||||||
void notification_do_action(const struct notification *n);
|
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.
|
* Remove all client action data from the notification.
|
||||||
|
|||||||
@ -137,6 +137,9 @@ bool string_parse_mouse_action(const char *s, enum mouse_action *ret)
|
|||||||
STRING_PARSE_RET("do_action", MOUSE_DO_ACTION);
|
STRING_PARSE_RET("do_action", MOUSE_DO_ACTION);
|
||||||
STRING_PARSE_RET("close_current", MOUSE_CLOSE_CURRENT);
|
STRING_PARSE_RET("close_current", MOUSE_CLOSE_CURRENT);
|
||||||
STRING_PARSE_RET("close_all", MOUSE_CLOSE_ALL);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
40
src/output.c
@ -8,7 +8,7 @@
|
|||||||
#include "wayland/wl.h"
|
#include "wayland/wl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const bool is_running_wayland(void) {
|
bool is_running_wayland(void) {
|
||||||
char* wayland_display = getenv("WAYLAND_DISPLAY");
|
char* wayland_display = getenv("WAYLAND_DISPLAY");
|
||||||
return !(wayland_display == NULL);
|
return !(wayland_display == NULL);
|
||||||
}
|
}
|
||||||
@ -24,13 +24,14 @@ const struct output output_x11 = {
|
|||||||
x_win_hide,
|
x_win_hide,
|
||||||
|
|
||||||
x_display_surface,
|
x_display_surface,
|
||||||
x_win_visible,
|
|
||||||
x_win_get_context,
|
x_win_get_context,
|
||||||
|
|
||||||
get_active_screen,
|
get_active_screen,
|
||||||
|
|
||||||
x_is_idle,
|
x_is_idle,
|
||||||
have_fullscreen_window
|
have_fullscreen_window,
|
||||||
|
|
||||||
|
x_get_scale,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef ENABLE_WAYLAND
|
#ifdef ENABLE_WAYLAND
|
||||||
@ -45,28 +46,51 @@ const struct output output_wl = {
|
|||||||
wl_win_hide,
|
wl_win_hide,
|
||||||
|
|
||||||
wl_display_surface,
|
wl_display_surface,
|
||||||
wl_win_visible,
|
|
||||||
wl_win_get_context,
|
wl_win_get_context,
|
||||||
|
|
||||||
wl_get_active_screen,
|
wl_get_active_screen,
|
||||||
|
|
||||||
wl_is_idle,
|
wl_is_idle,
|
||||||
wl_have_fullscreen_window
|
wl_have_fullscreen_window,
|
||||||
|
|
||||||
|
wl_get_scale,
|
||||||
};
|
};
|
||||||
#endif
|
#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)
|
const struct output* output_create(bool force_xwayland)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_WAYLAND
|
#ifdef ENABLE_WAYLAND
|
||||||
if (!force_xwayland && is_running_wayland()) {
|
if (!force_xwayland && is_running_wayland()) {
|
||||||
LOG_I("Using Wayland output");
|
LOG_I("Using Wayland output");
|
||||||
return &output_wl;
|
return get_wl_output();
|
||||||
} else {
|
} else {
|
||||||
LOG_I("Using X11 output");
|
LOG_I("Using X11 output");
|
||||||
return &output_x11;
|
return get_x11_output();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return &output_x11;
|
return get_x11_output();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
|||||||
12
src/output.h
@ -27,7 +27,7 @@ struct screen_info {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct output {
|
struct output {
|
||||||
void (*init)(void);
|
bool (*init)(void);
|
||||||
void (*deinit)(void);
|
void (*deinit)(void);
|
||||||
|
|
||||||
window (*win_create)(void);
|
window (*win_create)(void);
|
||||||
@ -38,18 +38,24 @@ struct output {
|
|||||||
|
|
||||||
void (*display_surface)(cairo_surface_t *srf, window win, const struct dimensions*);
|
void (*display_surface)(cairo_surface_t *srf, window win, const struct dimensions*);
|
||||||
|
|
||||||
bool (*win_visible)(window);
|
|
||||||
cairo_t* (*win_get_context)(window);
|
cairo_t* (*win_get_context)(window);
|
||||||
|
|
||||||
const struct screen_info* (*get_active_screen)(void);
|
const struct screen_info* (*get_active_screen)(void);
|
||||||
|
|
||||||
bool (*is_idle)(void);
|
bool (*is_idle)(void);
|
||||||
bool (*have_fullscreen_window)(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);
|
const struct output* output_create(bool force_xwayland);
|
||||||
|
|
||||||
const bool is_running_wayland(void);
|
bool is_running_wayland(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
|||||||
@ -149,7 +149,7 @@ gint64 queues_get_next_datachange(gint64 time);
|
|||||||
* Get the notification which has the given id in the displayed and waiting queue or
|
* Get the notification which has the given id in the displayed and waiting queue or
|
||||||
* NULL if not found
|
* NULL if not found
|
||||||
*
|
*
|
||||||
* @param the id searched for.
|
* @param id the id searched for.
|
||||||
*
|
*
|
||||||
* @return the `id` notification or NULL
|
* @return the `id` notification or NULL
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -26,6 +26,10 @@ void rule_apply(struct rule *r, struct notification *n)
|
|||||||
n->transient = r->set_transient;
|
n->transient = r->set_transient;
|
||||||
if (r->skip_display != -1)
|
if (r->skip_display != -1)
|
||||||
n->skip_display = r->skip_display;
|
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)
|
if (r->markup != MARKUP_NULL)
|
||||||
n->markup = r->markup;
|
n->markup = r->markup;
|
||||||
if (r->new_icon)
|
if (r->new_icon)
|
||||||
|
|||||||
@ -23,6 +23,7 @@ struct rule {
|
|||||||
/* actions */
|
/* actions */
|
||||||
gint64 timeout;
|
gint64 timeout;
|
||||||
enum urgency urgency;
|
enum urgency urgency;
|
||||||
|
char *action_name;
|
||||||
enum markup_mode markup;
|
enum markup_mode markup;
|
||||||
int history_ignore;
|
int history_ignore;
|
||||||
int match_transient;
|
int match_transient;
|
||||||
|
|||||||
@ -862,6 +862,7 @@ void load_settings(char *cmdline_config_path)
|
|||||||
g_free(c);
|
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->urgency = ini_get_urgency(cur_section, "urgency", r->urgency);
|
||||||
r->msg_urgency = ini_get_urgency(cur_section, "msg_urgency", r->msg_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->fg = ini_get_string(cur_section, "foreground", r->fg);
|
||||||
|
|||||||
@ -18,7 +18,7 @@ enum icon_position { ICON_LEFT, ICON_RIGHT, ICON_OFF };
|
|||||||
enum vertical_alignment { VERTICAL_TOP, VERTICAL_CENTER, VERTICAL_BOTTOM };
|
enum vertical_alignment { VERTICAL_TOP, VERTICAL_CENTER, VERTICAL_BOTTOM };
|
||||||
enum separator_color { SEP_FOREGROUND, SEP_AUTO, SEP_FRAME, SEP_CUSTOM };
|
enum separator_color { SEP_FOREGROUND, SEP_AUTO, SEP_FRAME, SEP_CUSTOM };
|
||||||
enum follow_mode { FOLLOW_NONE, FOLLOW_MOUSE, FOLLOW_KEYBOARD };
|
enum follow_mode { FOLLOW_NONE, FOLLOW_MOUSE, FOLLOW_KEYBOARD };
|
||||||
enum mouse_action { MOUSE_NONE, MOUSE_DO_ACTION, MOUSE_CLOSE_CURRENT, MOUSE_CLOSE_ALL };
|
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
|
#ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM
|
||||||
#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM
|
#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM
|
||||||
// Needed for compiling without wayland dependency
|
// Needed for compiling without wayland dependency
|
||||||
|
|||||||
@ -0,0 +1,611 @@
|
|||||||
|
/* 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
|
||||||
@ -0,0 +1,106 @@
|
|||||||
|
/* 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,
|
||||||
|
};
|
||||||
|
|
||||||
@ -0,0 +1,270 @@
|
|||||||
|
<?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>
|
||||||
367
src/wayland/wl.c
@ -19,6 +19,8 @@
|
|||||||
#include "protocols/xdg-shell.h"
|
#include "protocols/xdg-shell.h"
|
||||||
#include "protocols/wlr-layer-shell-unstable-v1-client-header.h"
|
#include "protocols/wlr-layer-shell-unstable-v1-client-header.h"
|
||||||
#include "protocols/wlr-layer-shell-unstable-v1.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-client-header.h"
|
||||||
#include "protocols/idle.h"
|
#include "protocols/idle.h"
|
||||||
#include "pool-buffer.h"
|
#include "pool-buffer.h"
|
||||||
@ -30,6 +32,8 @@
|
|||||||
#include "../input.h"
|
#include "../input.h"
|
||||||
#include "libgwater-wayland.h"
|
#include "libgwater-wayland.h"
|
||||||
|
|
||||||
|
#define MAX_TOUCHPOINTS 10
|
||||||
|
|
||||||
struct window_wl {
|
struct window_wl {
|
||||||
cairo_surface_t *c_surface;
|
cairo_surface_t *c_surface;
|
||||||
cairo_t * c_ctx;
|
cairo_t * c_ctx;
|
||||||
@ -54,6 +58,7 @@ struct wl_ctx {
|
|||||||
struct wl_callback *frame_callback;
|
struct wl_callback *frame_callback;
|
||||||
struct org_kde_kwin_idle *idle_handler;
|
struct org_kde_kwin_idle *idle_handler;
|
||||||
struct org_kde_kwin_idle_timeout *idle_timeout;
|
struct org_kde_kwin_idle_timeout *idle_timeout;
|
||||||
|
struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager;
|
||||||
bool configured;
|
bool configured;
|
||||||
bool dirty;
|
bool dirty;
|
||||||
bool is_idle;
|
bool is_idle;
|
||||||
@ -64,6 +69,13 @@ struct wl_ctx {
|
|||||||
int32_t x, y;
|
int32_t x, y;
|
||||||
} pointer;
|
} pointer;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_touch *wl_touch;
|
||||||
|
struct {
|
||||||
|
int32_t x, y;
|
||||||
|
} pts[MAX_TOUCHPOINTS];
|
||||||
|
} touch;
|
||||||
|
|
||||||
struct dimensions cur_dim;
|
struct dimensions cur_dim;
|
||||||
|
|
||||||
int32_t width, height;
|
int32_t width, height;
|
||||||
@ -79,9 +91,10 @@ struct dunst_output {
|
|||||||
|
|
||||||
uint32_t scale;
|
uint32_t scale;
|
||||||
uint32_t subpixel; // TODO do something with it
|
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;
|
struct wl_ctx ctx;
|
||||||
|
|
||||||
static void noop() {
|
static void noop() {
|
||||||
@ -94,7 +107,7 @@ 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 x, int32_t y, int32_t phy_width, int32_t phy_height,
|
||||||
int32_t subpixel, const char *make, const char *model,
|
int32_t subpixel, const char *make, const char *model,
|
||||||
int32_t transform) {
|
int32_t transform) {
|
||||||
//TODO
|
//TODO do something with the subpixel data
|
||||||
struct dunst_output *output = data;
|
struct dunst_output *output = data;
|
||||||
output->subpixel = subpixel;
|
output->subpixel = subpixel;
|
||||||
}
|
}
|
||||||
@ -103,6 +116,8 @@ static void output_handle_scale(void *data, struct wl_output *wl_output,
|
|||||||
int32_t factor) {
|
int32_t factor) {
|
||||||
struct dunst_output *output = data;
|
struct dunst_output *output = data;
|
||||||
output->scale = factor;
|
output->scale = factor;
|
||||||
|
|
||||||
|
wake_up();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_output_listener output_listener = {
|
static const struct wl_output_listener output_listener = {
|
||||||
@ -122,8 +137,8 @@ static void create_output( struct wl_output *wl_output, uint32_t global_name) {
|
|||||||
LOG_I("New output found - id %i", number);
|
LOG_I("New output found - id %i", number);
|
||||||
output->global_name = global_name;
|
output->global_name = global_name;
|
||||||
output->wl_output = wl_output;
|
output->wl_output = wl_output;
|
||||||
// TODO: Fix this
|
|
||||||
output->scale = 1;
|
output->scale = 1;
|
||||||
|
output->fullscreen = false;
|
||||||
wl_list_insert(&ctx.outputs, &output->link);
|
wl_list_insert(&ctx.outputs, &output->link);
|
||||||
|
|
||||||
wl_output_set_user_data(wl_output, output);
|
wl_output_set_user_data(wl_output, output);
|
||||||
@ -144,7 +159,36 @@ static void destroy_output(struct dunst_output *output) {
|
|||||||
free(output);
|
free(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Snipped touch handling
|
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,
|
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) {
|
uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
|
||||||
ctx.pointer.x = wl_fixed_to_int(surface_x);
|
ctx.pointer.x = wl_fixed_to_int(surface_x);
|
||||||
@ -165,7 +209,13 @@ static const struct wl_pointer_listener pointer_listener = {
|
|||||||
.axis = noop,
|
.axis = noop,
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME snipped touch listener
|
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,
|
static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
||||||
uint32_t capabilities) {
|
uint32_t capabilities) {
|
||||||
@ -178,7 +228,15 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
|||||||
ctx.pointer.wl_pointer = wl_seat_get_pointer(wl_seat);
|
ctx.pointer.wl_pointer = wl_seat_get_pointer(wl_seat);
|
||||||
wl_pointer_add_listener(ctx.pointer.wl_pointer,
|
wl_pointer_add_listener(ctx.pointer.wl_pointer,
|
||||||
&pointer_listener, ctx.seat);
|
&pointer_listener, ctx.seat);
|
||||||
LOG_I("Adding pointer");
|
}
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,9 +284,11 @@ static void layer_surface_handle_configure(void *data,
|
|||||||
static void layer_surface_handle_closed(void *data,
|
static void layer_surface_handle_closed(void *data,
|
||||||
struct zwlr_layer_surface_v1 *surface) {
|
struct zwlr_layer_surface_v1 *surface) {
|
||||||
LOG_I("Destroying layer");
|
LOG_I("Destroying layer");
|
||||||
|
if (ctx.layer_surface)
|
||||||
zwlr_layer_surface_v1_destroy(ctx.layer_surface);
|
zwlr_layer_surface_v1_destroy(ctx.layer_surface);
|
||||||
ctx.layer_surface = NULL;
|
ctx.layer_surface = NULL;
|
||||||
|
|
||||||
|
if (ctx.surface)
|
||||||
wl_surface_destroy(ctx.surface);
|
wl_surface_destroy(ctx.surface);
|
||||||
ctx.surface = NULL;
|
ctx.surface = NULL;
|
||||||
|
|
||||||
@ -257,11 +317,11 @@ static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
|
|||||||
|
|
||||||
static void idle_start (void *data, struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout) {
|
static void idle_start (void *data, struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout) {
|
||||||
ctx.is_idle = true;
|
ctx.is_idle = true;
|
||||||
LOG_I("User went idle");
|
LOG_D("User went idle");
|
||||||
}
|
}
|
||||||
static void idle_stop (void *data, struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout) {
|
static void idle_stop (void *data, struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout) {
|
||||||
ctx.is_idle = false;
|
ctx.is_idle = false;
|
||||||
LOG_I("User isn't idle anymore");
|
LOG_D("User isn't idle anymore");
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct org_kde_kwin_idle_timeout_listener idle_timeout_listener = {
|
static const struct org_kde_kwin_idle_timeout_listener idle_timeout_listener = {
|
||||||
@ -273,14 +333,154 @@ static void add_seat_to_idle_handler(struct wl_seat *seat) {
|
|||||||
if (!ctx.idle_handler){
|
if (!ctx.idle_handler){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (settings.idle_threshold > 0) {
|
||||||
uint32_t timeout_ms = settings.idle_threshold/1000;
|
uint32_t timeout_ms = settings.idle_threshold/1000;
|
||||||
ctx.idle_timeout = org_kde_kwin_idle_get_idle_timeout(ctx.idle_handler, seat, timeout_ms);
|
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);
|
org_kde_kwin_idle_timeout_add_listener(ctx.idle_timeout, &idle_timeout_listener, 0);
|
||||||
ctx.has_idle_monitor = true;
|
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,
|
static void handle_global(void *data, struct wl_registry *registry,
|
||||||
uint32_t name, const char *interface, uint32_t version) {
|
uint32_t name, const char *interface, uint32_t version) {
|
||||||
|
int *count = data;
|
||||||
|
if (*count == 0)
|
||||||
|
{
|
||||||
if (strcmp(interface, wl_compositor_interface.name) == 0) {
|
if (strcmp(interface, wl_compositor_interface.name) == 0) {
|
||||||
ctx.compositor = wl_registry_bind(registry, name,
|
ctx.compositor = wl_registry_bind(registry, name,
|
||||||
&wl_compositor_interface, 4);
|
&wl_compositor_interface, 4);
|
||||||
@ -302,6 +502,15 @@ static void handle_global(void *data, struct wl_registry *registry,
|
|||||||
version >= ORG_KDE_KWIN_IDLE_TIMEOUT_IDLE_SINCE_VERSION) {
|
version >= ORG_KDE_KWIN_IDLE_TIMEOUT_IDLE_SINCE_VERSION) {
|
||||||
ctx.idle_handler = wl_registry_bind(registry, name, &org_kde_kwin_idle_interface, 1);
|
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,
|
static void handle_global_remove(void *data, struct wl_registry *registry,
|
||||||
@ -320,31 +529,38 @@ static const struct wl_registry_listener registry_listener = {
|
|||||||
.global_remove = handle_global_remove,
|
.global_remove = handle_global_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool init_wayland() {
|
bool wl_init() {
|
||||||
wl_list_init(&ctx.outputs);
|
wl_list_init(&ctx.outputs);
|
||||||
//wl_list_init(&ctx.seats);
|
//wl_list_init(&ctx.seats); // TODO multi-seat support
|
||||||
|
|
||||||
ctx.display = wl_display_connect(NULL);
|
ctx.display = wl_display_connect(NULL);
|
||||||
|
|
||||||
if (ctx.display == NULL) {
|
if (ctx.display == NULL) {
|
||||||
LOG_E("failed to create display");
|
LOG_W("failed to create display");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
ctx.registry = wl_display_get_registry(ctx.display);
|
ctx.registry = wl_display_get_registry(ctx.display);
|
||||||
wl_registry_add_listener(ctx.registry, ®istry_listener, NULL);
|
wl_registry_add_listener(ctx.registry, ®istry_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, ®istry_listener, &count);
|
||||||
wl_display_roundtrip(ctx.display);
|
wl_display_roundtrip(ctx.display);
|
||||||
|
|
||||||
if (ctx.compositor == NULL) {
|
if (ctx.compositor == NULL) {
|
||||||
LOG_E("compositor doesn't support wl_compositor");
|
LOG_W("compositor doesn't support wl_compositor");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ctx.shm == NULL) {
|
if (ctx.shm == NULL) {
|
||||||
LOG_E("compositor doesn't support wl_shm");
|
LOG_W("compositor doesn't support wl_shm");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ctx.layer_shell == NULL) {
|
if (ctx.layer_shell == NULL) {
|
||||||
LOG_E("compositor doesn't support zwlr_layer_shell_v1");
|
LOG_W("compositor doesn't support zwlr_layer_shell_v1");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ctx.seat == NULL) {
|
if (ctx.seat == NULL) {
|
||||||
@ -359,10 +575,17 @@ bool init_wayland() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx.toplevel_manager == NULL) {
|
||||||
|
LOG_W("compositor doesn't support zwlr_foreign_toplevel_v1. Fullscreen detection won't work");
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void finish_wayland() {
|
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) {
|
if (ctx.layer_surface != NULL) {
|
||||||
zwlr_layer_surface_v1_destroy(ctx.layer_surface);
|
zwlr_layer_surface_v1_destroy(ctx.layer_surface);
|
||||||
}
|
}
|
||||||
@ -372,56 +595,47 @@ void finish_wayland() {
|
|||||||
finish_buffer(&ctx.buffers[0]);
|
finish_buffer(&ctx.buffers[0]);
|
||||||
finish_buffer(&ctx.buffers[1]);
|
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;
|
struct dunst_output *output, *output_tmp;
|
||||||
wl_list_for_each_safe(output, output_tmp, &ctx.outputs, link) {
|
wl_list_for_each_safe(output, output_tmp, &ctx.outputs, link) {
|
||||||
destroy_output(output);
|
destroy_output(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.seat) {
|
if (ctx.seat) {
|
||||||
|
if (ctx.pointer.wl_pointer)
|
||||||
wl_pointer_release(ctx.pointer.wl_pointer);
|
wl_pointer_release(ctx.pointer.wl_pointer);
|
||||||
wl_seat_release(ctx.seat);
|
wl_seat_release(ctx.seat);
|
||||||
ctx.seat = NULL;
|
ctx.seat = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
zwlr_layer_shell_v1_destroy(ctx.layer_shell);
|
if (ctx.idle_handler)
|
||||||
wl_compositor_destroy(ctx.compositor);
|
|
||||||
wl_shm_destroy(ctx.shm);
|
|
||||||
wl_registry_destroy(ctx.registry);
|
|
||||||
wl_display_disconnect(ctx.display);
|
|
||||||
|
|
||||||
org_kde_kwin_idle_destroy(ctx.idle_handler);
|
org_kde_kwin_idle_destroy(ctx.idle_handler);
|
||||||
|
|
||||||
|
if (ctx.idle_timeout)
|
||||||
org_kde_kwin_idle_timeout_release(ctx.idle_timeout);
|
org_kde_kwin_idle_timeout_release(ctx.idle_timeout);
|
||||||
}
|
|
||||||
|
|
||||||
static struct dunst_output *get_configured_output() {
|
if (ctx.layer_shell)
|
||||||
struct dunst_output *output;
|
zwlr_layer_shell_v1_destroy(ctx.layer_shell);
|
||||||
|
|
||||||
switch (settings.f_mode){
|
if (ctx.compositor)
|
||||||
case FOLLOW_NONE: ; // this semicolon is neccesary
|
wl_compositor_destroy(ctx.compositor);
|
||||||
int n = 0;
|
|
||||||
int target_monitor = settings.monitor;
|
|
||||||
|
|
||||||
wl_list_for_each(output, &ctx.outputs, link) {
|
if (ctx.shm)
|
||||||
if (n == target_monitor)
|
wl_shm_destroy(ctx.shm);
|
||||||
return output;
|
|
||||||
n++;
|
if (ctx.registry)
|
||||||
}
|
wl_registry_destroy(ctx.registry);
|
||||||
LOG_W("Monitor %i doesn't exist, using focused monitor", settings.monitor);
|
|
||||||
return NULL;
|
if (ctx.display)
|
||||||
case FOLLOW_MOUSE:
|
wl_display_disconnect(ctx.display);
|
||||||
// fallthrough
|
|
||||||
case FOLLOW_KEYBOARD:
|
|
||||||
// fallthrough
|
|
||||||
default:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void schedule_frame_and_commit();
|
static void schedule_frame_and_commit();
|
||||||
|
|
||||||
// Draw and commit a new frame.
|
// Draw and commit a new frame.
|
||||||
static void send_frame() {
|
static void send_frame() {
|
||||||
int scale = 1;
|
int scale = wl_get_scale();
|
||||||
|
|
||||||
struct dunst_output *output = get_configured_output();
|
struct dunst_output *output = get_configured_output();
|
||||||
int height = ctx.cur_dim.h;
|
int height = ctx.cur_dim.h;
|
||||||
@ -455,11 +669,13 @@ static void send_frame() {
|
|||||||
// different output), we need to create it.
|
// different output), we need to create it.
|
||||||
if (ctx.layer_surface == NULL) {
|
if (ctx.layer_surface == NULL) {
|
||||||
struct wl_output *wl_output = NULL;
|
struct wl_output *wl_output = NULL;
|
||||||
|
if (output != NULL) {
|
||||||
|
wl_output = output->wl_output;
|
||||||
|
}
|
||||||
ctx.layer_surface_output = output;
|
ctx.layer_surface_output = output;
|
||||||
ctx.surface = wl_compositor_create_surface(ctx.compositor);
|
ctx.surface = wl_compositor_create_surface(ctx.compositor);
|
||||||
wl_surface_add_listener(ctx.surface, &surface_listener, NULL);
|
wl_surface_add_listener(ctx.surface, &surface_listener, NULL);
|
||||||
|
|
||||||
if (settings.frame_color)
|
|
||||||
ctx.layer_surface = zwlr_layer_shell_v1_get_layer_surface(
|
ctx.layer_surface = zwlr_layer_shell_v1_get_layer_surface(
|
||||||
ctx.layer_shell, ctx.surface, wl_output,
|
ctx.layer_shell, ctx.surface, wl_output,
|
||||||
settings.layer, "notifications");
|
settings.layer, "notifications");
|
||||||
@ -485,8 +701,6 @@ static void send_frame() {
|
|||||||
if (ctx.height != height || ctx.width != width) {
|
if (ctx.height != height || ctx.width != width) {
|
||||||
struct dimensions dim = ctx.cur_dim;
|
struct dimensions dim = ctx.cur_dim;
|
||||||
// Set window size
|
// Set window size
|
||||||
LOG_D("Window dimensions %ix%i", dim.w, dim.h);
|
|
||||||
LOG_D("Window position %ix%i", dim.x, dim.y);
|
|
||||||
zwlr_layer_surface_v1_set_size(ctx.layer_surface,
|
zwlr_layer_surface_v1_set_size(ctx.layer_surface,
|
||||||
dim.w, dim.h);
|
dim.w, dim.h);
|
||||||
|
|
||||||
@ -582,13 +796,6 @@ void set_dirty() {
|
|||||||
schedule_frame_and_commit();
|
schedule_frame_and_commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wl_init(void) {
|
|
||||||
init_wayland();
|
|
||||||
}
|
|
||||||
|
|
||||||
void wl_deinit(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
window wl_win_create(void) {
|
window wl_win_create(void) {
|
||||||
struct window_wl *win = g_malloc0(sizeof(struct window_wl));
|
struct window_wl *win = g_malloc0(sizeof(struct window_wl));
|
||||||
|
|
||||||
@ -605,6 +812,8 @@ void wl_win_destroy(window winptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void wl_win_show(window 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) {
|
void wl_win_hide(window win) {
|
||||||
@ -616,12 +825,15 @@ void wl_win_hide(window win) {
|
|||||||
|
|
||||||
void wl_display_surface(cairo_surface_t *srf, window winptr, const struct dimensions* dim) {
|
void wl_display_surface(cairo_surface_t *srf, window winptr, const struct dimensions* dim) {
|
||||||
/* struct window_wl *win = (struct window_wl*)winptr; */
|
/* struct window_wl *win = (struct window_wl*)winptr; */
|
||||||
ctx.current_buffer = get_next_buffer(ctx.shm, ctx.buffers, dim->w, dim->h);
|
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_t *c = ctx.current_buffer->cairo;
|
||||||
cairo_save(c);
|
cairo_save(c);
|
||||||
cairo_set_source_surface(c, srf, 0, 0);
|
cairo_set_source_surface(c, srf, 0, 0);
|
||||||
cairo_rectangle(c, 0, 0, dim->w, dim->h);
|
cairo_rectangle(c, 0, 0, dim->w * scale, dim->h * scale);
|
||||||
cairo_fill(c);
|
cairo_fill(c);
|
||||||
cairo_restore(c);
|
cairo_restore(c);
|
||||||
|
|
||||||
@ -631,10 +843,6 @@ void wl_display_surface(cairo_surface_t *srf, window winptr, const struct dimens
|
|||||||
wl_display_roundtrip(ctx.display);
|
wl_display_roundtrip(ctx.display);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wl_win_visible(window win) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_t* wl_win_get_context(window winptr) {
|
cairo_t* wl_win_get_context(window winptr) {
|
||||||
struct window_wl *win = (struct window_wl*)winptr;
|
struct window_wl *win = (struct window_wl*)winptr;
|
||||||
ctx.current_buffer = get_next_buffer(ctx.shm, ctx.buffers, 500, 500);
|
ctx.current_buffer = get_next_buffer(ctx.shm, ctx.buffers, 500, 500);
|
||||||
@ -653,6 +861,7 @@ const struct screen_info* wl_get_active_screen(void) {
|
|||||||
.id = 0,
|
.id = 0,
|
||||||
.mmh = 500
|
.mmh = 500
|
||||||
};
|
};
|
||||||
|
scr.dpi = wl_get_scale() * 96;
|
||||||
return &scr;
|
return &scr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,7 +875,43 @@ bool wl_is_idle(void) {
|
|||||||
return ctx.is_idle;
|
return ctx.is_idle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wl_have_fullscreen_window(void) {
|
bool wl_have_fullscreen_window(void) {
|
||||||
return false;
|
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: */
|
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include "../output.h"
|
#include "../output.h"
|
||||||
|
|
||||||
void wl_init(void);
|
bool wl_init(void);
|
||||||
void wl_deinit(void);
|
void wl_deinit(void);
|
||||||
|
|
||||||
window wl_win_create(void);
|
window wl_win_create(void);
|
||||||
@ -17,12 +17,16 @@ void wl_win_show(window);
|
|||||||
void wl_win_hide(window);
|
void wl_win_hide(window);
|
||||||
|
|
||||||
void wl_display_surface(cairo_surface_t *srf, window win, const struct dimensions*);
|
void wl_display_surface(cairo_surface_t *srf, window win, const struct dimensions*);
|
||||||
bool wl_win_visible(window);
|
|
||||||
cairo_t* wl_win_get_context(window);
|
cairo_t* wl_win_get_context(window);
|
||||||
|
|
||||||
const struct screen_info* wl_get_active_screen(void);
|
const struct screen_info* wl_get_active_screen(void);
|
||||||
|
|
||||||
bool wl_is_idle(void);
|
bool wl_is_idle(void);
|
||||||
bool wl_have_fullscreen_window(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
|
#endif
|
||||||
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
|||||||
18
src/x11/x.c
@ -113,7 +113,7 @@ static void x_win_corners_shape(struct window_x11 *win, const int rad)
|
|||||||
|
|
||||||
draw_rounded_rect(cr, 0, 0,
|
draw_rounded_rect(cr, 0, 0,
|
||||||
width, height,
|
width, height,
|
||||||
rad,
|
rad, 1,
|
||||||
true, true);
|
true, true);
|
||||||
cairo_fill(cr);
|
cairo_fill(cr);
|
||||||
|
|
||||||
@ -179,11 +179,6 @@ void x_display_surface(cairo_surface_t *srf, window winptr, const struct dimensi
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool x_win_visible(window winptr)
|
|
||||||
{
|
|
||||||
return ((struct window_x11*)winptr)->visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_t* x_win_get_context(window winptr)
|
cairo_t* x_win_get_context(window winptr)
|
||||||
{
|
{
|
||||||
return ((struct window_x11*)win)->c_ctx;
|
return ((struct window_x11*)win)->c_ctx;
|
||||||
@ -501,14 +496,16 @@ static void XRM_update_db(void)
|
|||||||
/*
|
/*
|
||||||
* Setup X11 stuff
|
* Setup X11 stuff
|
||||||
*/
|
*/
|
||||||
void x_setup(void)
|
bool x_setup(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* initialize xctx.dc, font, keyboard, colors */
|
/* initialize xctx.dc, font, keyboard, colors */
|
||||||
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
|
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
|
||||||
LOG_W("No locale support");
|
LOG_W("No locale support");
|
||||||
|
|
||||||
if (!(xctx.dpy = XOpenDisplay(NULL))) {
|
if (!(xctx.dpy = XOpenDisplay(NULL))) {
|
||||||
DIE("Cannot open X11 display.");
|
LOG_W("Cannot open X11 display.");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
x_shortcut_init(&settings.close_ks);
|
x_shortcut_init(&settings.close_ks);
|
||||||
@ -532,6 +529,7 @@ void x_setup(void)
|
|||||||
|
|
||||||
init_screens();
|
init_screens();
|
||||||
x_shortcut_grab(&settings.history_ks);
|
x_shortcut_grab(&settings.history_ks);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct geometry x_parse_geometry(const char *geom_str)
|
struct geometry x_parse_geometry(const char *geom_str)
|
||||||
@ -944,4 +942,8 @@ static void x_shortcut_init(struct keyboard_shortcut *ks)
|
|||||||
g_free(str_begin);
|
g_free(str_begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int x_get_scale(void) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
|||||||
@ -42,15 +42,15 @@ void x_win_hide(window);
|
|||||||
|
|
||||||
void x_display_surface(cairo_surface_t *srf, window, const struct dimensions *dim);
|
void x_display_surface(cairo_surface_t *srf, window, const struct dimensions *dim);
|
||||||
|
|
||||||
bool x_win_visible(window);
|
|
||||||
cairo_t* x_win_get_context(window);
|
cairo_t* x_win_get_context(window);
|
||||||
|
|
||||||
/* X misc */
|
/* X misc */
|
||||||
bool x_is_idle(void);
|
bool x_is_idle(void);
|
||||||
void x_setup(void);
|
bool x_setup(void);
|
||||||
void x_free(void);
|
void x_free(void);
|
||||||
|
|
||||||
struct geometry x_parse_geometry(const char *geom_str);
|
struct geometry x_parse_geometry(const char *geom_str);
|
||||||
|
|
||||||
|
int x_get_scale(void);
|
||||||
#endif
|
#endif
|
||||||
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
|||||||
@ -686,6 +686,7 @@ TEST test_server_caps(enum markup_mode markup)
|
|||||||
ASSERT(g_strv_contains(capsarray, "actions"));
|
ASSERT(g_strv_contains(capsarray, "actions"));
|
||||||
ASSERT(g_strv_contains(capsarray, "body"));
|
ASSERT(g_strv_contains(capsarray, "body"));
|
||||||
ASSERT(g_strv_contains(capsarray, "body-hyperlinks"));
|
ASSERT(g_strv_contains(capsarray, "body-hyperlinks"));
|
||||||
|
ASSERT(g_strv_contains(capsarray, "icon-static"));
|
||||||
ASSERT(g_strv_contains(capsarray, "x-dunst-stack-tag"));
|
ASSERT(g_strv_contains(capsarray, "x-dunst-stack-tag"));
|
||||||
|
|
||||||
if (settings.markup != MARKUP_NO)
|
if (settings.markup != MARKUP_NO)
|
||||||
@ -856,6 +857,10 @@ SUITE(suite_dbus)
|
|||||||
loop = g_main_loop_new(NULL, false);
|
loop = g_main_loop_new(NULL, false);
|
||||||
|
|
||||||
dbus_bus = g_test_dbus_new(G_TEST_DBUS_NONE);
|
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);
|
g_test_dbus_up(dbus_bus);
|
||||||
|
|
||||||
thread_tests = g_thread_new("testexecutor", run_threaded_tests, loop);
|
thread_tests = g_thread_new("testexecutor", run_threaded_tests, loop);
|
||||||
|
|||||||
20
test/icon.c
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
extern const char *base;
|
extern const char *base;
|
||||||
|
|
||||||
|
int scale = 1;
|
||||||
|
|
||||||
TEST test_get_path_from_icon_null(void){
|
TEST test_get_path_from_icon_null(void){
|
||||||
char *result = get_path_from_icon_name(NULL);
|
char *result = get_path_from_icon_name(NULL);
|
||||||
ASSERT_EQ(result, NULL);
|
ASSERT_EQ(result, NULL);
|
||||||
@ -86,7 +88,7 @@ TEST test_get_pixbuf_from_file_tilde(void)
|
|||||||
gchar *path = g_build_filename(base, iconpath, "valid", "icon1.svg", NULL);
|
gchar *path = g_build_filename(base, iconpath, "valid", "icon1.svg", NULL);
|
||||||
path = string_replace_at(path, 0, strlen(home), "~");
|
path = string_replace_at(path, 0, strlen(home), "~");
|
||||||
|
|
||||||
GdkPixbuf *pixbuf = get_pixbuf_from_file(path);
|
GdkPixbuf *pixbuf = get_pixbuf_from_file(path, scale);
|
||||||
g_clear_pointer(&path, g_free);
|
g_clear_pointer(&path, g_free);
|
||||||
|
|
||||||
ASSERT(pixbuf);
|
ASSERT(pixbuf);
|
||||||
@ -101,7 +103,7 @@ TEST test_get_pixbuf_from_file_absolute(void)
|
|||||||
|
|
||||||
gchar *path = g_build_filename(base, iconpath, "valid", "icon1.svg", NULL);
|
gchar *path = g_build_filename(base, iconpath, "valid", "icon1.svg", NULL);
|
||||||
|
|
||||||
GdkPixbuf *pixbuf = get_pixbuf_from_file(path);
|
GdkPixbuf *pixbuf = get_pixbuf_from_file(path, scale);
|
||||||
g_clear_pointer(&path, g_free);
|
g_clear_pointer(&path, g_free);
|
||||||
|
|
||||||
ASSERT(pixbuf);
|
ASSERT(pixbuf);
|
||||||
@ -113,7 +115,7 @@ TEST test_get_pixbuf_from_file_absolute(void)
|
|||||||
|
|
||||||
TEST test_get_pixbuf_from_icon_invalid(void)
|
TEST test_get_pixbuf_from_icon_invalid(void)
|
||||||
{
|
{
|
||||||
GdkPixbuf *pixbuf = get_pixbuf_from_icon("invalid");
|
GdkPixbuf *pixbuf = get_pixbuf_from_icon("invalid", scale);
|
||||||
ASSERT(pixbuf == NULL);
|
ASSERT(pixbuf == NULL);
|
||||||
g_clear_pointer(&pixbuf, g_object_unref);
|
g_clear_pointer(&pixbuf, g_object_unref);
|
||||||
|
|
||||||
@ -122,7 +124,7 @@ TEST test_get_pixbuf_from_icon_invalid(void)
|
|||||||
|
|
||||||
TEST test_get_pixbuf_from_icon_both(void)
|
TEST test_get_pixbuf_from_icon_both(void)
|
||||||
{
|
{
|
||||||
GdkPixbuf *pixbuf = get_pixbuf_from_icon("icon1");
|
GdkPixbuf *pixbuf = get_pixbuf_from_icon("icon1", scale);
|
||||||
// the first icon found is invalid, so the pixbuf is empty
|
// the first icon found is invalid, so the pixbuf is empty
|
||||||
ASSERT(!pixbuf);
|
ASSERT(!pixbuf);
|
||||||
g_clear_pointer(&pixbuf, g_object_unref);
|
g_clear_pointer(&pixbuf, g_object_unref);
|
||||||
@ -132,7 +134,7 @@ TEST test_get_pixbuf_from_icon_both(void)
|
|||||||
|
|
||||||
TEST test_get_pixbuf_from_icon_onlysvg(void)
|
TEST test_get_pixbuf_from_icon_onlysvg(void)
|
||||||
{
|
{
|
||||||
GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlysvg");
|
GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlysvg", scale);
|
||||||
ASSERT(pixbuf);
|
ASSERT(pixbuf);
|
||||||
ASSERTm("SVG pixbuf isn't loaded", IS_ICON_SVG(pixbuf));
|
ASSERTm("SVG pixbuf isn't loaded", IS_ICON_SVG(pixbuf));
|
||||||
g_clear_pointer(&pixbuf, g_object_unref);
|
g_clear_pointer(&pixbuf, g_object_unref);
|
||||||
@ -142,7 +144,7 @@ TEST test_get_pixbuf_from_icon_onlysvg(void)
|
|||||||
|
|
||||||
TEST test_get_pixbuf_from_icon_onlypng(void)
|
TEST test_get_pixbuf_from_icon_onlypng(void)
|
||||||
{
|
{
|
||||||
GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlypng");
|
GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlypng", scale);
|
||||||
ASSERT(pixbuf);
|
ASSERT(pixbuf);
|
||||||
ASSERTm("PNG pixbuf isn't loaded", IS_ICON_PNG(pixbuf));
|
ASSERTm("PNG pixbuf isn't loaded", IS_ICON_PNG(pixbuf));
|
||||||
g_clear_pointer(&pixbuf, g_object_unref);
|
g_clear_pointer(&pixbuf, g_object_unref);
|
||||||
@ -153,7 +155,7 @@ TEST test_get_pixbuf_from_icon_onlypng(void)
|
|||||||
TEST test_get_pixbuf_from_icon_filename(void)
|
TEST test_get_pixbuf_from_icon_filename(void)
|
||||||
{
|
{
|
||||||
char *icon = g_strconcat(base, "/data/icons/valid.png", NULL);
|
char *icon = g_strconcat(base, "/data/icons/valid.png", NULL);
|
||||||
GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon);
|
GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon, scale);
|
||||||
ASSERT(pixbuf);
|
ASSERT(pixbuf);
|
||||||
ASSERTm("PNG pixbuf isn't loaded", IS_ICON_PNG(pixbuf));
|
ASSERTm("PNG pixbuf isn't loaded", IS_ICON_PNG(pixbuf));
|
||||||
g_clear_pointer(&pixbuf, g_object_unref);
|
g_clear_pointer(&pixbuf, g_object_unref);
|
||||||
@ -165,7 +167,7 @@ TEST test_get_pixbuf_from_icon_filename(void)
|
|||||||
TEST test_get_pixbuf_from_icon_fileuri(void)
|
TEST test_get_pixbuf_from_icon_fileuri(void)
|
||||||
{
|
{
|
||||||
char *icon = g_strconcat("file://", base, "/data/icons/valid.svg", NULL);
|
char *icon = g_strconcat("file://", base, "/data/icons/valid.svg", NULL);
|
||||||
GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon);
|
GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon, scale);
|
||||||
ASSERT(pixbuf);
|
ASSERT(pixbuf);
|
||||||
ASSERTm("SVG pixbuf isn't loaded", IS_ICON_SVG(pixbuf));
|
ASSERTm("SVG pixbuf isn't loaded", IS_ICON_SVG(pixbuf));
|
||||||
g_clear_pointer(&pixbuf, g_object_unref);
|
g_clear_pointer(&pixbuf, g_object_unref);
|
||||||
@ -220,7 +222,7 @@ TEST test_icon_size_clamp_too_small_then_too_big(void)
|
|||||||
|
|
||||||
TEST test_get_pixbuf_from_icon_both_is_scaled(void)
|
TEST test_get_pixbuf_from_icon_both_is_scaled(void)
|
||||||
{
|
{
|
||||||
GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlypng");
|
GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlypng", scale);
|
||||||
ASSERT(pixbuf);
|
ASSERT(pixbuf);
|
||||||
ASSERT_EQ(gdk_pixbuf_get_width(pixbuf), 16);
|
ASSERT_EQ(gdk_pixbuf_get_width(pixbuf), 16);
|
||||||
ASSERT_EQ(gdk_pixbuf_get_height(pixbuf), 16);
|
ASSERT_EQ(gdk_pixbuf_get_height(pixbuf), 16);
|
||||||
|
|||||||
@ -763,6 +763,68 @@ TEST test_queue_find_by_id(void)
|
|||||||
PASS();
|
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)
|
SUITE(suite_queues)
|
||||||
{
|
{
|
||||||
settings.icon_path = "";
|
settings.icon_path = "";
|
||||||
@ -794,6 +856,7 @@ SUITE(suite_queues)
|
|||||||
RUN_TEST(test_queues_update_xmore);
|
RUN_TEST(test_queues_update_xmore);
|
||||||
RUN_TEST(test_queues_timeout_before_paused);
|
RUN_TEST(test_queues_timeout_before_paused);
|
||||||
RUN_TEST(test_queue_find_by_id);
|
RUN_TEST(test_queue_find_by_id);
|
||||||
|
RUN_TEST(test_queue_no_sort_and_pause);
|
||||||
|
|
||||||
settings.icon_path = NULL;
|
settings.icon_path = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||