pax_global_header 0000666 0000000 0000000 00000000064 14662337126 0014524 g ustar 00root root 0000000 0000000 52 comment=15065ca1a2e3a596db3dbcba64823c5dee90f191
wayfire-0.9.0/ 0000775 0000000 0000000 00000000000 14662337126 0013200 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/.editorconfig 0000664 0000000 0000000 00000000277 14662337126 0015663 0 ustar 00root root 0000000 0000000 root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 4
[*.{build,xml,yaml}]
indent_size = 2
[metadata/**.xml]
indent_style = tab
wayfire-0.9.0/.github/ 0000775 0000000 0000000 00000000000 14662337126 0014540 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 14662337126 0016723 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/.github/ISSUE_TEMPLATE/bug_report.md 0000664 0000000 0000000 00000001276 14662337126 0021423 0 ustar 00root root 0000000 0000000 ---
name: Bug report
about: Bad behavior (crash, something doesn't work, etc.)
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Enable plugin X
2. Do Y
3. Z happens
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots or stacktrace**
If applicable, add screenshots to help explain your problem.
If it is a crash, attach the backtrace (or the whole log file), Wayfire will print it in the end of the log file or stdout.
Backtrace with address sanitizer enabled (if possible):
**Wayfire version**
0.5.0, git, package, something else?
wayfire-0.9.0/.github/ISSUE_TEMPLATE/feature_request.md 0000664 0000000 0000000 00000000341 14662337126 0022446 0 ustar 00root root 0000000 0000000 ---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
Please describe what you want Wayfire to do.
If applicable, give an example: User does X, Y, Wayfire does Z
wayfire-0.9.0/.github/ISSUE_TEMPLATE/others.md 0000664 0000000 0000000 00000000165 14662337126 0020553 0 ustar 00root root 0000000 0000000 ---
name: Others
about: Issues which are neither bugs nor feature requests
title: ''
labels: ''
assignees: ''
---
wayfire-0.9.0/.github/workflows/ 0000775 0000000 0000000 00000000000 14662337126 0016575 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/.github/workflows/ci.yaml 0000664 0000000 0000000 00000006123 14662337126 0020056 0 ustar 00root root 0000000 0000000 name: CI
on: [push, pull_request]
jobs:
test_musl_gcc:
name: "Test with GCC/musl/libstdc++/BFD on Alpine Linux"
runs-on: ubuntu-latest
container: alpine:latest
steps:
- run: apk --no-cache add git gcc g++ binutils pkgconf meson ninja musl-dev wayland-dev wayland-protocols libinput-dev libevdev-dev libxkbcommon-dev pixman-dev glm-dev libdrm-dev mesa-dev cairo-dev pango-dev eudev-dev libxml2-dev libseat-dev libxcb-dev xcb-util-wm-dev xwayland doctest doctest-dev cmake libdisplay-info-dev hwdata-dev nlohmann-json
- uses: actions/checkout@v1
- run: git config --global --add safe.directory /__w/wayfire/wayfire
- run: git submodule sync --recursive && git submodule update --init --force --recursive
- run: (cd subprojects/wlroots && meson build --prefix=/usr && ninja -C build install)
- run: meson build -Dtests=enabled -Db_pch=true -Duse_system_wlroots=enabled
- run: ninja -v -Cbuild
- run: ninja -v -Cbuild test
test_glibc_llvm:
name: "Test with clang/glibc/libc++/lld on Arch Linux"
runs-on: ubuntu-latest
container:
image: archlinux:latest
steps:
- run: sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
- run: pacman --noconfirm --noprogressbar -Syyu
- run: pacman-key --init
- run: pacman-key --recv-key 7DD85120C491D581 --keyserver keyserver.ubuntu.com
- run: pacman-key --lsign-key 7DD85120C491D581
- run: printf '[stefanwimmer128]\nServer = https://repo.stefanwimmer128.xyz/$repo/$arch/' >> /etc/pacman.conf
- run: pacman --noconfirm --noprogressbar -Syyu
- run: pacman --noconfirm --noprogressbar -Sy git clang17 lld libc++ pkgconf cmake meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd hwdata libdisplay-info openmp nlohmann-json
# Build Wayfire
- uses: actions/checkout@v1
- run: git config --global --add safe.directory /__w/wayfire/wayfire
- run: git submodule sync --recursive && git submodule update --init --force --recursive
- run: find /usr/bin/ | grep clang
- run: (cd subprojects/wlroots && env CC=clang-17 CXX=clang++-17 CXXFLAGS="-stdlib=libc++" LDFLAGS="-fuse-ld=lld -stdlib=libc++" meson build --prefix=/usr && ninja -C build install)
- run: env CC=clang-17 CXX=clang++-17 CXXFLAGS="-stdlib=libc++" LDFLAGS="-fuse-ld=lld -stdlib=libc++" meson build -Db_pch=true -Duse_system_wlroots=enabled --unity on
- run: ninja -v -Cbuild
- run: ninja -v -Cbuild test
test_code_style:
name: "Check code style with uncrustify"
runs-on: ubuntu-latest
steps:
- run: sudo apt-get update
- run: sudo apt-get install -y git cmake gcc make
- uses: actions/checkout@v1
- run: git clone http://github.com/ammen99/uncrustify
- run: cd uncrustify && mkdir build && cd build && cmake ../ && make && cd ../../
- run: git ls-files | grep "hpp$\|cpp$" | xargs ./uncrustify/build/uncrustify -c uncrustify.ini --no-backup --replace
- run: git diff
- run: git diff | diff - /dev/null &> /dev/null
wayfire-0.9.0/.github/workflows/mandoc.yaml 0000664 0000000 0000000 00000000600 14662337126 0020716 0 ustar 00root root 0000000 0000000 name: mandoc
on:
push:
branches:
- '*'
pull_request:
branches:
- '*'
jobs:
pipeline:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: |
sudo apt update
sudo apt-get install -y mandoc
- name: Check man pages
run: |
mandoc -T lint -W warning man/wayfire.1.in
wayfire-0.9.0/.gitignore 0000664 0000000 0000000 00000001733 14662337126 0015174 0 ustar 00root root 0000000 0000000
# Created by https://www.toptal.com/developers/gitignore/api/c++,meson,ninja,linux
# Edit at https://www.toptal.com/developers/gitignore?templates=c++,meson,ninja,linux
### C++ ###
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### Meson ###
# subproject directories
/subprojects/*
!/subprojects/*.wrap
### Ninja ###
.ninja_deps
.ninja_log
build/**
# End of https://www.toptal.com/developers/gitignore/api/c++,meson,ninja,linux wayfire-0.9.0/.gitmodules 0000664 0000000 0000000 00000000706 14662337126 0015360 0 ustar 00root root 0000000 0000000 [submodule "subprojects/wf-config"]
path = subprojects/wf-config
url = https://github.com/WayfireWM/wf-config
[submodule "subprojects/wlroots"]
path = subprojects/wlroots
url = https://gitlab.freedesktop.org/wlroots/wlroots.git
[submodule "subprojects/wf-utils"]
path = subprojects/wf-utils
url = https://github.com/WayfireWM/wf-utils.git
[submodule "subprojects/wf-touch"]
path = subprojects/wf-touch
url = https://github.com/WayfireWM/wf-touch
wayfire-0.9.0/CONTRIBUTING.md 0000664 0000000 0000000 00000006035 14662337126 0015435 0 ustar 00root root 0000000 0000000 # Contributing
## Documentation
Updating the documentation is one of the easiest way to contribute to the project.
The [wiki](https://github.com/WayfireWM/wayfire/wiki) is the primary location for documentation and is editable by everyone.
Feel free to do minor changes or additions (for example, adding a missing option or adding a tip) without consulting anyone.
Make contact with the maintainer(s) of the repository if you want to make big changes.
## Issues
Opening quality issues is another good way to contribute. See the issue templates for information about what a good issue would look like.
## Pull requests
Pull requests are welcome, be it a bug fix or a new feature. A lot of ideas are already on the GitHub issue tracker:
- The label [good first issue](https://github.com/WayfireWM/wayfire/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
indicates items which everyone with basic programming knowledge in C++ should be able to implement.
- The label [easy](https://github.com/WayfireWM/wayfire/issues?q=is%3Aopen+is%3Aissue+label%3Aeasy)
indicates items which do not require deep knowledge about the codebase, and whose solution is relatively simple.
- The label [help wanted](https://github.com/WayfireWM/wayfire/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
indicates items which require more hardware or knowledge than we have available, so external contributions are needed.
- The label `low priority` indicates that something is unlikely to be implemented by @ammen99 anytime soon, but a PR would still be reviewed and merged.
- The label `external-plugin` indicates that the feature can be implemented in a plugin which will not be included in the main repository.
Some of the issues have milestones.
These are used to check which features are planned by @ammen99 for the given release.
However, milestones are not firmly set, PRs by anyone for any issue can be merged at any time.
If you want to work on a feature or a bug fix which does not have an open issue, it would be best to open a new one or at least contact the maintainer(s) to make sure your changes will be accepted. The base repository is meant only for common functionality like Autostart, Expo, Vswitch, Scale or plugins which demonstrate particular core features like Cube, Fisheye, Extra-gestures, etc.
In any case, feel free to ask questions if you do not understand a part of the code, or if you are unsure how a particular feature should be implemented.
### Code Formatting
Please use [`uncrustify`](https://github.com/uncrustify/uncrustify) (version `>=0.71`) to automatically format the code before committing:
```sh
$ git ls-files | grep "hpp$\|cpp$" | xargs uncrustify -c uncrustify.ini --no-backup
```
You can setup a [githook](https://git-scm.com/docs/githooks) to run this automatically before committing.
## Contacting the maintainer(s)
The primary communication channels are Matrix (#wayfire:matrix.org) and IRC (#wayfire at Libera.chat).
The two channels are bridged together.
Use GitHub to ask questions only if you are unable to access IRC and Matrix.
wayfire-0.9.0/LICENSE 0000664 0000000 0000000 00000002071 14662337126 0014205 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2018 Iliya Bozhinov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
wayfire-0.9.0/README.md 0000664 0000000 0000000 00000013415 14662337126 0014463 0 ustar 00root root 0000000 0000000 # [Wayfire]
[Wayfire]: https://wayfire.org

[](https://matrix.to/#/#wayfire:matrix.org)
[](https://web.libera.chat/#wayfire)
[](https://discord.gg/5SWAxmBCUH)
[](https://github.com/WayfireWM/wayfire/actions)
[](https://repology.org/project/wayfire/versions)
[](LICENSE)
###### [Get started] | [Manual] | [Configuration]
[Get started]: https://github.com/WayfireWM/wayfire/wiki/Tutorial
[Manual]: https://github.com/WayfireWM/wayfire/wiki/General
[Configuration]: https://github.com/WayfireWM/wayfire/wiki/Configuration
Wayfire is a 3D [Wayland] compositor, inspired by [Compiz] and based on [wlroots].
It aims to create a customizable, extendable and lightweight environment without sacrificing its appearance.
[](https://youtube.com/playlist?list=PLb7YRKEhWEBUIoT-a29UoJW9mhfzjpNle "YouTube – Wayfire demos")
[](https://youtube.com/playlist?list=PLb7YRKEhWEBUIoT-a29UoJW9mhfzjpNle) · [Wayfire demos](https://youtube.com/playlist?list=PLb7YRKEhWEBUIoT-a29UoJW9mhfzjpNle)
[Wayland]: https://wayland.freedesktop.org
[wlroots]: https://github.com/swaywm/wlroots
[Compiz]: https://launchpad.net/compiz
## Dependencies
### Wayfire Dependencies
These are the dependencies needed for building Wayfire.
- [Cairo](https://cairographics.org)
- [Pango](https://pango.gnome.org/) and PangoCairo
- [FreeType](https://freetype.org)
- [GLM](https://glm.g-truc.net)
- [libdrm](https://dri.freedesktop.org/wiki/DRM/)
- [libevdev](https://freedesktop.org/wiki/Software/libevdev/)
- [libGL](https://mesa3d.org)
- [libinput](https://freedesktop.org/wiki/Software/libinput/)
- [libjpeg](https://libjpeg-turbo.org)
- [libpng](http://libpng.org/pub/png/libpng.html)
- [libxkbcommon](https://xkbcommon.org)
- [libxml2](http://xmlsoft.org/)
- [Pixman](https://pixman.org)
- [pkg-config](https://freedesktop.org/wiki/Software/pkg-config/)
- [Wayland](https://wayland.freedesktop.org)
- [wayland-protocols](https://gitlab.freedesktop.org/wayland/wayland-protocols)
- [wf-config](https://github.com/WayfireWM/wf-config)
- [wlroots](https://github.com/swaywm/wlroots)
### wlroots Dependencies
These are the dependencies needed for building wlroots, and should be installed before building it.
They are relevant for cases when the system doesn't have a version of wlroots installed.
#### DRM Backend (required)
- [libdisplay-info-dev](https://gitlab.freedesktop.org/emersion/libdisplay-info)
- [hwdata-dev](https://github.com/vcrhonek/hwdata)
#### GLES2 renderer (required)
- [libglvnd](https://gitlab.freedesktop.org/glvnd/libglvnd)
- [mesa](https://gitlab.freedesktop.org/mesa/mesa) (with libEGL and gbm support)
#### Libinput Backend (required)
- [libinput](https://gitlab.freedesktop.org/libinput/libinput)
#### Session Provider (required)
- libudev (via [systemd](https://systemd.io/) **or** other providers)
- [seatd](https://git.sr.ht/~kennylevinsen/seatd)
#### XWayland Support (optional)
- [xcb](https://xcb.freedesktop.org/)
- [xcb-composite](https://xorg.freedesktop.org/wiki/)
- [xcb-render](https://xorg.freedesktop.org/wiki/)
- [xcb-xfixes](https://xorg.freedesktop.org/wiki/)
#### X11 Backend (optional)
- [xcb](https://xcb.freedesktop.org/)
- [x11-xcb](https://xcb.freedesktop.org/)
- [xcb-xinput](https://xorg.freedesktop.org/wiki/)
- [xcb-xfixes](https://xorg.freedesktop.org/wiki/)
## Installation
The easiest way to install Wayfire, wf-shell and WCM to get a functional desktop is to use the [install scripts](https://github.com/WayfireWM/wf-install).
Alternatively, you can build from source:
``` sh
meson build
ninja -C build
sudo ninja -C build install
```
**Note**: `wf-config` and `wlroots` can be built as submodules, by specifying
`-Duse_system_wfconfig=disabled` and `-Duse_system_wlroots=disabled` options to `meson`.
This is the default if they are not present on your system.
Installing [wf-shell](https://github.com/WayfireWM/wf-shell) is recommended for a complete experience.
###### Arch Linux
[wayfire](https://aur.archlinux.org/packages/wayfire/) and [wayfire-git] are available in the [AUR].
``` sh
yay -S wayfire
```
[AUR]: https://aur.archlinux.org
[wayfire-git]: https://aur.archlinux.org/packages/wayfire-git/
###### Exherbo
``` sh
cave resolve -x wayfire
```
###### Fedora
``` sh
dnf install wayfire
```
###### FreeBSD
Install the latest release and recommended addons with
``` sh
pkg install wayfire wayfire-plugins-extra wf-shell wcm
```
###### Gentoo
Install the latest release with
```sh
emerge --ask --verbose wayfire
```
and to use the live version
```sh
emerge --ask --verbose "=gui-wm/wayfire-9999"
```
###### NixOS
Enable Wayfire in your NixOS configuration:
```nix
programs.wayfire = {
enable = true;
plugins = with pkgs.wayfirePlugins; [
wcm
wf-shell
wayfire-plugins-extra
];
};
```
###### Ubuntu
```
apt install wayfire
```
###### Void
``` sh
xbps-install -S wayfire
```
## Configuration
Copy [`wayfire.ini`] to `~/.config/wayfire.ini`.
Before running Wayfire, you may want to change the command to start a terminal.
See the [Configuration] document for information on the options.
[`wayfire.ini`]: wayfire.ini
## Running
Run [`wayfire`][Manual] from a TTY, or via a Wayland-compatible login manager.
wayfire-0.9.0/config.h.in 0000664 0000000 0000000 00000000575 14662337126 0015232 0 ustar 00root root 0000000 0000000 #ifndef CONFIG_H
#define CONFIG_H
#define INSTALL_PREFIX "@INSTALL_PREFIX@"
#define PLUGIN_PATH "@PLUGIN_PATH@"
#define PLUGIN_XML_DIR "@PLUGIN_XML_DIR@"
#define SYSCONFDIR "@SYSCONFDIR@"
#define WF_DEFAULT_CONFIG_BACKEND "@DEFAULT_CONFIG_BACKEND@"
#mesondefine BUILD_WITH_IMAGEIO
#mesondefine USE_GLES32
#mesondefine WF_HAS_XWAYLAND
#endif /* end of include guard: CONFIG_H */
wayfire-0.9.0/man/ 0000775 0000000 0000000 00000000000 14662337126 0013753 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/man/meson.build 0000664 0000000 0000000 00000000274 14662337126 0016120 0 ustar 00root root 0000000 0000000 configure_file(input: 'wayfire.1.in',
output: 'wayfire.1',
configuration: conf_data)
install_man(join_paths(meson.project_build_root(), 'man', 'wayfire.1'))
wayfire-0.9.0/man/wayfire.1.in 0000664 0000000 0000000 00000005156 14662337126 0016117 0 ustar 00root root 0000000 0000000 .Dd $Mdocdate: May 21 2023 $
.Dt WAYFIRE 1
.Os
.Sh NAME
.Nm wayfire
.Nd modular and extensible wayland compositor
.Sh SYNOPSIS
.Nm wayfire
.Op Fl c , -config Ar config_file
.Op Fl B , -config-backend Ar config_backend
.Op Fl d , -debug
.Op Fl D , -damage-debug
.Op Fl h , -help
.Op Fl R , -damage-renderer
.Op Fl v , -version
.Sh DESCRIPTION
.Nm
is a wayland compositor focusing on modularity and extensibility by providing a
small core compositor implementation with all major functionality being provided
by plugins.
The default plugins provide 3D effects similar to compiz, such as 3D cube,
wobbly windows, blur, fish eye, etc.
.Pp
The optional flags are described as follows:
.Pp
.Bl -tag -width Ds -compact
.It Fl c , -config Ar config_file
.Pp
Start
.Nm
with an alternative configuration file.
The default configuration file is searched first in the
.Ev ${WAYFIRE_CONFIG_FILE}
environment variable, or paths
.Pa ${XDG_CONFIG_HOME}/wayfire.ini ,
.Pa ${HOME}/.config/wayfire.ini .
.Pp
.It Fl B , -config-backend Ar config_backend
.Pp
Specify config backend to use.
.Pp
.It Fl d , -debug
.Pp
Enable debug logging.
.Pp
.It Fl D , -damage-debug
.Pp
Enable additional debug for damaged regions.
.Pp
.It Fl h , -help
.Pp
Print a short help message.
.Pp
.It Fl R , -damage-renderer
.Pp
Rerender damaged regions.
.Pp
.It Fl v , -version
.Pp
Print the version.
.El
.Sh ENVIRONMENT VARIABLES
.Nm
respects the following environment variables:
.Pp
.Bl -tag -width Ds -compact
.It Ev WAYFIRE_CONFIG_FILE
The config file to use.
.Pp
.It Ev WAYFIRE_PLUGIN_XML_PATH
.Pp
A string of paths, separated by : , in which to look for plugin configuration
files.
By default
.Nm
looks for configuration files in
.Pa @PLUGIN_XML_DIR@
and
.Pa ${XDG_DATA_HOME}/wayfire/metadata .
.Pp
.It Ev WAYFIRE_PLUGIN_PATH
.Pp
A string of paths, separated by : , in which to look for plugins.
By default
.Nm
looks for plugins in
.Pa @PLUGIN_PATH@
and
.Pa ${XDG_DATA_HOME}/wayfire/plugins .
.Pp
.It Ev _WAYFIRE_SOCKET
.Pp
Socket override to use to communicate with a specific
.Nm
instance using the IPC.
Useful incase of multiple running instances of
.Nm .
.El
.Pp
In addition,
.Nm
also sets the following environment variables:
.Pp
.Bl -tag -width Ds -compact
.It Ev WAYFIRE_SOCKET
.Pp
Socket to use when communicating with
.Nm .
.Pp
.It Ev WAYLAND_DISPLAY
.Pp
Wayland display currently in effect.
.Pp
.It Ev CONFIG_FILE_ENV
.Pp
Which config file is being used.
.Pp
.It Ev _JAVA_AWT_WM_NONREPARENTING
.Pp
Needed for java based windows and it is set to 1.
.Pp
.It Ev DISPLAY
.It Ev XCURSOR_SIZE
.It Ev XCURSOR_THEME
.Pp
Variables for use with legacy
.Xr xwayland 1
windows.
.El
.Sh SEE ALSO
.Xr xwayland 1
wayfire-0.9.0/meson.build 0000664 0000000 0000000 00000017344 14662337126 0015353 0 ustar 00root root 0000000 0000000 project(
'wayfire',
'c',
'cpp',
version: '0.9.0',
license: 'MIT',
meson_version: '>=0.63.0',
default_options: [
'cpp_std=c++17',
'c_std=c11',
'warning_level=2',
'werror=false',
],
)
version = '"@0@"'.format(meson.project_version())
add_project_arguments('-DWAYFIRE_VERSION=@0@'.format(version), language: 'cpp')
wayfire_api_inc = include_directories('src/api')
wayland_server = dependency('wayland-server')
wayland_client = dependency('wayland-client')
wayland_cursor = dependency('wayland-cursor')
wayland_protos = dependency('wayland-protocols', version: '>=1.12')
cairo = dependency('cairo')
pango = dependency('pango')
pangocairo = dependency('pangocairo')
drm = dependency('libdrm')
egl = dependency('egl')
glesv2 = dependency('glesv2')
glm = dependency('glm', required: false)
libinput = dependency('libinput', version: '>=1.7.0')
pixman = dependency('pixman-1')
xkbcommon = dependency('xkbcommon')
libdl = meson.get_compiler('cpp').find_library('dl')
json = dependency('nlohmann_json', version: '>= 3.11.2')
# We're not to use system wlroots: So we'll use the subproject
if get_option('use_system_wlroots').disabled()
use_system_wlroots = false
wlroots = subproject('wlroots', default_options : ['examples=false']).get_variable('wlroots')
elif get_option('use_system_wlroots').enabled()
use_system_wlroots = true
wlroots = dependency('wlroots', version: ['>=0.17.0', '<0.18.0'], required: true)
elif get_option('use_system_wlroots').auto()
message( 'SEARCHING FOR WLROOTS' )
wlroots = dependency('wlroots', version: ['>=0.17.0', '<0.18.0'], required: false)
use_system_wlroots = true
if not wlroots.found()
use_system_wlroots = false
wlroots = subproject('wlroots', default_options : ['examples=false']).get_variable('wlroots')
endif
endif
wlroots_features = {
'xwayland': false,
'drm_backend': false,
'gles2_renderer': false,
'libinput_backend': false,
'session': false,
'x11_backend': false,
}
foreach name, _ : wlroots_features
var_name = 'have_' + name.underscorify()
wlroots_features += { name: wlroots.get_variable(pkgconfig: var_name, internal: var_name) == 'true' }
endforeach
required_wlroots_features= [
'drm_backend',
'gles2_renderer',
'session',
'libinput_backend',
]
missing_wlroots_features = []
# Required features based on currently exposed public api
foreach required_feature : required_wlroots_features
if not wlroots_features[required_feature]
missing_wlroots_features += required_feature
endif
endforeach
if missing_wlroots_features.length() > 0
error('wlroots is missing the following required features: @0@'.format(' '.join(missing_wlroots_features)))
endif
# We're not to use system wlroots: So we'll use the subproject
if get_option('use_system_wfconfig').disabled()
use_system_wfconfig = false
wfconfig = subproject('wf-config').get_variable('wfconfig')
elif get_option('use_system_wfconfig').enabled()
use_system_wfconfig = true
wfconfig = dependency('wf-config', version: ['>=0.9.0', '<0.10.0'], required: true)
elif get_option('use_system_wfconfig').auto()
wfconfig = dependency('wf-config', version: ['>=0.9.0', '<0.10.0'], required: false)
use_system_wfconfig = true
if not wfconfig.found()
use_system_wfconfig = false
wfconfig = subproject('wf-config').get_variable('wfconfig')
endif
endif
if not glm.found() and not meson.get_compiler('cpp').check_header('glm/glm.hpp')
error('GLM not found, and directly using the header \'glm/glm.hpp\' is not possible.')
endif
backtrace = meson.get_compiler('cpp').find_library('execinfo', required: false)
wfutils = subproject('wf-utils').get_variable('wfutils')
wftouch = subproject('wf-touch').get_variable('wftouch')
needs_libinotify = ['freebsd', 'dragonfly'].contains(host_machine.system())
libinotify = dependency('libinotify', required: needs_libinotify)
jpeg = dependency('libjpeg', required: false)
png = dependency('libpng', required: false)
# backtrace() is in a separate library on FreeBSD and Linux with musl
backtrace = meson.get_compiler('cpp').find_library('execinfo', required: false)
conf_data = configuration_data()
conf_data.set('INSTALL_PREFIX', get_option('prefix'))
conf_data.set('PLUGIN_PATH', join_paths(get_option('prefix'), get_option('libdir'), 'wayfire'))
metadata_dir_suffix = 'share/wayfire/metadata'
conf_data.set('PLUGIN_XML_DIR', join_paths(get_option('prefix'), metadata_dir_suffix))
sysconfdir = join_paths(get_option('prefix'), get_option('sysconfdir'))
conf_data.set('SYSCONFDIR', sysconfdir)
pkgdatadir = join_paths(get_option('prefix'), 'share', 'wayfire', 'protocols')
if get_option('default_config_backend') == 'default'
conf_data.set('DEFAULT_CONFIG_BACKEND', join_paths(conf_data.get('PLUGIN_PATH'), 'libdefault-config-backend.so'))
else
conf_data.set('DEFAULT_CONFIG_BACKEND', get_option('default_config_backend'))
endif
cpp = meson.get_compiler('cpp')
# needed to dlopen() plugins
# -E is for RTTI/dynamic_cast across plugins
add_project_link_arguments(['-rdynamic', '-Wl,-E'], language: 'cpp')
project_args = ['-DWLR_USE_UNSTABLE']
# Needed for dlclose to actually free plugin memory on gcc+glibc
if cpp.has_argument('-fno-gnu-unique')
project_args += '-fno-gnu-unique'
endif
add_project_arguments(project_args, language: ['cpp', 'c'])
# Needed on some older compilers
if cpp.has_link_argument('-lc++fs')
add_project_link_arguments(['-lc++fs'], language: 'cpp')
elif cpp.has_link_argument('-lc++experimental')
add_project_link_arguments(['-lc++experimental'], language: 'cpp')
elif cpp.has_link_argument('-lstdc++fs')
add_project_link_arguments(['-lstdc++fs'], language: 'cpp')
endif
if get_option('enable_gles32')
cpp.check_header('GLES3/gl32.h', dependencies: glesv2, required: true)
conf_data.set('USE_GLES32', true)
else
conf_data.set('USE_GLES32', false)
endif
if png.found() and jpeg.found()
conf_data.set('BUILD_WITH_IMAGEIO', true)
else
conf_data.set('BUILD_WITH_IMAGEIO', false)
endif
wayfire_conf_inc = include_directories(['.'])
add_project_arguments(['-Wno-unused-parameter'], language: 'cpp')
if get_option('xwayland').enabled() and not wlroots_features['xwayland']
error('Cannot enable Xwayland in wayfire: wlroots has been built without Xwayland support')
endif
if get_option('xwayland').enabled() or (get_option('xwayland').auto() and wlroots_features['xwayland'])
xcb = dependency('xcb')
conf_data.set('WF_HAS_XWAYLAND', 1)
else
xcb = declare_dependency() # dummy dep
conf_data.set('WF_HAS_XWAYLAND', 0)
endif
if get_option('print_trace')
print_trace = true
else
print_trace = false
endif
add_project_arguments(['-DWF_USE_CONFIG_H'], language: ['cpp', 'c'])
configure_file(input: 'config.h.in',
output: 'config.h',
install: true,
install_dir: join_paths('include', 'wayfire'),
configuration: conf_data)
subdir('proto')
subdir('src')
subdir('man')
subdir('metadata')
subdir('plugins')
# Unit tests
doctest = dependency('doctest', required: get_option('tests'))
if doctest.found()
subdir('test')
endif
install_data('wayfire.desktop', install_dir :
join_paths(get_option('prefix'), 'share/wayland-sessions'))
summary = [
'',
'----------------',
'wayfire @0@'.format(meson.project_version()),
'',
'system wfconfig: @0@'.format(use_system_wfconfig),
' system wlroots: @0@'.format(use_system_wlroots),
' xwayland: @0@'.format(wlroots_features['xwayland']),
' x11-backend: @0@'.format(wlroots_features['x11_backend']),
' imageio: @0@'.format(conf_data.get('BUILD_WITH_IMAGEIO')),
' gles32: @0@'.format(conf_data.get('USE_GLES32')),
' print trace: @0@'.format(print_trace),
' unit tests: @0@'.format(doctest.found()),
'----------------',
''
]
message('\n'.join(summary))
wayfire-0.9.0/meson_options.txt 0000664 0000000 0000000 00000001605 14662337126 0016637 0 ustar 00root root 0000000 0000000 option('enable_gles32', type: 'boolean', value: true, description: 'Enable usage of GLES 3.2')
option('enable_openmp', type: 'boolean', value: true, description: 'Enable usage of OpenMP')
option('use_system_wfconfig', type: 'feature', value: 'auto', description: 'Use the system-wide installation of wf-config')
option('use_system_wlroots', type: 'feature', value: 'auto', description: 'Use the system-wide installation of wlroots')
option('xwayland', type: 'feature', value: 'auto', description: 'Build with xwayland support. Requires wlroots also built with xwayland support')
option('default_config_backend', type: 'string', value: 'default', description: 'Default configuration backend to use')
option('print_trace', type: 'boolean', value: true, description: 'Print stack trace in debug logs (disables coredump)')
option('tests', type: 'feature', value: 'auto', description: 'Enable unit tests')
wayfire-0.9.0/metadata/ 0000775 0000000 0000000 00000000000 14662337126 0014760 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/metadata/alpha.xml 0000664 0000000 0000000 00000001334 14662337126 0016570 0 ustar 00root root 0000000 0000000
<_short>Alpha
<_long>A plugin to change the opacity of windows.
Desktop
wayfire-0.9.0/metadata/animate.xml 0000664 0000000 0000000 00000010366 14662337126 0017126 0 ustar 00root root 0000000 0000000
<_short>Animate
<_long>A plugin which provides animations when a window is opened or closed.
Effects
wayfire-0.9.0/metadata/autostart.xml 0000664 0000000 0000000 00000001561 14662337126 0017533 0 ustar 00root root 0000000 0000000
<_short>Autostart
<_long>A plugin to run shell commands on startup.
General
<_short>Autostart
<_long>Specifies the shell commands to run on startup.
wayfire-0.9.0/metadata/blur.xml 0000664 0000000 0000000 00000007470 14662337126 0016456 0 ustar 00root root 0000000 0000000
<_short>Blur
<_long>A plugin to blur windows.
Effects
wayfire-0.9.0/metadata/command.xml 0000664 0000000 0000000 00000004440 14662337126 0017122 0 ustar 00root root 0000000 0000000
<_short>Command
<_long>A plugin to bind key combo (key, button, touch) to execute shell commands.
General
wayfire-0.9.0/metadata/core.xml 0000664 0000000 0000000 00000007276 14662337126 0016446 0 ustar 00root root 0000000 0000000
<_short>Core
<_long>General options.
General
wayfire-0.9.0/metadata/cube.xml 0000664 0000000 0000000 00000007361 14662337126 0016427 0 ustar 00root root 0000000 0000000
<_short>Cube
<_long>A plugin to show the current workspace row as a cube.
Desktop
<_short>Bindings
<_long>Sets the cube bindings.
wayfire-0.9.0/metadata/decoration.xml 0000664 0000000 0000000 00000003041 14662337126 0017627 0 ustar 00root root 0000000 0000000
<_short>Decoration
<_long>Default decorations around XWayland windows.
Effects
wayfire-0.9.0/metadata/expo.xml 0000664 0000000 0000000 00000004042 14662337126 0016455 0 ustar 00root root 0000000 0000000
<_short>Expo
<_long>A plugin to show an overview of all workspaces.
Desktop
wayfire-0.9.0/metadata/extra-gestures.xml 0000664 0000000 0000000 00000001730 14662337126 0020465 0 ustar 00root root 0000000 0000000
<_short>Extra Touchscreen Gestures
<_long>A plugin which provides several touchscreen gestures.
Desktop
wayfire-0.9.0/metadata/fast-switcher.xml 0000664 0000000 0000000 00000001632 14662337126 0020267 0 ustar 00root root 0000000 0000000
<_short>Fast Switcher
<_long>A plugin to switch active window.
Window Management
wayfire-0.9.0/metadata/fisheye.xml 0000664 0000000 0000000 00000001412 14662337126 0017134 0 ustar 00root root 0000000 0000000
<_short>Fisheye
<_long>A plugin which provides fisheye effect.
Effects
wayfire-0.9.0/metadata/foreign-toplevel.xml 0000664 0000000 0000000 00000000373 14662337126 0020766 0 ustar 00root root 0000000 0000000
<_short>Foreign Toplevel Protocol
<_long>An implementation of the wlr-foreign-toplevel-management-v1 protocol.
Utility
wayfire-0.9.0/metadata/grid.xml 0000664 0000000 0000000 00000006715 14662337126 0016440 0 ustar 00root root 0000000 0000000
<_short>Grid
<_long>A plugin to position the windows in certain regions of the output.
Window Management
wayfire-0.9.0/metadata/gtk-shell.xml 0000664 0000000 0000000 00000000324 14662337126 0017373 0 ustar 00root root 0000000 0000000
<_short>GTK Shell Protocol
<_long>An implementation of the gtk-shell protocol.
Utility
wayfire-0.9.0/metadata/idle.xml 0000664 0000000 0000000 00000004227 14662337126 0016424 0 ustar 00root root 0000000 0000000
<_short>Idle
<_long>A plugin for idle settings, such as the screensaver and DPMS.
Desktop
wayfire-0.9.0/metadata/input-device.xml 0000664 0000000 0000000 00000000310 14662337126 0020070 0 ustar 00root root 0000000 0000000
wayfire-0.9.0/metadata/input-method-v1.xml 0000664 0000000 0000000 00000001242 14662337126 0020442 0 ustar 00root root 0000000 0000000
<_short>Input-Method-V1 Protocol
<_long>An implementation of the input-method-v1 protocol. Needed for proper functioning of input methods like Fcitx5.
Utility
wayfire-0.9.0/metadata/input.xml 0000664 0000000 0000000 00000021556 14662337126 0016652 0 ustar 00root root 0000000 0000000
<_short>Input
<_long>Input configuration.
General
<_short>Keyboard
<_long>Configure the keyboard.
<_short>Mouse
<_long>Configure the mouse.
<_short>Touchpad
<_long>Configure the touchpad.
<_short>Tablet
<_long>Configure graphic tablets.
<_short>Cursor
<_long>Configure the cursor.
wayfire-0.9.0/metadata/invert.xml 0000664 0000000 0000000 00000001135 14662337126 0017011 0 ustar 00root root 0000000 0000000
<_short>Invert
<_long>A plugin to invert the colors of the whole output.
Accessibility
wayfire-0.9.0/metadata/ipc-rules.xml 0000664 0000000 0000000 00000000425 14662337126 0017406 0 ustar 00root root 0000000 0000000
<_short>Window Rules IPC Interface
<_long>Interface to allow an external program to implement window rules (requires the IPC plugin).
Window Management
wayfire-0.9.0/metadata/ipc.xml 0000664 0000000 0000000 00000000325 14662337126 0016255 0 ustar 00root root 0000000 0000000
<_short>IPC protocol
<_long>Allow external programs to interact with Wayfire plugins.
Utility
wayfire-0.9.0/metadata/meson.build 0000664 0000000 0000000 00000006500 14662337126 0017123 0 ustar 00root root 0000000 0000000 install_data('alpha.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('animate.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('autostart.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('blur.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('command.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('core.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('cube.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('decoration.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('expo.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('extra-gestures.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('fast-switcher.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('fisheye.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('foreign-toplevel.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('grid.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('gtk-shell.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('idle.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('input.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('input-device.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('input-method-v1.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('invert.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('ipc.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('ipc-rules.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('move.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('oswitch.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('output.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('place.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('preserve-output.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('resize.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('scale.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('simple-tile.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('switcher.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('vswipe.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('vswitch.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('window-rules.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('wm-actions.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('wobbly.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('workarounds.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('wrot.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('zoom.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('scale-title-filter.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('shortcuts-inhibit.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('wsets.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('wayfire-shell.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('xdg-activation.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
install_data('session-lock.xml', install_dir: conf_data.get('PLUGIN_XML_DIR'))
wayfire-0.9.0/metadata/move.xml 0000664 0000000 0000000 00000005244 14662337126 0016455 0 ustar 00root root 0000000 0000000
<_short>Move
<_long>A plugin to move windows around by dragging them from any part (not just the title bar).
Window Management
wayfire-0.9.0/metadata/oswitch.xml 0000664 0000000 0000000 00000002153 14662337126 0017163 0 ustar 00root root 0000000 0000000
<_short>Output Switcher
<_long>A plugin to change the focused output.
Desktop
wayfire-0.9.0/metadata/output.xml 0000664 0000000 0000000 00000001236 14662337126 0017044 0 ustar 00root root 0000000 0000000
wayfire-0.9.0/metadata/place.xml 0000664 0000000 0000000 00000001257 14662337126 0016573 0 ustar 00root root 0000000 0000000
<_short>Place
<_long>A plugin to position newly opened windows.
Window Management
wayfire-0.9.0/metadata/preserve-output.xml 0000664 0000000 0000000 00000001144 14662337126 0020673 0 ustar 00root root 0000000 0000000
<_short>Preserve Output
<_long>A plugin to restore windows to their original position if outputs are temporarily disconnected.
Window Management
wayfire-0.9.0/metadata/resize.xml 0000664 0000000 0000000 00000001364 14662337126 0017007 0 ustar 00root root 0000000 0000000
<_short>Resize
<_long>A plugin to resize windows by dragging them from any part (not just the edges).
Window Management
wayfire-0.9.0/metadata/scale-title-filter.xml 0000664 0000000 0000000 00000002524 14662337126 0021176 0 ustar 00root root 0000000 0000000
<_short>Scale Title Filter
<_long>Filter the views shown by scale by typing.
Utility
wayfire-0.9.0/metadata/scale.xml 0000664 0000000 0000000 00000010256 14662337126 0016575 0 ustar 00root root 0000000 0000000
<_short>Scale
<_long>Show all views on screen.
Accessibility
<_short>Behavior
<_short>Appearance
wayfire-0.9.0/metadata/session-lock.xml 0000664 0000000 0000000 00000000411 14662337126 0020107 0 ustar 00root root 0000000 0000000
<_short>Session Lock Protocol
<_long>An implementation of the ext-session-lock-v1 protocol. Provides more secure screen locking.
Utility
wayfire-0.9.0/metadata/shortcuts-inhibit.xml 0000664 0000000 0000000 00000001614 14662337126 0021166 0 ustar 00root root 0000000 0000000
<_short>Keyboard Shortcuts Inhibit Protocol
<_long>An implementation of the keyboard-shortcuts-inhibit-v1 protocol.
Utility
wayfire-0.9.0/metadata/simple-tile.xml 0000664 0000000 0000000 00000007263 14662337126 0017736 0 ustar 00root root 0000000 0000000
<_short>Simple Tile
<_long>A plugin which provides some tiling features, inspired by Sway. The plugin is meant to contain only the basics.
Window Management
wayfire-0.9.0/metadata/switcher.xml 0000664 0000000 0000000 00000002257 14662337126 0017340 0 ustar 00root root 0000000 0000000
<_short>Switcher
<_long>A plugin to change active window with an animation.
Window Management
wayfire-0.9.0/metadata/vswipe.xml 0000664 0000000 0000000 00000004350 14662337126 0017021 0 ustar 00root root 0000000 0000000
<_short>Viewport Swipe
<_long>A plugin to swipe workspaces in a grid.
Desktop
wayfire-0.9.0/metadata/vswitch.xml 0000664 0000000 0000000 00000012420 14662337126 0017170 0 ustar 00root root 0000000 0000000
<_short>Viewport Switcher
<_long>A plugin to switch workspaces in a grid.
Desktop
wayfire-0.9.0/metadata/wayfire-shell.xml 0000664 0000000 0000000 00000000634 14662337126 0020260 0 ustar 00root root 0000000 0000000
<_short>Wayfire Shell Protocol
<_long>An implementation of the wayfire-shell protocol.
Utility
wayfire-0.9.0/metadata/window-rules.xml 0000664 0000000 0000000 00000001055 14662337126 0020142 0 ustar 00root root 0000000 0000000
<_short>Window Rules
<_long>A plugin to apply specific commands to windows by using various criteria.
Window Management
wayfire-0.9.0/metadata/wm-actions.xml 0000664 0000000 0000000 00000002771 14662337126 0017572 0 ustar 00root root 0000000 0000000
<_short>WM Actions
<_long>A plugin which provides various window management functionalities.
Window Management
wayfire-0.9.0/metadata/wobbly.xml 0000664 0000000 0000000 00000001217 14662337126 0017001 0 ustar 00root root 0000000 0000000
<_short>Wobbly
<_long>A plugin to get wobbly windows.
Effects
wayfire-0.9.0/metadata/workarounds.xml 0000664 0000000 0000000 00000007167 14662337126 0020073 0 ustar 00root root 0000000 0000000
<_short>Workarounds
<_long>Some hacks that might be required to make things work.
Utility
wayfire-0.9.0/metadata/wrot.xml 0000664 0000000 0000000 00000003204 14662337126 0016474 0 ustar 00root root 0000000 0000000
<_short>Window Rotate
<_long>A plugin to rotate windows with the mouse.
Effects
wayfire-0.9.0/metadata/wsets.xml 0000664 0000000 0000000 00000001751 14662337126 0016653 0 ustar 00root root 0000000 0000000
<_short>Workspace Sets
<_long>A plugin which allows manipulation of workspace sets.
Desktop
wayfire-0.9.0/metadata/xdg-activation.xml 0000664 0000000 0000000 00000000346 14662337126 0020426 0 ustar 00root root 0000000 0000000
<_short>XDG Activation Protocol
<_long>An implementation of the xdg-activation-v1 protocol.
Utility
wayfire-0.9.0/metadata/zoom.xml 0000664 0000000 0000000 00000002232 14662337126 0016465 0 ustar 00root root 0000000 0000000
<_short>Zoom
<_long>A plugin to zoom in the desktop with the mouse.
Accessibility
wayfire-0.9.0/plugins/ 0000775 0000000 0000000 00000000000 14662337126 0014661 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/plugins/animate/ 0000775 0000000 0000000 00000000000 14662337126 0016277 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/plugins/animate/animate.cpp 0000664 0000000 0000000 00000034301 14662337126 0020422 0 ustar 00root root 0000000 0000000 #include
#include
#include
#include
#include
#include
#include
#include "animate.hpp"
#include "system_fade.hpp"
#include "basic_animations.hpp"
#include "fire/fire.hpp"
#include "unmapped-view-node.hpp"
#include "wayfire/plugin.hpp"
#include "wayfire/scene-operations.hpp"
#include "wayfire/scene.hpp"
#include "wayfire/signal-provider.hpp"
#include "wayfire/view.hpp"
#include
void animation_base::init(wayfire_view, wf::animation_description_t, wf_animation_type)
{}
bool animation_base::step()
{
return false;
}
void animation_base::reverse()
{}
int animation_base::get_direction()
{
return 1;
}
animation_base::~animation_base()
{}
static constexpr const char *animate_custom_data_fire = "animation-hook-fire";
static constexpr const char *animate_custom_data_zoom = "animation-hook-zoom";
static constexpr const char *animate_custom_data_fade = "animation-hook-fade";
static constexpr const char *animate_custom_data_minimize =
"animation-hook-minimize";
static constexpr int HIDDEN = 0;
static constexpr int SHOWN = 1;
/* Represents an animation running for a specific view
* animation_t is which animation to use (i.e fire, zoom, etc). */
struct animation_hook_base : public wf::custom_data_t
{
virtual void stop_hook(bool) = 0;
virtual void reverse(wf_animation_type) = 0;
virtual int get_direction() = 0;
animation_hook_base() = default;
virtual ~animation_hook_base() = default;
animation_hook_base(const animation_hook_base &) = default;
animation_hook_base(animation_hook_base &&) = default;
animation_hook_base& operator =(const animation_hook_base&) = default;
animation_hook_base& operator =(animation_hook_base&&) = default;
};
template
struct animation_hook : public animation_hook_base
{
static_assert(std::is_base_of::value,
"animation_type must be derived from animation_base!");
std::shared_ptr view;
wf_animation_type type;
std::string name;
wf::output_t *current_output = nullptr;
std::unique_ptr animation;
std::shared_ptr unmapped_contents;
void damage_whole_view()
{
view->damage();
if (unmapped_contents)
{
wf::scene::damage_node(unmapped_contents, unmapped_contents->get_bounding_box());
}
}
/* Update animation right before each frame */
wf::effect_hook_t update_animation_hook = [=] ()
{
damage_whole_view();
bool result = animation->step();
damage_whole_view();
if (!result)
{
stop_hook(false);
}
};
/**
* Switch the output the view is being animated on, and update the lastly
* animated output in the global list.
*/
void set_output(wf::output_t *new_output)
{
if (current_output)
{
current_output->render->rem_effect(&update_animation_hook);
}
if (new_output)
{
new_output->render->add_effect(&update_animation_hook,
wf::OUTPUT_EFFECT_PRE);
}
current_output = new_output;
}
wf::signal::connection_t on_set_output = [=] (auto)
{
set_output(view->get_output());
};
animation_hook(wayfire_view view, wf::animation_description_t duration, wf_animation_type type,
std::string name)
{
this->type = type;
this->view = view->shared_from_this();
this->name = name;
animation = std::make_unique();
animation->init(view, duration, type);
set_output(view->get_output());
/* Animation is driven by the output render cycle the view is on.
* Thus, we need to keep in sync with the current output. */
view->connect(&on_set_output);
wf::scene::set_node_enabled(view->get_root_node(), true);
if (type == ANIMATION_TYPE_UNMAP)
{
set_unmapped_contents();
}
}
void stop_hook(bool detached) override
{
view->erase_data(name);
}
// When showing the final unmap animation, we show a ``fake'' node instead of the actual view contents,
// because the underlying (sub)surfaces might be destroyed.
//
// The unmapped contents have to be visible iff the view is in an unmap animation.
void set_unmapped_contents()
{
if (!unmapped_contents)
{
unmapped_contents = std::make_shared(view);
auto parent = dynamic_cast(
view->get_surface_root_node()->parent());
if (parent)
{
wf::scene::add_front(
std::dynamic_pointer_cast(parent->shared_from_this()),
unmapped_contents);
}
}
}
void unset_unmapped_contents()
{
if (unmapped_contents)
{
wf::scene::remove_child(unmapped_contents);
unmapped_contents.reset();
}
}
void reverse(wf_animation_type type) override
{
if (type == ANIMATION_TYPE_UNMAP)
{
set_unmapped_contents();
} else
{
unset_unmapped_contents();
}
this->type = type;
if (animation)
{
animation->reverse();
}
}
int get_direction() override
{
return animation->get_direction();
}
~animation_hook()
{
/**
* Order here is very important.
* After doing unref() the view will be potentially destroyed.
* Hence, we want to deinitialize everything else before that.
*/
set_output(nullptr);
on_set_output.disconnect();
this->animation.reset();
unset_unmapped_contents();
wf::scene::set_node_enabled(view->get_root_node(), false);
}
animation_hook(const animation_hook &) = delete;
animation_hook(animation_hook &&) = delete;
animation_hook& operator =(const animation_hook&) = delete;
animation_hook& operator =(animation_hook&&) = delete;
};
static void cleanup_views_on_output(wf::output_t *output)
{
std::vector> all_views;
for (auto& view : wf::get_core().get_all_views())
{
all_views.push_back(view->shared_from_this());
}
for (auto& view : all_views)
{
auto wo = view->get_output();
if ((wo != output) && output)
{
continue;
}
if (view->has_data(animate_custom_data_fire))
{
view->get_data(
animate_custom_data_fire)->stop_hook(true);
}
if (view->has_data(animate_custom_data_zoom))
{
view->get_data(
animate_custom_data_zoom)->stop_hook(true);
}
if (view->has_data(animate_custom_data_fade))
{
view->get_data(
animate_custom_data_fade)->stop_hook(true);
}
if (view->has_data(animate_custom_data_minimize))
{
view->get_data(
animate_custom_data_minimize)->stop_hook(true);
}
}
}
class wayfire_animation : public wf::plugin_interface_t, private wf::per_output_tracker_mixin_t<>
{
wf::option_wrapper_t open_animation{"animate/open_animation"};
wf::option_wrapper_t close_animation{"animate/close_animation"};
wf::option_wrapper_t default_duration{"animate/duration"};
wf::option_wrapper_t fade_duration{"animate/fade_duration"};
wf::option_wrapper_t zoom_duration{"animate/zoom_duration"};
wf::option_wrapper_t fire_duration{"animate/fire_duration"};
wf::option_wrapper_t startup_duration{"animate/startup_duration"};
wf::view_matcher_t animation_enabled_for{"animate/enabled_for"};
wf::view_matcher_t fade_enabled_for{"animate/fade_enabled_for"};
wf::view_matcher_t zoom_enabled_for{"animate/zoom_enabled_for"};
wf::view_matcher_t fire_enabled_for{"animate/fire_enabled_for"};
public:
void init() override
{
init_output_tracking();
}
void handle_new_output(wf::output_t *output) override
{
output->connect(&on_view_mapped);
output->connect(&on_view_pre_unmap);
output->connect(&on_render_start);
output->connect(&on_minimize_request);
}
void handle_output_removed(wf::output_t *output) override
{
cleanup_views_on_output(output);
}
void fini() override
{
cleanup_views_on_output(nullptr);
}
struct view_animation_t
{
std::string animation_name;
wf::animation_description_t duration;
};
view_animation_t get_animation_for_view(
wf::option_wrapper_t& anim_type, wayfire_view view)
{
/* Determine the animation for the given view.
* Note that the matcher plugin might not have been loaded, so
* we need to have a fallback algorithm */
if (fade_enabled_for.matches(view))
{
return {"fade", fade_duration};
}
if (zoom_enabled_for.matches(view))
{
return {"zoom", zoom_duration};
}
if (fire_enabled_for.matches(view))
{
return {"fire", fire_duration};
}
if (animation_enabled_for.matches(view))
{
return {anim_type, default_duration};
}
return {"none", wf::animation_description_t{0, {}, ""}};
}
bool try_reverse(wayfire_view view, wf_animation_type type, std::string name,
int visibility)
{
visibility = !visibility;
if (view->has_data(name))
{
auto data = view->get_data(name);
if (data->get_direction() == visibility)
{
data->reverse(type);
return true;
}
}
return false;
}
template
void set_animation(wayfire_view view,
wf_animation_type type, wf::animation_description_t duration, std::string name)
{
name = "animation-hook-" + name;
if (type == ANIMATION_TYPE_MAP)
{
if (try_reverse(view, type, name, SHOWN))
{
return;
}
auto animation = get_animation_for_view(open_animation, view);
view->store_data(
std::make_unique>(view, duration, type,
name), name);
} else if (type == ANIMATION_TYPE_UNMAP)
{
if (try_reverse(view, type, name, HIDDEN))
{
return;
}
auto animation = get_animation_for_view(close_animation, view);
view->store_data(
std::make_unique>(view, duration, type,
name), name);
} else if (type & MINIMIZE_STATE_ANIMATION)
{
if (view->has_data(animate_custom_data_minimize))
{
view->get_data(
animate_custom_data_minimize)->reverse(type);
return;
}
view->store_data(
std::make_unique>(view, duration, type,
animate_custom_data_minimize),
animate_custom_data_minimize);
}
}
/* TODO: enhance - add more animations */
wf::signal::connection_t on_view_mapped = [=] (wf::view_mapped_signal *ev)
{
auto animation = get_animation_for_view(open_animation, ev->view);
if (animation.animation_name == "fade")
{
set_animation(ev->view, ANIMATION_TYPE_MAP,
animation.duration, animation.animation_name);
} else if (animation.animation_name == "zoom")
{
set_animation(ev->view, ANIMATION_TYPE_MAP,
animation.duration, animation.animation_name);
} else if (animation.animation_name == "fire")
{
set_animation(ev->view, ANIMATION_TYPE_MAP,
animation.duration, animation.animation_name);
}
};
wf::signal::connection_t on_view_pre_unmap =
[=] (wf::view_pre_unmap_signal *ev)
{
auto animation = get_animation_for_view(close_animation, ev->view);
if (animation.animation_name == "fade")
{
set_animation(ev->view, ANIMATION_TYPE_UNMAP,
animation.duration, animation.animation_name);
} else if (animation.animation_name == "zoom")
{
set_animation(ev->view, ANIMATION_TYPE_UNMAP,
animation.duration, animation.animation_name);
} else if (animation.animation_name == "fire")
{
set_animation(ev->view, ANIMATION_TYPE_UNMAP,
animation.duration, animation.animation_name);
}
};
wf::signal::connection_t on_minimize_request =
[=] (wf::view_minimize_request_signal *ev)
{
if (ev->state)
{
set_animation(ev->view, ANIMATION_TYPE_MINIMIZE, default_duration, "minimize");
} else
{
set_animation(ev->view, ANIMATION_TYPE_RESTORE, default_duration, "minimize");
}
// ev->carried_out should remain false, so that core also does the automatic minimize/restore and
// refocus
};
wf::signal::connection_t on_render_start =
[=] (wf::output_start_rendering_signal *ev)
{
new wf_system_fade(ev->output, startup_duration);
};
};
DECLARE_WAYFIRE_PLUGIN(wayfire_animation);
wayfire-0.9.0/plugins/animate/animate.hpp 0000664 0000000 0000000 00000002276 14662337126 0020435 0 ustar 00root root 0000000 0000000 #ifndef ANIMATE_H_
#define ANIMATE_H_
#include
#include
#include
#define HIDING_ANIMATION (1 << 0)
#define SHOWING_ANIMATION (1 << 1)
#define MAP_STATE_ANIMATION (1 << 2)
#define MINIMIZE_STATE_ANIMATION (1 << 3)
enum wf_animation_type
{
ANIMATION_TYPE_MAP = SHOWING_ANIMATION | MAP_STATE_ANIMATION,
ANIMATION_TYPE_UNMAP = HIDING_ANIMATION | MAP_STATE_ANIMATION,
ANIMATION_TYPE_MINIMIZE = HIDING_ANIMATION | MINIMIZE_STATE_ANIMATION,
ANIMATION_TYPE_RESTORE = SHOWING_ANIMATION | MINIMIZE_STATE_ANIMATION,
};
class animation_base
{
public:
virtual void init(wayfire_view view, wf::animation_description_t duration, wf_animation_type type);
virtual bool step(); /* return true if continue, false otherwise */
virtual void reverse(); /* reverse the animation */
virtual int get_direction();
animation_base() = default;
virtual ~animation_base();
animation_base(const animation_base &) = default;
animation_base(animation_base &&) = default;
animation_base& operator =(const animation_base&) = default;
animation_base& operator =(animation_base&&) = default;
};
#endif
wayfire-0.9.0/plugins/animate/basic_animations.hpp 0000664 0000000 0000000 00000011462 14662337126 0022317 0 ustar 00root root 0000000 0000000 #include "animate.hpp"
#include "wayfire/toplevel-view.hpp"
#include
#include
#include
#include
#include
class fade_animation : public animation_base
{
wayfire_view view;
float start = 0, end = 1;
wf::animation::simple_animation_t progression;
std::string name;
public:
void init(wayfire_view view, wf::animation_description_t dur, wf_animation_type type) override
{
this->view = view;
this->progression =
wf::animation::simple_animation_t(wf::create_option(dur));
this->progression.animate(start, end);
if (type & HIDING_ANIMATION)
{
this->progression.flip();
}
name = "animation-fade-" + std::to_string(type);
auto tr = std::make_shared(view);
view->get_transformed_node()->add_transformer(
tr, wf::TRANSFORMER_HIGHLEVEL, name);
}
bool step() override
{
auto transform = view->get_transformed_node()
->get_transformer(name);
transform->alpha = this->progression;
return progression.running();
}
void reverse() override
{
this->progression.reverse();
}
int get_direction() override
{
return this->progression.get_direction();
}
~fade_animation()
{
view->get_transformed_node()->rem_transformer(name);
}
};
using namespace wf::animation;
class zoom_animation_t : public duration_t
{
public:
using duration_t::duration_t;
timed_transition_t alpha{*this};
timed_transition_t zoom{*this};
timed_transition_t offset_x{*this};
timed_transition_t offset_y{*this};
};
class zoom_animation : public animation_base
{
wayfire_view view;
zoom_animation_t progression;
std::string name;
public:
void init(wayfire_view view, wf::animation_description_t dur, wf_animation_type type) override
{
this->view = view;
this->progression = zoom_animation_t(wf::create_option(dur));
this->progression.alpha = wf::animation::timed_transition_t(
this->progression, 0, 1);
this->progression.zoom = wf::animation::timed_transition_t(
this->progression, 1. / 3, 1);
this->progression.offset_x = wf::animation::timed_transition_t(
this->progression, 0, 0);
this->progression.offset_y = wf::animation::timed_transition_t(
this->progression, 0, 0);
this->progression.start();
if (type & MINIMIZE_STATE_ANIMATION)
{
auto toplevel = wf::toplevel_cast(view);
wf::dassert(toplevel != nullptr, "We cannot minimize non-toplevel views!");
auto hint = toplevel->get_minimize_hint();
if ((hint.width > 0) && (hint.height > 0))
{
int hint_cx = hint.x + hint.width / 2;
int hint_cy = hint.y + hint.height / 2;
auto bbox = toplevel->get_geometry();
int view_cx = bbox.x + bbox.width / 2;
int view_cy = bbox.y + bbox.height / 2;
progression.offset_x.set(1.0 * hint_cx - view_cx, 0);
progression.offset_y.set(1.0 * hint_cy - view_cy, 0);
if ((bbox.width > 0) && (bbox.height > 0))
{
double scale_x = 1.0 * hint.width / bbox.width;
double scale_y = 1.0 * hint.height / bbox.height;
progression.zoom.set(std::min(scale_x, scale_y), 1);
}
}
}
if (type & HIDING_ANIMATION)
{
progression.alpha.flip();
progression.zoom.flip();
progression.offset_x.flip();
progression.offset_y.flip();
}
name = "animation-zoom-" + std::to_string(type);
auto tr = std::make_shared(view);
view->get_transformed_node()->add_transformer(
tr, wf::TRANSFORMER_HIGHLEVEL, name);
}
bool step() override
{
auto our_transform = view->get_transformed_node()
->get_transformer(name);
float c = this->progression.zoom;
our_transform->alpha = this->progression.alpha;
our_transform->scale_x = c;
our_transform->scale_y = c;
our_transform->translation_x = this->progression.offset_x;
our_transform->translation_y = this->progression.offset_y;
return this->progression.running();
}
void reverse() override
{
this->progression.reverse();
}
~zoom_animation()
{
view->get_transformed_node()->rem_transformer(name);
}
};
wayfire-0.9.0/plugins/animate/fire/ 0000775 0000000 0000000 00000000000 14662337126 0017224 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/plugins/animate/fire/fire.cpp 0000664 0000000 0000000 00000020160 14662337126 0020654 0 ustar 00root root 0000000 0000000 #include "fire.hpp"
#include "particle.hpp"
#include "wayfire/debug.hpp"
#include "wayfire/geometry.hpp"
#include "wayfire/opengl.hpp"
#include "wayfire/scene-render.hpp"
#include "wayfire/scene.hpp"
#include "wayfire/view-transform.hpp"
#include
#include
#include
#include
static wf::option_wrapper_t fire_particles{"animate/fire_particles"};
static wf::option_wrapper_t fire_particle_size{"animate/fire_particle_size"};
static wf::option_wrapper_t random_fire_color{"animate/random_fire_color"};
static wf::option_wrapper_t fire_color{"animate/fire_color"};
// generate a random float between s and e
static float random(float s, float e)
{
double r = 1.0 * (std::rand() % RAND_MAX) / (RAND_MAX - 1);
return (s * r + (1 - r) * e);
}
static int particle_count_for_width(int width)
{
int particles = fire_particles;
return particles * std::min(width / 400.0, 3.5);
}
class fire_node_t : public wf::scene::floating_inner_node_t
{
public:
std::unique_ptr ps;
fire_node_t() : floating_inner_node_t(false)
{
ps = std::make_unique(1);
ps->set_initer(
[=] (Particle& p)
{
init_particle_with_node(p, get_children_bounding_box(), progress_line);
});
}
static void init_particle_with_node(Particle& p,
wf::geometry_t bounding_box, double progress)
{
p.life = 1;
p.fade = random(0.1, 0.6);
wf::color_t color_setting = fire_color;
float r;
float g;
float b;
if (!random_fire_color)
{
// The calculation here makes the variation lower at darker values
float randomize_amount_r = (color_setting.r * 0.857) / 2;
float randomize_amount_g = (color_setting.g * 0.857) / 2;
float randomize_amount_b = (color_setting.b * 0.857) / 2;
r = random(color_setting.r - randomize_amount_r,
std::min(color_setting.r + randomize_amount_r,
1.0));
g = random(color_setting.g - randomize_amount_g,
std::min(color_setting.g + randomize_amount_g,
1.0));
b = random(color_setting.b - randomize_amount_b,
std::min(color_setting.b + randomize_amount_b,
1.0));
} else
{
r = random(0, 1);
g = random(0, 1);
b = random(0, 1);
r = 2 * pow(r, 16);
g = 2 * pow(g, 16);
b = 2 * pow(b, 16);
}
p.color = {r, g, b, 1};
const double cur_pos = bounding_box.height * progress;
p.pos = {random(0, bounding_box.width), random(cur_pos - 10, cur_pos + 10)};
p.start_pos = p.pos;
p.speed = {random(-10, 10), random(-25, 5)};
p.g = {-1, -3};
double size = fire_particle_size;
p.base_radius = p.radius = random(size * 0.8, size * 1.2);
}
std::string stringify() const override
{
return "fire";
}
void gen_render_instances(
std::vector& instances,
wf::scene::damage_callback push_damage,
wf::output_t *output = nullptr) override;
wf::geometry_t get_bounding_box() override
{
static constexpr int left_border = 200;
static constexpr int right_border = 200;
static constexpr int top_border = 200;
static constexpr int bottom_border = 200;
auto view = get_children_bounding_box();
view.x -= left_border;
view.y -= top_border;
view.width += left_border + right_border;
view.height += top_border + bottom_border;
return view;
}
float progress_line;
void set_progress_line(float line)
{
progress_line = line;
}
};
class fire_render_instance_t : public wf::scene::render_instance_t
{
std::shared_ptr self;
public:
fire_render_instance_t(fire_node_t *self,
wf::scene::damage_callback push_damage,
wf::output_t *output)
{
this->self = std::dynamic_pointer_cast(self->shared_from_this());
auto child_damage = [=] (const wf::region_t& damage)
{
push_damage(damage | self->get_bounding_box());
};
for (auto& ch : self->get_children())
{
if (ch->is_enabled())
{
ch->gen_render_instances(children, child_damage, output);
}
}
}
void schedule_instructions(
std::vector& instructions,
const wf::render_target_t& target, wf::region_t& damage) override
{
if (children.empty())
{
return;
}
// Step 2: we render ourselves
auto bbox = self->get_bounding_box();
instructions.push_back(wf::scene::render_instruction_t{
.instance = this,
.target = target,
.damage = damage & bbox,
});
// Step 1: render the view below normally, however, make sure it doesn't
// render above the progress line
bbox = self->get_children_bounding_box();
bbox.height *= self->progress_line;
auto child_damage = damage & bbox;
for (auto& ch : children)
{
ch->schedule_instructions(instructions, target, child_damage);
}
}
void render(const wf::render_target_t& target_fb,
const wf::region_t& region) override
{
OpenGL::render_begin(target_fb);
auto bbox = self->get_children_bounding_box();
auto translate =
glm::translate(glm::mat4(1.0), {bbox.x, bbox.y, 0});
for (auto& box : region)
{
target_fb.logic_scissor(wlr_box_from_pixman_box(box));
self->ps->render(target_fb.get_orthographic_projection() * translate);
}
OpenGL::render_end();
}
void presentation_feedback(wf::output_t *output) override
{
for (auto& ch : children)
{
ch->presentation_feedback(output);
}
}
void compute_visibility(wf::output_t *output, wf::region_t& visible) override
{
for (auto& ch : this->children)
{
ch->compute_visibility(output, visible);
}
}
private:
std::vector children;
};
void fire_node_t::gen_render_instances(
std::vector& instances,
wf::scene::damage_callback push_damage,
wf::output_t *output)
{
instances.push_back(std::make_unique(
this, push_damage, output));
}
static float fire_duration_mod_for_height(int height)
{
return std::min(height / 400.0, 3.0);
}
void FireAnimation::init(wayfire_view view, wf::animation_description_t dur, wf_animation_type type)
{
this->view = view;
auto bbox = view->get_transformed_node()->get_bounding_box();
dur.length_ms *= fire_duration_mod_for_height(bbox.height);
this->progression = wf::animation::simple_animation_t(
wf::create_option(dur));
this->progression.animate(0, 1);
if (type & HIDING_ANIMATION)
{
this->progression.flip();
}
name = "animation-fire-" + std::to_string(type);
auto tr = std::make_shared();
view->get_transformed_node()->add_transformer(
tr, wf::TRANSFORMER_HIGHLEVEL + 1, name);
}
bool FireAnimation::step()
{
auto transformer = view->get_transformed_node()
->get_transformer(name);
transformer->set_progress_line(this->progression);
if (this->progression.running())
{
transformer->ps->spawn(transformer->ps->size() / 10);
}
transformer->ps->update();
transformer->ps->resize(particle_count_for_width(
transformer->get_children_bounding_box().width));
return this->progression.running() || transformer->ps->statistic();
}
void FireAnimation::reverse()
{
this->progression.reverse();
}
FireAnimation::~FireAnimation()
{
view->get_transformed_node()->rem_transformer(name);
}
wayfire-0.9.0/plugins/animate/fire/fire.hpp 0000664 0000000 0000000 00000001313 14662337126 0020660 0 ustar 00root root 0000000 0000000 #ifndef FIRE_ANIMATION_HPP
#define FIRE_ANIMATION_HPP
#include
#include
#include "../animate.hpp"
class FireTransformer;
class ParticleSystem;
class FireAnimation : public animation_base
{
std::string name; // the name of the transformer in the view's table
wayfire_view view;
wf::animation::simple_animation_t progression;
public:
~FireAnimation();
void init(wayfire_view view, wf::animation_description_t, wf_animation_type type) override;
bool step() override; /* return true if continue, false otherwise */
void reverse() override; /* reverse the animation */
};
#endif /* end of include guard: FIRE_ANIMATION_HPP */
wayfire-0.9.0/plugins/animate/fire/particle.cpp 0000664 0000000 0000000 00000010266 14662337126 0021540 0 ustar 00root root 0000000 0000000 #include "particle.hpp"
#include "shaders.hpp"
#include
void Particle::update(float time)
{
if (life <= 0) // ignore
{
return;
}
const float slowdown = 0.8;
pos += speed * 0.2f * slowdown;
speed += g * 0.3f * slowdown;
if (life != 0)
{
color.a /= life;
}
life -= fade * 0.3 * slowdown;
radius = base_radius * std::pow(life, 0.5);
color.a *= life;
if (start_pos.x < pos.x)
{
g.x = -1;
} else
{
g.x = 1;
}
if (life <= 0)
{
/* move outside */
pos = {-10000, -10000};
}
}
ParticleSystem::ParticleSystem(int particles)
{
resize(particles);
last_update_msec = wf::get_current_time();
create_program();
particles_alive.store(0);
}
void ParticleSystem::set_initer(ParticleIniter init)
{
this->pinit_func = init;
}
ParticleSystem::~ParticleSystem()
{
OpenGL::render_begin();
program.free_resources();
OpenGL::render_end();
}
int ParticleSystem::spawn(int num)
{
std::atomic spawned(0);
# pragma omp parallel for
for (size_t i = 0; i < ps.size(); i++)
{
if ((ps[i].life <= 0) && (spawned < num))
{
pinit_func(ps[i]);
++spawned;
++particles_alive;
}
}
return spawned;
}
void ParticleSystem::resize(int num)
{
if (num == (int)ps.size())
{
return;
}
# pragma omp parallel for
for (size_t i = num; i < ps.size(); i++)
{
if (ps[i].life >= 0)
{
--particles_alive;
}
}
ps.resize(num);
color.resize(color_per_particle * num);
dark_color.resize(color_per_particle * num);
radius.resize(radius_per_particle * num);
center.resize(center_per_particle * num);
}
int ParticleSystem::size()
{
return ps.size();
}
void ParticleSystem::update_worker(float time, int i)
{
if (ps[i].life <= 0)
{
return;
}
ps[i].update(time);
if (ps[i].life <= 0)
{
--particles_alive;
}
for (int j = 0; j < 4; j++) // maybe use memcpy?
{
color[4 * i + j] = ps[i].color[j];
dark_color[4 * i + j] = ps[i].color[j] * 0.5;
}
center[2 * i] = ps[i].pos[0];
center[2 * i + 1] = ps[i].pos[1];
radius[i] = ps[i].radius;
}
void ParticleSystem::update()
{
// FIXME: don't hardcode 60FPS
float time = (wf::get_current_time() - last_update_msec) / 16.0;
last_update_msec = wf::get_current_time();
# pragma omp parallel for
for (size_t i = 0; i < ps.size(); i++)
{
update_worker(time, i);
}
}
int ParticleSystem::statistic()
{
return particles_alive;
}
void ParticleSystem::create_program()
{
/* Just load the proper context, viewport doesn't matter */
OpenGL::render_begin();
program.set_simple(OpenGL::compile_program(particle_vert_source,
particle_frag_source));
OpenGL::render_end();
}
void ParticleSystem::render(glm::mat4 matrix)
{
program.use(wf::TEXTURE_TYPE_RGBA);
static float vertex_data[] = {
-1, -1,
1, -1,
1, 1,
-1, 1
};
program.attrib_pointer("position", 2, 0, vertex_data);
program.attrib_divisor("position", 0);
program.attrib_pointer("radius", 1, 0, radius.data());
program.attrib_divisor("radius", 1);
program.attrib_pointer("center", 2, 0, center.data());
program.attrib_divisor("center", 1);
// matrix
program.uniformMatrix4f("matrix", matrix);
/* Darken the background */
program.attrib_pointer("color", 4, 0, dark_color.data());
program.attrib_divisor("color", 1);
GL_CALL(glEnable(GL_BLEND));
GL_CALL(glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA));
program.uniform1f("smoothing", 0.7);
// TODO: optimize shaders for this case
GL_CALL(glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, ps.size()));
// particle color
program.attrib_pointer("color", 4, 0, color.data());
GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE));
program.uniform1f("smoothing", 0.5);
GL_CALL(glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, ps.size()));
GL_CALL(glDisable(GL_BLEND));
GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
program.deactivate();
}
wayfire-0.9.0/plugins/animate/fire/particle.hpp 0000664 0000000 0000000 00000004471 14662337126 0021546 0 ustar 00root root 0000000 0000000 #ifndef ANIMATION_FIRE_PARTICLE_HPP
#define ANIMATION_FIRE_PARTICLE_HPP
#include
#include
#include
#include
struct Particle
{
float life = -1;
float fade;
float radius, base_radius;
glm::vec2 pos{0.0, 0.0}, speed{0.0, 0.0}, g{0.0, 0.0};
glm::vec2 start_pos;
glm::vec4 color{1.0, 1.0, 1.0, 1.0};
/* update the given particle
* time is the percentage of the frame which has elapsed
* must be thread-safe */
void update(float time);
};
/* a function to initialize a particle */
using ParticleIniter = std::function;
class ParticleSystem
{
public:
/* the user of this class has to set up a proper GL context
* before creating the ParticleSystem */
ParticleSystem(int num_part);
~ParticleSystem();
void set_initer(ParticleIniter init);
ParticleSystem(const ParticleSystem &) = delete;
ParticleSystem(ParticleSystem &&) = delete;
ParticleSystem& operator =(const ParticleSystem&) = delete;
ParticleSystem& operator =(ParticleSystem&&) = delete;
/* spawn at most num new particles.
* returns the number of actually spawned particles */
int spawn(int num);
/* change the maximal number of particles
* Warning: This might kill a lot of particles */
void resize(int num);
// return the maximal number of particles
int size();
/* update all particles */
void update();
// number of particles alive
int statistic();
/* render particles, each will be multiplied by matrix
* The user of this class has to set up the same GL context that was
* used during the creation of the particle system */
void render(glm::mat4 matrix);
private:
ParticleSystem() = delete;
ParticleIniter pinit_func = [] (auto) {};
uint32_t last_update_msec;
std::atomic particles_alive;
std::vector ps;
static constexpr int color_per_particle = 4;
std::vector color, dark_color;
static constexpr int radius_per_particle = 1;
std::vector radius;
static constexpr int center_per_particle = 2;
std::vector center;
OpenGL::program_t program;
void update_worker(float time, int i);
void create_program();
};
#endif /* end of include guard: ANIMATION_FIRE_PARTICLE_HPP */
wayfire-0.9.0/plugins/animate/fire/shaders.hpp 0000664 0000000 0000000 00000002047 14662337126 0021371 0 ustar 00root root 0000000 0000000 #ifndef PARTICLE_ANIMATION_SHADER
#define PARTICLE_ANIMATION_SHADER
static const char *particle_vert_source =
R"(
#version 100
attribute mediump float radius;
attribute mediump vec2 position;
attribute mediump vec2 center;
attribute mediump vec4 color;
uniform mat4 matrix;
varying mediump vec2 uv;
varying mediump vec4 out_color;
varying mediump float R;
void main() {
uv = position * radius;
gl_Position = matrix * vec4(center.x + uv.x * 0.75, center.y + uv.y, 0.0, 1.0);
R = radius;
out_color = color;
}
)";
static const char *particle_frag_source =
R"(
#version 100
varying mediump vec2 uv;
varying mediump vec4 out_color;
varying mediump float R;
uniform mediump float smoothing;
void main()
{
mediump float len = length(uv);
if (len >= R)
{
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
}
else {
mediump float factor = 1.0 - len / R;
factor = pow(factor, smoothing);
gl_FragColor = factor * out_color;
}
}
)";
#endif /* end of include guard: PARTICLE_ANIMATION_SHADER */
wayfire-0.9.0/plugins/animate/meson.build 0000664 0000000 0000000 00000001047 14662337126 0020443 0 ustar 00root root 0000000 0000000 dependencies = [wlroots, pixman, wfconfig]
if get_option('enable_openmp')
dependencies += [dependency('openmp')]
endif
animiate = shared_module('animate',
['animate.cpp',
'fire/particle.cpp',
'fire/fire.cpp'],
include_directories: [wayfire_api_inc, wayfire_conf_inc],
dependencies: dependencies,
install: true,
install_dir: join_paths(get_option('libdir'), 'wayfire'))
wayfire-0.9.0/plugins/animate/shaders/ 0000775 0000000 0000000 00000000000 14662337126 0017730 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/plugins/animate/shaders/frag.glsl 0000664 0000000 0000000 00000000654 14662337126 0021537 0 ustar 00root root 0000000 0000000 #version 310 es
in mediump vec4 out_color;
in mediump vec2 pos;
out mediump vec4 fragColor;
layout(location = 4) uniform highp float radii;
void main()
{
mediump float dist_center = sqrt(pos.x * pos.x + pos.y * pos.y);
mediump float factor = (radii - dist_center) / radii;
if (factor < 0.0) factor = 0.0;
mediump float factor2 = factor * factor;
fragColor = vec4(out_color.xyz, out_color.w * factor2);
}
wayfire-0.9.0/plugins/animate/shaders/vertex.glsl 0000664 0000000 0000000 00000000607 14662337126 0022133 0 ustar 00root root 0000000 0000000 #version 310 es
layout(location = 0) in mediump vec2 position;
layout(location = 1) in mediump vec2 center;
layout(location = 2) in mediump vec4 color;
layout(location = 3) uniform mediump vec2 global_offset;
out mediump vec4 out_color;
out mediump vec2 pos;
void main() {
gl_Position = vec4 (position + center + global_offset, 0.0, 1.0);
out_color = color;
pos = position;
}
wayfire-0.9.0/plugins/animate/system_fade.hpp 0000664 0000000 0000000 00000003146 14662337126 0021317 0 ustar 00root root 0000000 0000000 #ifndef SYSTEM_FADE_HPP
#define SYSTEM_FADE_HPP
#include
#include
#include
#include
#include
/* animates wake from suspend/startup by fading in the whole output */
class wf_system_fade
{
wf::animation::simple_animation_t progression;
wf::output_t *output;
wf::effect_hook_t damage_hook, render_hook;
public:
wf_system_fade(wf::output_t *out, wf::animation_description_t dur) :
progression(wf::create_option(dur)), output(out)
{
damage_hook = [=] ()
{ output->render->damage_whole(); };
render_hook = [=] ()
{ render(); };
output->render->add_effect(&damage_hook, wf::OUTPUT_EFFECT_PRE);
output->render->add_effect(&render_hook, wf::OUTPUT_EFFECT_OVERLAY);
output->render->set_redraw_always();
this->progression.animate(1, 0);
}
void render()
{
wf::color_t color{0, 0, 0, this->progression};
auto fb = output->render->get_target_framebuffer();
auto geometry = output->get_relative_geometry();
OpenGL::render_begin(fb);
OpenGL::render_rectangle(geometry, color,
fb.get_orthographic_projection());
OpenGL::render_end();
if (!progression.running())
{
finish();
}
}
void finish()
{
output->render->rem_effect(&damage_hook);
output->render->rem_effect(&render_hook);
output->render->set_redraw_always(false);
delete this;
}
};
#endif
wayfire-0.9.0/plugins/animate/unmapped-view-node.hpp 0000664 0000000 0000000 00000003132 14662337126 0022513 0 ustar 00root root 0000000 0000000 #pragma once
#include "wayfire/geometry.hpp"
#include "wayfire/opengl.hpp"
#include "wayfire/region.hpp"
#include "wayfire/scene-render.hpp"
#include "wayfire/scene.hpp"
#include
namespace wf
{
class unmapped_view_snapshot_node : public wf::scene::node_t
{
wf::render_target_t snapshot;
wf::geometry_t bbox;
public:
unmapped_view_snapshot_node(wayfire_view view) : node_t(false)
{
view->take_snapshot(snapshot);
bbox = view->get_surface_root_node()->get_bounding_box();
}
~unmapped_view_snapshot_node()
{
OpenGL::render_begin();
snapshot.release();
OpenGL::render_end();
}
wf::geometry_t get_bounding_box() override
{
return bbox;
}
void gen_render_instances(std::vector& instances,
scene::damage_callback push_damage, wf::output_t *shown_on) override
{
instances.push_back(std::make_unique(this, push_damage, shown_on));
}
private:
class rinstance_t : public wf::scene::simple_render_instance_t
{
public:
using simple_render_instance_t::simple_render_instance_t;
void render(const wf::render_target_t& target, const wf::region_t& region)
{
OpenGL::render_begin(target);
for (auto& box : region)
{
target.logic_scissor(wlr_box_from_pixman_box(box));
OpenGL::render_texture(self->snapshot.tex, target, self->get_bounding_box());
}
OpenGL::render_end();
}
};
};
}
wayfire-0.9.0/plugins/blur/ 0000775 0000000 0000000 00000000000 14662337126 0015625 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/plugins/blur/blur-base.cpp 0000664 0000000 0000000 00000024062 14662337126 0020211 0 ustar 00root root 0000000 0000000 #include "blur.hpp"
#include "wayfire/core.hpp"
#include "wayfire/geometry.hpp"
#include "wayfire/region.hpp"
#include "wayfire/scene-render.hpp"
#include
#include
#include
#include
static const char *blur_blend_vertex_shader =
R"(
#version 100
attribute mediump vec2 position;
attribute mediump vec2 uv_in;
varying mediump vec2 uvpos[2];
uniform mat4 mvp;
uniform mat4 background_uv_matrix;
void main() {
gl_Position = mvp * vec4(position, 0.0, 1.0);
uvpos[0] = uv_in;
uvpos[1] = vec4(background_uv_matrix * vec4(uv_in - 0.5, 0.0, 1.0)).xy + 0.5;
})";
static const char *blur_blend_fragment_shader =
R"(
#version 100
@builtin_ext@
precision mediump float;
@builtin@
uniform float sat;
uniform sampler2D bg_texture;
varying mediump vec2 uvpos[2];
vec3 saturation(vec3 rgb, float adjustment)
{
// Algorithm from Chapter 16 of OpenGL Shading Language
const vec3 w = vec3(0.2125, 0.7154, 0.0721);
vec3 intensity = vec3(dot(rgb, w));
return mix(intensity, rgb, adjustment);
}
void main()
{
vec4 bp = texture2D(bg_texture, uvpos[1]);
bp = vec4(saturation(bp.rgb, sat), bp.a);
vec4 wp = get_pixel(uvpos[0]);
vec4 c = clamp(4.0 * wp.a, 0.0, 1.0) * bp;
gl_FragColor = wp + (1.0 - wp.a) * c;
})";
wf_blur_base::wf_blur_base(std::string name)
{
this->algorithm_name = name;
this->saturation_opt.load_option("blur/saturation");
this->offset_opt.load_option("blur/" + algorithm_name + "_offset");
this->degrade_opt.load_option("blur/" + algorithm_name + "_degrade");
this->iterations_opt.load_option("blur/" + algorithm_name + "_iterations");
this->options_changed = [=] ()
{
wf::scene::damage_node(wf::get_core().scene(), wf::get_core().scene()->get_bounding_box());
};
this->saturation_opt.set_callback(options_changed);
this->offset_opt.set_callback(options_changed);
this->degrade_opt.set_callback(options_changed);
this->iterations_opt.set_callback(options_changed);
OpenGL::render_begin();
blend_program.compile(blur_blend_vertex_shader, blur_blend_fragment_shader);
OpenGL::render_end();
}
wf_blur_base::~wf_blur_base()
{
OpenGL::render_begin();
fb[0].release();
fb[1].release();
program[0].free_resources();
program[1].free_resources();
blend_program.free_resources();
OpenGL::render_end();
}
int wf_blur_base::calculate_blur_radius()
{
return offset_opt * degrade_opt * std::max(1, (int)iterations_opt);
}
void wf_blur_base::render_iteration(wf::region_t blur_region,
wf::framebuffer_t& in, wf::framebuffer_t& out,
int width, int height)
{
/* Special case for small regions where we can't really blur, because we
* simply have too few pixels */
width = std::max(width, 1);
height = std::max(height, 1);
out.allocate(width, height);
out.bind();
GL_CALL(glBindTexture(GL_TEXTURE_2D, in.tex));
for (auto& b : blur_region)
{
out.scissor(wlr_box_from_pixman_box(b));
GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
}
}
/** @return Smallest integer >= x which is divisible by mod */
static int round_up(int x, int mod)
{
return mod * int((x + mod - 1) / mod);
}
/**
* Calculate the smallest box which contains @box and whose x, y, width, height
* are divisible by @degrade, and clamp that box to @bounds.
*/
static wf::geometry_t sanitize(wf::geometry_t box, int degrade,
wf::geometry_t bounds)
{
wf::geometry_t out_box;
out_box.x = degrade * int(box.x / degrade);
out_box.y = degrade * int(box.y / degrade);
out_box.width = round_up(box.width, degrade);
out_box.height = round_up(box.height, degrade);
if (out_box.x + out_box.width < box.x + box.width)
{
out_box.width += degrade;
}
if (out_box.y + out_box.height < box.y + box.height)
{
out_box.height += degrade;
}
return wf::clamp(out_box, bounds);
}
wlr_box wf_blur_base::copy_region(wf::framebuffer_t& result,
const wf::render_target_t& source, const wf::region_t& region)
{
auto subbox = source.framebuffer_box_from_geometry_box(
wlr_box_from_pixman_box(region.get_extents()));
auto source_box =
source.framebuffer_box_from_geometry_box(source.geometry);
// Make sure that the box is aligned properly for degrading, otherwise,
// we get a flickering
subbox = sanitize(subbox, degrade_opt, source_box);
int degraded_width = subbox.width / degrade_opt;
int degraded_height = subbox.height / degrade_opt;
OpenGL::render_begin(source);
result.allocate(degraded_width, degraded_height);
GL_CALL(glBindFramebuffer(GL_READ_FRAMEBUFFER, source.fb));
GL_CALL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, result.fb));
GL_CALL(glBlitFramebuffer(
subbox.x, source.viewport_height - subbox.y - subbox.height,
subbox.x + subbox.width, source.viewport_height - subbox.y,
0, 0, degraded_width, degraded_height,
GL_COLOR_BUFFER_BIT, GL_LINEAR));
OpenGL::render_end();
return subbox;
}
void wf_blur_base::prepare_blur(const wf::render_target_t& target_fb, const wf::region_t& damage)
{
if (damage.empty())
{
return;
}
int degrade = degrade_opt;
auto damage_box = copy_region(fb[0], target_fb, damage);
/* As an optimization, we create a region that blur can use
* to perform minimal rendering required to blur. We start
* by translating the input damage region */
wf::region_t blur_damage;
for (auto b : damage)
{
blur_damage |= target_fb.framebuffer_box_from_geometry_box(
wlr_box_from_pixman_box(b));
}
/* Scale and translate the region */
blur_damage += -wf::point_t{damage_box.x, damage_box.y};
blur_damage *= 1.0 / degrade;
int r = blur_fb0(blur_damage, fb[0].viewport_width, fb[0].viewport_height);
/* Make sure the result is always fb[0], because that's what is used in render()
* */
if (r != 0)
{
std::swap(fb[0], fb[1]);
}
prepared_geometry = damage_box;
}
static wf::pointf_t get_center(wf::geometry_t g)
{
return {g.x + g.width / 2.0, g.y + g.height / 2.0};
}
void wf_blur_base::render(wf::texture_t src_tex, wlr_box src_box, const wf::region_t& damage,
const wf::render_target_t& background_source_fb, const wf::render_target_t& target_fb)
{
OpenGL::render_begin(target_fb);
blend_program.use(src_tex.type);
/* Use shader and enable vertex and texcoord data */
static const float vertex_data_uv[] = {
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
};
const float vertex_data_pos[] = {
1.0f * src_box.x, 1.0f * src_box.y + src_box.height,
1.0f * src_box.x + src_box.width, 1.0f * src_box.y + src_box.height,
1.0f * src_box.x + src_box.width, 1.0f * src_box.y,
1.0f * src_box.x, 1.0f * src_box.y,
};
blend_program.attrib_pointer("position", 2, 0, vertex_data_pos);
blend_program.attrib_pointer("uv_in", 2, 0, vertex_data_uv);
// The blurred background is contained in a framebuffer with dimensions equal to the projected damage.
// We need to calculate a mapping between the uv coordinates of the view (which may be bigger than the
// damage) and the uv coordinates used for sampling the blurred background.
// How it works:
// 1. translate UV coordinates to (-0.5, -0.5) ~ (0.5, 0.5) range
// 2. apply inverse framebuffer transform (needed because on rotated outputs, the framebuffer box includes
// rotation).
// 3. Scale to match the view size
// 4. Translate to match the view
auto view_box = background_source_fb.framebuffer_box_from_geometry_box(src_box); // Projected view
auto blurred_box = prepared_geometry;
// prepared_geometry is the projected damage bounding box
glm::mat4 fb_fix = target_fb.transform;
const auto scale_x = 1.0 * view_box.width / blurred_box.width;
const auto scale_y = 1.0 * view_box.height / blurred_box.height;
glm::mat4 scale = glm::scale(glm::mat4(1.0), glm::vec3{scale_x, scale_y, 1.0});
const wf::pointf_t center_view = get_center(view_box);
const wf::pointf_t center_prepared = get_center(blurred_box);
const auto translate_x = 1.0 * (center_view.x - center_prepared.x) / view_box.width;
const auto translate_y = -1.0 * (center_view.y - center_prepared.y) / view_box.height;
glm::mat4 fix_center = glm::translate(glm::mat4(1.0), glm::vec3{translate_x, translate_y, 0.0});
glm::mat4 composite = scale * fix_center * fb_fix;
blend_program.uniformMatrix4f("background_uv_matrix", composite);
/* Blend blurred background with window texture src_tex */
blend_program.uniformMatrix4f("mvp", target_fb.get_orthographic_projection());
/* XXX: core should give us the number of texture units used */
blend_program.uniform1i("bg_texture", 1);
blend_program.uniform1f("sat", saturation_opt);
blend_program.set_active_texture(src_tex);
GL_CALL(glActiveTexture(GL_TEXTURE0 + 1));
GL_CALL(glBindTexture(GL_TEXTURE_2D, fb[0].tex));
/* Render it to target_fb */
target_fb.bind();
for (const auto& box : damage)
{
target_fb.logic_scissor(wlr_box_from_pixman_box(box));
GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
}
/*
* Disable stuff
* GL_CALL(glActiveTexture(GL_TEXTURE0 + 1));
*/
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
GL_CALL(glActiveTexture(GL_TEXTURE0));
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
blend_program.deactivate();
OpenGL::render_end();
}
std::unique_ptr create_blur_from_name(std::string algorithm_name)
{
if (algorithm_name == "box")
{
return create_box_blur();
}
if (algorithm_name == "bokeh")
{
return create_bokeh_blur();
}
if (algorithm_name == "kawase")
{
return create_kawase_blur();
}
if (algorithm_name == "gaussian")
{
return create_gaussian_blur();
}
LOGE("Unrecognized blur algorithm %s. Using default kawase blur.", algorithm_name.c_str());
return create_kawase_blur();
}
wayfire-0.9.0/plugins/blur/blur.cpp 0000664 0000000 0000000 00000030377 14662337126 0017307 0 ustar 00root root 0000000 0000000 #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "blur.hpp"
#include "wayfire/core.hpp"
#include "wayfire/debug.hpp"
#include "wayfire/geometry.hpp"
#include "wayfire/opengl.hpp"
#include "wayfire/region.hpp"
#include "wayfire/scene-render.hpp"
#include "wayfire/scene.hpp"
#include "wayfire/signal-provider.hpp"
using blur_algorithm_provider =
std::function()>;
static int calculate_damage_padding(const wf::render_target_t& target, int blur_radius)
{
float scale = target.scale;
if (target.subbuffer)
{
const float subbox_scale_x = 1.0 * target.subbuffer->width / target.geometry.width;
const float subbox_scale_y = 1.0 * target.subbuffer->height / target.geometry.height;
scale *= std::max(subbox_scale_x, subbox_scale_y);
}
return std::ceil(blur_radius / scale);
}
namespace wf
{
namespace scene
{
class blur_node_t : public transformer_base_node_t
{
public:
blur_algorithm_provider provider;
blur_node_t(blur_algorithm_provider provider) : transformer_base_node_t(false)
{
this->provider = provider;
}
~blur_node_t()
{
OpenGL::render_begin();
for (auto& buffer : saved_pixels)
{
buffer.pixels.release();
}
OpenGL::render_end();
}
std::string stringify() const override
{
return "blur";
}
void gen_render_instances(std::vector& instances,
damage_callback push_damage, wf::output_t *shown_on) override;
struct saved_pixels_t
{
wf::framebuffer_t pixels;
wf::region_t region;
bool taken = false;
};
std::list saved_pixels;
saved_pixels_t *acquire_saved_pixel_buffer()
{
auto it = std::find_if(saved_pixels.begin(), saved_pixels.end(),
[] (const saved_pixels_t& buffer) { return !buffer.taken; });
if (it != saved_pixels.end())
{
it->taken = true;
return &(*it);
}
saved_pixels.emplace_back();
saved_pixels.back().taken = true;
return &saved_pixels.back();
}
void release_saved_pixel_buffer(saved_pixels_t *buffer)
{
buffer->taken = false;
}
};
class blur_render_instance_t : public transformer_render_instance_t
{
blur_node_t::saved_pixels_t *saved_pixels = nullptr;
public:
using transformer_render_instance_t::transformer_render_instance_t;
bool is_fully_opaque(wf::region_t damage)
{
if (self->get_children().size() == 1)
{
if (auto opaque = dynamic_cast(self->get_children().front().get()))
{
return (damage ^ opaque->get_opaque_region()).empty();
}
}
return false;
}
wf::region_t calculate_translucent_damage(const wf::render_target_t& target, wf::region_t damage)
{
if (self->get_children().size() == 1)
{
if (auto opaque = dynamic_cast(self->get_children().front().get()))
{
const int padding =
calculate_damage_padding(target, self->provider()->calculate_blur_radius());
auto opaque_region = opaque->get_opaque_region();
opaque_region.expand_edges(-padding);
wf::region_t translucent_region = damage ^ opaque_region;
return translucent_region;
}
}
return damage;
}
void schedule_instructions(std::vector& instructions,
const wf::render_target_t& target, wf::region_t& damage) override
{
const int padding = calculate_damage_padding(target, self->provider()->calculate_blur_radius());
auto bbox = self->get_bounding_box();
// In order to render a part of the blurred background, we need to sample
// from area which is larger than the damaged area. However, the edges
// of the expanded area suffer from the same problem (e.g. the blurred
// background has artifacts). The solution to this is to expand the
// damage and keep a copy of the pixels where we redraw, but wouldn't
// have redrawn if not for blur. After that, we copy those old areas
// back to the destination framebuffer, giving the illusion that they
// were never damaged.
auto padded_region = damage & bbox;
if (is_fully_opaque(padded_region & target.geometry))
{
// If there are no regions to blur, we can directly render them.
for (auto& ch : this->children)
{
ch->schedule_instructions(instructions, target, damage);
}
return;
}
padded_region.expand_edges(padding);
padded_region &= bbox;
// Don't forget to keep expanded damage within the bounds of the render
// target, otherwise we may be sampling from outside of it (undefined
// contents).
padded_region &= target.geometry;
// Actual region which will be repainted by this render instance.
wf::region_t we_repaint = padded_region;
this->saved_pixels = self->acquire_saved_pixel_buffer();
saved_pixels->region =
target.framebuffer_region_from_geometry_region(padded_region) ^
target.framebuffer_region_from_geometry_region(damage);
// Nodes below should re-render the padded areas so that we can sample from them
damage |= padded_region;
OpenGL::render_begin();
saved_pixels->pixels.allocate(target.viewport_width, target.viewport_height);
saved_pixels->pixels.bind();
GL_CALL(glBindFramebuffer(GL_READ_FRAMEBUFFER, target.fb));
/* Copy pixels in padded_region from target_fb to saved_pixels. */
for (const auto& box : saved_pixels->region)
{
GL_CALL(glBlitFramebuffer(
box.x1, target.viewport_height - box.y2,
box.x2, target.viewport_height - box.y1,
box.x1, box.y1, box.x2, box.y2,
GL_COLOR_BUFFER_BIT, GL_LINEAR));
}
OpenGL::render_end();
instructions.push_back(render_instruction_t{
.instance = this,
.target = target,
.damage = we_repaint,
});
}
void render(const wf::render_target_t& target, const wf::region_t& damage) override
{
auto tex = get_texture(target.scale);
auto bounding_box = self->get_bounding_box();
if (!damage.empty())
{
auto translucent_damage = calculate_translucent_damage(target, damage);
self->provider()->prepare_blur(target, translucent_damage);
self->provider()->render(tex, bounding_box, damage, target, target);
}
OpenGL::render_begin(target);
// Setup framebuffer I/O. target_fb contains the frame
// rendered with expanded damage and artifacts on the edges.
// saved_pixels has the the padded region of pixels to overwrite the
// artifacts that blurring has left behind.
GL_CALL(glBindFramebuffer(GL_READ_FRAMEBUFFER, saved_pixels->pixels.fb));
/* Copy pixels back from saved_pixels to target_fb. */
for (const auto& box : saved_pixels->region)
{
GL_CALL(glBlitFramebuffer(
box.x1, box.y1, box.x2, box.y2,
box.x1, target.viewport_height - box.y2,
box.x2, target.viewport_height - box.y1,
GL_COLOR_BUFFER_BIT, GL_LINEAR));
}
/* Reset stuff */
saved_pixels->region.clear();
self->release_saved_pixel_buffer(saved_pixels);
saved_pixels = NULL;
OpenGL::render_end();
}
direct_scanout try_scanout(wf::output_t *output) override
{
// Enable direct scanout if it is possible
return scene::try_scanout_from_list(children, output);
}
};
void blur_node_t::gen_render_instances(std::vector& instances,
damage_callback push_damage, wf::output_t *shown_on)
{
auto uptr =
std::make_unique(this, push_damage, shown_on);
if (uptr->has_instances())
{
instances.push_back(std::move(uptr));
}
}
}
}
class wayfire_blur : public wf::plugin_interface_t
{
// Before doing a render pass, expand the damage by the blur radius.
// This is needed, because when blurring, the pixels that changed
// affect a larger area than the really damaged region, e.g. the region
// that comes from client damage.
wf::signal::connection_t
on_render_pass_begin = [=] (wf::scene::render_pass_begin_signal *ev)
{
if (!provider)
{
return;
}
const int padding = calculate_damage_padding(ev->target, provider()->calculate_blur_radius());
ev->damage.expand_edges(padding);
ev->damage &= ev->target.geometry;
};
public:
blur_algorithm_provider provider;
wf::button_callback button_toggle;
wf::signal::connection_t on_view_mapped = [=] (wf::view_mapped_signal *ev)
{
if (blur_by_default.matches(ev->view))
{
add_transformer(ev->view);
}
};
wf::view_matcher_t blur_by_default{"blur/blur_by_default"};
wf::option_wrapper_t method_opt{"blur/method"};
wf::option_wrapper_t toggle_button{"blur/toggle"};
wf::config::option_base_t::updated_callback_t blur_method_changed;
std::unique_ptr blur_algorithm;
void add_transformer(wayfire_view view)
{
auto tmanager = view->get_transformed_node();
if (tmanager->get_transformer())
{
return;
}
auto provider = [=] ()
{
return blur_algorithm.get();
};
auto node = std::make_shared(provider);
tmanager->add_transformer(node, wf::TRANSFORMER_BLUR);
}
void pop_transformer(wayfire_view view)
{
auto tmanager = view->get_transformed_node();
tmanager->rem_transformer();
}
void remove_transformers()
{
for (auto& view : wf::get_core().get_all_views())
{
pop_transformer(view);
}
}
public:
void init() override
{
wf::get_core().connect(&on_render_pass_begin);
blur_method_changed = [=] ()
{
blur_algorithm = create_blur_from_name(method_opt);
wf::scene::damage_node(wf::get_core().scene(), wf::get_core().scene()->get_bounding_box());
};
/* Create initial blur algorithm */
blur_method_changed();
method_opt.set_callback(blur_method_changed);
/* Toggles the blur state of the view the user clicked on */
button_toggle = [=] (auto)
{
auto view = wf::get_core().get_cursor_focus_view();
if (!view)
{
return false;
}
if (view->get_transformed_node()->get_transformer())
{
pop_transformer(view);
} else
{
add_transformer(view);
}
return true;
};
wf::get_core().bindings->add_button(toggle_button, &button_toggle);
provider = [=] () { return this->blur_algorithm.get(); };
wf::get_core().connect(&on_view_mapped);
for (auto& view : wf::get_core().get_all_views())
{
if (blur_by_default.matches(view))
{
add_transformer(view);
}
}
}
void fini() override
{
remove_transformers();
wf::get_core().bindings->rem_binding(&button_toggle);
/* Call blur algorithm destructor */
blur_algorithm = nullptr;
}
};
DECLARE_WAYFIRE_PLUGIN(wayfire_blur);
wayfire-0.9.0/plugins/blur/blur.hpp 0000664 0000000 0000000 00000017467 14662337126 0017321 0 ustar 00root root 0000000 0000000 #pragma once
#include "wayfire/geometry.hpp"
#include
#include
#include
#include
/* The MIT License (MIT)
*
* Copyright (c) 2018 Ilia Bozhinov
* Copyright (c) 2018 Scott Moreau
*
* The design of blur takes extra consideration due to the fact that
* the results of blurred pixels rely on surrounding pixel values.
* This means that when damage happens for only part of the scene (1),
* blurring this area can result to artifacts because of sampling
* beyond the edges of the area. To work around this issue, wayfire
* issues two signals - workspace-stream-pre and workspace-stream-post.
* workspace-stream-pre gives plugins an opportunity to pad the rects
* of the damage region (2) and save a snap-shot of the padded area from
* the buffer containing the last frame. This will be used to redraw
* the area that will contain artifacts after rendering. This is ok
* because this area is outside of the original damage area, so the
* pixels won't be changing in this region of the scene. pre_render is
* called with the padded damage region as an argument (2). The padded
* damage extents (3) are used for blitting from the framebuffer, which
* contains the scene rendered up until the view for which pre_render
* is called. The padded damage extents rect is blurred with artifacts
* in pre_render, after which it is then alpha blended with the window
* and rendered to the framebuffer. Finally, workspace-stream-post
* allows a chance to redraw the padded area with the saved pixels,
* before swapping buffers. As long as the padding is enough to cover
* the maximum sample offset that the shader uses, there should be a
* seamless experience.
*
* 1)
* .................................................................
* | |
* | |
* | .................................. |
* | | |.. |
* | | | | |
* | | Damage region | | |
* | | | | |
* | | | | |
* | | | | |
* | | | | |
* | ```|```````````````````````````````| |
* | ````````````````````````````````` |
* | |
* | |
* `````````````````````````````````````````````````````````````````
*
* 2)
* .................................................................
* | |
* | ...................................... |
* | | .................................. |..<-- Padding |
* | | | |.. | |
* | | | | | | |
* | | | Padded | | | |
* | | | Damage region | | | |
* | | | | | | |
* | | | | | | |
* | | | | | | |
* | | | | | | |
* | | ```|```````````````````````````````| | |
* | ```| ````````````````````````````````` |<-- Padding |
* | ````````````````````````````````````` |
* `````````````````````````````````````````````````````````````````
*
* 3)
* .................................................................
* | |
* | x1| |x2 |
* | y1__ ...................................... . |
* | | |.. |
* | | | |
* | | ^ | |
* | | | |
* | | <- Padded extents -> | |
* | | | |
* | | v | |
* | | | |
* | y2__ ```| | |
* | ` ````````````````````````````````````` |
* | |
* `````````````````````````````````````````````````````````````````
*/
class wf_blur_base
{
protected:
/* used to store temporary results in blur algorithms, cleaned up in base
* destructor */
wf::framebuffer_t fb[2];
wf::geometry_t prepared_geometry;
/* the program created by the given algorithm, cleaned up in base destructor */
OpenGL::program_t program[2];
/* the program used by wf_blur_base to combine the blurred, unblurred and
* view texture */
OpenGL::program_t blend_program;
/* used to get individual algorithm options from config
* should be set by the constructor */
std::string algorithm_name;
wf::option_wrapper_t saturation_opt;
wf::option_wrapper_t offset_opt;
wf::option_wrapper_t degrade_opt, iterations_opt;
wf::config::option_base_t::updated_callback_t options_changed;
/* renders the in texture to the out framebuffer.
* assumes a properly bound and initialized GL program */
void render_iteration(wf::region_t blur_region,
wf::framebuffer_t& in, wf::framebuffer_t& out,
int width, int height);
/* copy the source pixels from region, storing into result
* returns the result geometry, in framebuffer coords */
wlr_box copy_region(wf::framebuffer_t& result,
const wf::render_target_t& source, const wf::region_t& region);
/* blur fb[0]
* width and height are the scaled dimensions of the buffer
* returns the index of the fb where the result is stored (0 or 1) */
virtual int blur_fb0(const wf::region_t& blur_region, int width, int height) = 0;
public:
wf_blur_base(std::string name);
virtual ~wf_blur_base();
virtual int calculate_blur_radius();
/**
* Calculate the blurred background region.
*
* @param target_fb A render target containing the background to be blurred.
* @param damage The region to be blurred.
*/
void prepare_blur(const wf::render_target_t& target_fb, const wf::region_t& damage);
/**
* Render a view with a blended background as prepared from @prepare_blur.
*
* @param src_tex The texture of the view to render.
* @param src_box The geometry of the view in framebuffer logical coordinates.
* @param damage The region to repaint, in logical coordinates.
* @param background_source_fb The framebuffer used to prepare the background blur.
* @param target_fb The target to draw to.
*/
void render(wf::texture_t src_tex, wlr_box src_box, const wf::region_t& damage,
const wf::render_target_t& background_source_fb, const wf::render_target_t& target_fb);
};
std::unique_ptr create_box_blur();
std::unique_ptr create_bokeh_blur();
std::unique_ptr create_kawase_blur();
std::unique_ptr create_gaussian_blur();
std::unique_ptr create_blur_from_name(std::string algorithm_name);
wayfire-0.9.0/plugins/blur/bokeh.cpp 0000664 0000000 0000000 00000005336 14662337126 0017430 0 ustar 00root root 0000000 0000000 #include "blur.hpp"
static const char *bokeh_vertex_shader =
R"(
#version 100
attribute mediump vec2 position;
varying mediump vec2 uv;
void main() {
gl_Position = vec4(position.xy, 0.0, 1.0);
uv = (position.xy + vec2(1.0, 1.0)) / 2.0;
}
)";
static const char *bokeh_fragment_shader =
R"(
#version 100
precision mediump float;
uniform float offset;
uniform int iterations;
uniform vec2 halfpixel;
uniform int mode;
uniform sampler2D bg_texture;
varying mediump vec2 uv;
#define GOLDEN_ANGLE 2.39996
mat2 rot = mat2(cos(GOLDEN_ANGLE), sin(GOLDEN_ANGLE), -sin(GOLDEN_ANGLE), cos(GOLDEN_ANGLE));
void main()
{
float radius = offset;
vec4 acc = vec4(0), div = acc;
float r = 1.0;
vec2 vangle = vec2(radius / sqrt(float(iterations)), radius / sqrt(float(iterations)));
for (int j = 0; j < iterations; j++)
{
r += 1.0 / r;
vangle = rot * vangle;
vec4 col = texture2D(bg_texture, uv + (r - 1.0) * vangle * halfpixel * 2.0);
vec4 bokeh = pow(col, vec4(4.0));
acc += col * bokeh;
div += bokeh;
}
if (iterations == 0)
gl_FragColor = texture2D(bg_texture, uv);
else
gl_FragColor = acc / div;
}
)";
class wf_bokeh_blur : public wf_blur_base
{
public:
wf_bokeh_blur() : wf_blur_base("bokeh")
{
OpenGL::render_begin();
program[0].set_simple(OpenGL::compile_program(bokeh_vertex_shader,
bokeh_fragment_shader));
OpenGL::render_end();
}
int blur_fb0(const wf::region_t& blur_region, int width, int height) override
{
int iterations = iterations_opt;
float offset = offset_opt;
static const float vertexData[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, 1.0f
};
OpenGL::render_begin();
/* Upload data to shader */
program[0].use(wf::TEXTURE_TYPE_RGBA);
program[0].uniform2f("halfpixel", 0.5f / width, 0.5f / height);
program[0].uniform1f("offset", offset);
program[0].uniform1i("iterations", iterations);
program[0].attrib_pointer("position", 2, 0, vertexData);
GL_CALL(glDisable(GL_BLEND));
render_iteration(blur_region, fb[0], fb[1], width, height);
/* Reset gl state */
GL_CALL(glEnable(GL_BLEND));
GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
program[0].deactivate();
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
OpenGL::render_end();
return 1;
}
int calculate_blur_radius() override
{
return 5 * wf_blur_base::offset_opt*wf_blur_base::degrade_opt;
}
};
std::unique_ptr create_bokeh_blur()
{
return std::make_unique();
}
wayfire-0.9.0/plugins/blur/box.cpp 0000664 0000000 0000000 00000007122 14662337126 0017123 0 ustar 00root root 0000000 0000000 #include "blur.hpp"
static const char *box_vertex_shader =
R"(
#version 100
attribute mediump vec2 position;
uniform vec2 size;
uniform float offset;
varying highp vec2 blurcoord[5];
void main() {
gl_Position = vec4(position.xy, 0.0, 1.0);
vec2 texcoord = (position.xy + vec2(1.0, 1.0)) / 2.0;
blurcoord[0] = texcoord;
blurcoord[1] = texcoord + vec2(1.5 * offset) / size;
blurcoord[2] = texcoord - vec2(1.5 * offset) / size;
blurcoord[3] = texcoord + vec2(3.5 * offset) / size;
blurcoord[4] = texcoord - vec2(3.5 * offset) / size;
}
)";
static const char *box_fragment_shader_horz =
R"(
#version 100
precision mediump float;
uniform sampler2D bg_texture;
uniform int mode;
varying highp vec2 blurcoord[5];
void main()
{
vec2 uv = blurcoord[0];
vec4 bp = vec4(0.0);
for(int i = 0; i < 5; i++) {
vec2 uv = vec2(blurcoord[i].x, uv.y);
bp += texture2D(bg_texture, uv);
}
gl_FragColor = bp / 5.0;
}
)";
static const char *box_fragment_shader_vert =
R"(
#version 100
precision mediump float;
uniform sampler2D bg_texture;
uniform int mode;
varying highp vec2 blurcoord[5];
void main()
{
vec2 uv = blurcoord[0];
vec4 bp = vec4(0.0);
for(int i = 0; i < 5; i++) {
vec2 uv = vec2(uv.x, blurcoord[i].y);
bp += texture2D(bg_texture, uv);
}
gl_FragColor = bp / 5.0;
}
)";
class wf_box_blur : public wf_blur_base
{
public:
void get_id_locations(int i)
{}
wf_box_blur() : wf_blur_base("box")
{
OpenGL::render_begin();
program[0].set_simple(OpenGL::compile_program(
box_vertex_shader, box_fragment_shader_horz));
program[1].set_simple(OpenGL::compile_program(
box_vertex_shader, box_fragment_shader_vert));
OpenGL::render_end();
}
void upload_data(int i, int width, int height)
{
float offset = offset_opt;
static const float vertexData[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, 1.0f
};
program[i].use(wf::TEXTURE_TYPE_RGBA);
program[i].uniform2f("size", width, height);
program[i].uniform1f("offset", offset);
program[i].attrib_pointer("position", 2, 0, vertexData);
}
void blur(const wf::region_t& blur_region, int i, int width, int height)
{
program[i].use(wf::TEXTURE_TYPE_RGBA);
render_iteration(blur_region, fb[i], fb[!i], width, height);
}
int blur_fb0(const wf::region_t& blur_region, int width, int height) override
{
int i, iterations = iterations_opt;
OpenGL::render_begin();
GL_CALL(glDisable(GL_BLEND));
/* Enable our shader and pass some data to it. The shader
* does box blur on the background texture in two passes,
* one horizontal and one vertical */
upload_data(0, width, height);
upload_data(1, width, height);
for (i = 0; i < iterations; i++)
{
/* Blur horizontally */
blur(blur_region, 0, width, height);
/* Blur vertically */
blur(blur_region, 1, width, height);
}
/* Reset gl state */
GL_CALL(glEnable(GL_BLEND));
GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
program[0].deactivate();
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
OpenGL::render_end();
return 0;
}
int calculate_blur_radius() override
{
return 4 * wf_blur_base::calculate_blur_radius();
}
};
std::unique_ptr create_box_blur()
{
return std::make_unique();
}
wayfire-0.9.0/plugins/blur/gaussian.cpp 0000664 0000000 0000000 00000010057 14662337126 0020146 0 ustar 00root root 0000000 0000000 #include "blur.hpp"
static const char *gaussian_vertex_shader =
R"(
#version 100
attribute mediump vec2 position;
uniform vec2 size;
uniform float offset;
varying highp vec2 blurcoord[5];
void main() {
gl_Position = vec4(position.xy, 0.0, 1.0);
vec2 texcoord = (position.xy + vec2(1.0, 1.0)) / 2.0;
blurcoord[0] = texcoord;
blurcoord[1] = texcoord + vec2(1.5 * offset) / size;
blurcoord[2] = texcoord - vec2(1.5 * offset) / size;
blurcoord[3] = texcoord + vec2(3.5 * offset) / size;
blurcoord[4] = texcoord - vec2(3.5 * offset) / size;
}
)";
static const char *gaussian_fragment_shader_horz =
R"(
#version 100
precision mediump float;
uniform sampler2D bg_texture;
uniform int mode;
varying highp vec2 blurcoord[5];
void main()
{
vec2 uv = blurcoord[0];
vec4 bp = vec4(0.0);
bp += texture2D(bg_texture, vec2(blurcoord[0].x, uv.y)) * 0.204164;
bp += texture2D(bg_texture, vec2(blurcoord[1].x, uv.y)) * 0.304005;
bp += texture2D(bg_texture, vec2(blurcoord[2].x, uv.y)) * 0.304005;
bp += texture2D(bg_texture, vec2(blurcoord[3].x, uv.y)) * 0.093913;
bp += texture2D(bg_texture, vec2(blurcoord[4].x, uv.y)) * 0.093913;
gl_FragColor = bp;
})";
static const char *gaussian_fragment_shader_vert =
R"(
#version 100
precision mediump float;
uniform sampler2D bg_texture;
uniform int mode;
varying highp vec2 blurcoord[5];
void main()
{
vec2 uv = blurcoord[0];
vec4 bp = vec4(0.0);
bp += texture2D(bg_texture, vec2(uv.x, blurcoord[0].y)) * 0.204164;
bp += texture2D(bg_texture, vec2(uv.x, blurcoord[1].y)) * 0.304005;
bp += texture2D(bg_texture, vec2(uv.x, blurcoord[2].y)) * 0.304005;
bp += texture2D(bg_texture, vec2(uv.x, blurcoord[3].y)) * 0.093913;
bp += texture2D(bg_texture, vec2(uv.x, blurcoord[4].y)) * 0.093913;
gl_FragColor = bp;
})";
class wf_gaussian_blur : public wf_blur_base
{
public:
wf_gaussian_blur() : wf_blur_base("gaussian")
{
OpenGL::render_begin();
program[0].set_simple(OpenGL::compile_program(
gaussian_vertex_shader, gaussian_fragment_shader_horz));
program[1].set_simple(OpenGL::compile_program(
gaussian_vertex_shader, gaussian_fragment_shader_vert));
OpenGL::render_end();
}
void upload_data(int i, int width, int height)
{
float offset = offset_opt;
static const float vertexData[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, 1.0f
};
program[i].use(wf::TEXTURE_TYPE_RGBA);
program[i].uniform2f("size", width, height);
program[i].uniform1f("offset", offset);
program[i].attrib_pointer("position", 2, 0, vertexData);
}
void blur(const wf::region_t& blur_region, int i, int width, int height)
{
program[i].use(wf::TEXTURE_TYPE_RGBA);
render_iteration(blur_region, fb[i], fb[!i], width, height);
}
int blur_fb0(const wf::region_t& blur_region, int width, int height) override
{
int i, iterations = iterations_opt;
OpenGL::render_begin();
GL_CALL(glDisable(GL_BLEND));
/* Enable our shader and pass some data to it. The shader
* does gaussian blur on the background texture in two passes,
* one horizontal and one vertical */
upload_data(0, width, height);
upload_data(1, width, height);
for (i = 0; i < iterations; i++)
{
/* Blur horizontally */
blur(blur_region, 0, width, height);
/* Blur vertically */
blur(blur_region, 1, width, height);
}
/* Reset gl state */
GL_CALL(glEnable(GL_BLEND));
GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
program[1].deactivate();
OpenGL::render_end();
return 0;
}
int calculate_blur_radius() override
{
return 4 * wf_blur_base::calculate_blur_radius();
}
};
std::unique_ptr create_gaussian_blur()
{
return std::make_unique();
}
wayfire-0.9.0/plugins/blur/kawase.cpp 0000664 0000000 0000000 00000010662 14662337126 0017611 0 ustar 00root root 0000000 0000000 #include "blur.hpp"
static const char *kawase_vertex_shader =
R"(
#version 100
attribute mediump vec2 position;
varying mediump vec2 uv;
void main() {
gl_Position = vec4(position.xy, 0.0, 1.0);
uv = (position.xy + vec2(1.0, 1.0)) / 2.0;
})";
static const char *kawase_fragment_shader_down =
R"(
#version 100
precision mediump float;
uniform float offset;
uniform vec2 halfpixel;
uniform sampler2D bg_texture;
varying mediump vec2 uv;
void main()
{
vec4 sum = texture2D(bg_texture, uv) * 4.0;
sum += texture2D(bg_texture, uv - halfpixel.xy * offset);
sum += texture2D(bg_texture, uv + halfpixel.xy * offset);
sum += texture2D(bg_texture, uv + vec2(halfpixel.x, -halfpixel.y) * offset);
sum += texture2D(bg_texture, uv - vec2(halfpixel.x, -halfpixel.y) * offset);
gl_FragColor = sum / 8.0;
})";
static const char *kawase_fragment_shader_up =
R"(
#version 100
precision mediump float;
uniform float offset;
uniform vec2 halfpixel;
uniform sampler2D bg_texture;
varying mediump vec2 uv;
void main()
{
vec4 sum = texture2D(bg_texture, uv + vec2(-halfpixel.x * 2.0, 0.0) * offset);
sum += texture2D(bg_texture, uv + vec2(-halfpixel.x, halfpixel.y) * offset) * 2.0;
sum += texture2D(bg_texture, uv + vec2(0.0, halfpixel.y * 2.0) * offset);
sum += texture2D(bg_texture, uv + vec2(halfpixel.x, halfpixel.y) * offset) * 2.0;
sum += texture2D(bg_texture, uv + vec2(halfpixel.x * 2.0, 0.0) * offset);
sum += texture2D(bg_texture, uv + vec2(halfpixel.x, -halfpixel.y) * offset) * 2.0;
sum += texture2D(bg_texture, uv + vec2(0.0, -halfpixel.y * 2.0) * offset);
sum += texture2D(bg_texture, uv + vec2(-halfpixel.x, -halfpixel.y) * offset) * 2.0;
gl_FragColor = sum / 12.0;
})";
class wf_kawase_blur : public wf_blur_base
{
public:
wf_kawase_blur() : wf_blur_base("kawase")
{
OpenGL::render_begin();
program[0].set_simple(OpenGL::compile_program(kawase_vertex_shader,
kawase_fragment_shader_down));
program[1].set_simple(OpenGL::compile_program(kawase_vertex_shader,
kawase_fragment_shader_up));
OpenGL::render_end();
}
int blur_fb0(const wf::region_t& blur_region, int width, int height) override
{
int iterations = iterations_opt;
float offset = offset_opt;
int sampleWidth, sampleHeight;
/* Upload data to shader */
static const float vertexData[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, 1.0f
};
OpenGL::render_begin();
program[0].use(wf::TEXTURE_TYPE_RGBA);
/* Downsample */
program[0].attrib_pointer("position", 2, 0, vertexData);
/* Disable blending, because we may have transparent background, which
* we want to render on uncleared framebuffer */
GL_CALL(glDisable(GL_BLEND));
program[0].uniform1f("offset", offset);
for (int i = 0; i < iterations; i++)
{
sampleWidth = width / (1 << i);
sampleHeight = height / (1 << i);
auto region = blur_region * (1.0 / (1 << i));
program[0].uniform2f("halfpixel",
0.5f / sampleWidth, 0.5f / sampleHeight);
render_iteration(region, fb[i % 2], fb[1 - i % 2], sampleWidth,
sampleHeight);
}
program[0].deactivate();
/* Upsample */
program[1].use(wf::TEXTURE_TYPE_RGBA);
program[1].attrib_pointer("position", 2, 0, vertexData);
program[1].uniform1f("offset", offset);
for (int i = iterations - 1; i >= 0; i--)
{
sampleWidth = width / (1 << i);
sampleHeight = height / (1 << i);
auto region = blur_region * (1.0 / (1 << i));
program[1].uniform2f("halfpixel",
0.5f / sampleWidth, 0.5f / sampleHeight);
render_iteration(region, fb[1 - i % 2], fb[i % 2], sampleWidth,
sampleHeight);
}
/* Reset gl state */
GL_CALL(glEnable(GL_BLEND));
GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
program[1].deactivate();
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
OpenGL::render_end();
return 0;
}
int calculate_blur_radius() override
{
return pow(2, iterations_opt + 1) * offset_opt * degrade_opt;
}
};
std::unique_ptr create_kawase_blur()
{
return std::make_unique();
}
wayfire-0.9.0/plugins/blur/meson.build 0000664 0000000 0000000 00000001156 14662337126 0017772 0 ustar 00root root 0000000 0000000 blur_base = shared_library('wayfire-blur-base',
['blur-base.cpp', 'box.cpp', 'gaussian.cpp', 'kawase.cpp', 'bokeh.cpp'],
include_directories: [wayfire_api_inc, wayfire_conf_inc],
dependencies: [wlroots, pixman, wfconfig],
override_options: ['b_lundef=false'],
install: true)
install_headers(['blur.hpp'], subdir: 'wayfire/plugins/blur')
blur = shared_module('blur', ['blur.cpp'],
link_with: blur_base,
include_directories: [wayfire_api_inc, wayfire_conf_inc],
dependencies: [wlroots, pixman, wfconfig],
install: true, install_dir: join_paths(get_option('libdir'), 'wayfire'))
wayfire-0.9.0/plugins/common/ 0000775 0000000 0000000 00000000000 14662337126 0016151 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/plugins/common/meson.build 0000664 0000000 0000000 00000000157 14662337126 0020316 0 ustar 00root root 0000000 0000000 plugins_common_inc = include_directories('.')
install_subdir('wayfire', install_dir: get_option('includedir'))
wayfire-0.9.0/plugins/common/wayfire/ 0000775 0000000 0000000 00000000000 14662337126 0017617 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/plugins/common/wayfire/plugins/ 0000775 0000000 0000000 00000000000 14662337126 0021300 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/plugins/common/wayfire/plugins/common/ 0000775 0000000 0000000 00000000000 14662337126 0022570 5 ustar 00root root 0000000 0000000 wayfire-0.9.0/plugins/common/wayfire/plugins/common/cairo-util.hpp 0000664 0000000 0000000 00000024354 14662337126 0025361 0 ustar 00root root 0000000 0000000 #pragma once
#include "wayfire/geometry.hpp"
#include
#include
#include
#include
#include
#include
namespace wf
{
struct simple_texture_t;
}
/**
* Upload the data from the cairo surface to the OpenGL texture.
*
* @param surface The source cairo surface.
* @param buffer The buffer to upload data to.
*/
static void cairo_surface_upload_to_texture(
cairo_surface_t *surface, wf::simple_texture_t& buffer)
{
buffer.width = cairo_image_surface_get_width(surface);
buffer.height = cairo_image_surface_get_height(surface);
if (buffer.tex == (GLuint) - 1)
{
GL_CALL(glGenTextures(1, &buffer.tex));
}
auto src = cairo_image_surface_get_data(surface);
GL_CALL(glBindTexture(GL_TEXTURE_2D, buffer.tex));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED));
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
buffer.width, buffer.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, src));
}
namespace wf
{
/**
* Simple wrapper around rendering text with Cairo. This object can be
* kept around to avoid reallocation of the cairo surface and OpenGL
* texture on repeated renders.
*/
struct cairo_text_t
{
wf::simple_texture_t tex;
/* parameters used for rendering */
struct params
{
/* font size */
int font_size = 12;
/* color for background rectangle (only used if bg_rect == true) */
wf::color_t bg_color;
/* text color */
wf::color_t text_color;
/* scale everything by this amount */
float output_scale = 1.f;
/* crop result to this size (if nonzero);
* note that this is multiplied by output_scale */
wf::dimensions_t max_size{0, 0};
/* draw a rectangle in the background with bg_color */
bool bg_rect = true;
/* round the corners of the background rectangle */
bool rounded_rect = true;
/* if true, the resulting surface will be cropped to the
* minimum size necessary to fit the text; otherwise, the
* resulting surface might be bigger than necessary and the
* text is centered in it */
bool exact_size = false;
params()
{}
params(int font_size_, const wf::color_t& bg_color_,
const wf::color_t& text_color_, float output_scale_ = 1.f,
const wf::dimensions_t& max_size_ = {0, 0},
bool bg_rect_ = true, bool exact_size_ = false) :
font_size(font_size_), bg_color(bg_color_),
text_color(text_color_), output_scale(output_scale_),
max_size(max_size_), bg_rect(bg_rect_),
exact_size(exact_size_)
{}
};
/**
* Render the given text in the texture tex.
*
* @param text text to render
* @param par parameters for rendering
*
* @return The size needed to render in scaled coordinates. If this is larger
* than the size of tex, it means the result was cropped (due to the constraint
* given in par.max_size). If it is smaller, than the result is centered along
* that dimension.
*/
wf::dimensions_t render_text(const std::string& text, const params& par)
{
if (!cr)
{
/* create with default size */
cairo_create_surface();
}
PangoFontDescription *font_desc;
PangoLayout *layout;
PangoRectangle extents;
/* TODO: font properties could be made parameters! */
font_desc = pango_font_description_from_string("sans-serif bold");
pango_font_description_set_absolute_size(font_desc,
par.font_size * par.output_scale * PANGO_SCALE);
layout = pango_cairo_create_layout(cr);
pango_layout_set_font_description(layout, font_desc);
pango_layout_set_text(layout, text.c_str(), text.size());
pango_layout_get_extents(layout, NULL, &extents);
double xpad = par.bg_rect ? 10.0 * par.output_scale : 0.0;
double ypad = par.bg_rect ?
0.2 * ((float)extents.height / PANGO_SCALE) : 0.0;
int w = (int)((float)extents.width / PANGO_SCALE + 2 * xpad);
int h = (int)((float)extents.height / PANGO_SCALE + 2 * ypad);
wf::dimensions_t ret = {w, h};
if (par.max_size.width && (w > par.max_size.width * par.output_scale))
{
w = (int)std::floor(par.max_size.width * par.output_scale);
}
if (par.max_size.height && (h > par.max_size.height * par.output_scale))
{
h = (int)std::floor(par.max_size.height * par.output_scale);
}
if ((w != surface_size.width) || (h != surface_size.height))
{
if (par.exact_size || (w > surface_size.width) ||
(h > surface_size.height))
{
surface_size.width = w;
surface_size.height = h;
cairo_create_surface();
}
}
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
int x = (surface_size.width - w) / 2;
int y = (surface_size.height - h) / 2;
if (par.bg_rect)
{
int min_r = (int)(20 * par.output_scale);
int r = par.rounded_rect ? (h > min_r ? min_r : (h - 2) / 2) : 0;
cairo_move_to(cr, x + r, y);
cairo_line_to(cr, x + w - r, y);
if (par.rounded_rect)
{
cairo_curve_to(cr, x + w, y, x + w, y, x + w, y + r);
}
cairo_line_to(cr, x + w, y + h - r);
if (par.rounded_rect)
{
cairo_curve_to(cr, x + w, y + h, x + w, y + h, x + w - r, y + h);
}
cairo_line_to(cr, x + r, y + h);
if (par.rounded_rect)
{
cairo_curve_to(cr, x, y + h, x, y + h, x, y + h - r);
}
cairo_line_to(cr, x, y + r);
if (par.rounded_rect)
{
cairo_curve_to(cr, x, y, x, y, x + r, y);
}
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, par.bg_color.r, par.bg_color.g,
par.bg_color.b, par.bg_color.a);
cairo_fill(cr);
}
x += xpad;
y += ypad;
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_move_to(cr, x - (float)extents.x / PANGO_SCALE, y);
cairo_set_source_rgba(cr, par.text_color.r, par.text_color.g,
par.text_color.b, par.text_color.a);
pango_cairo_show_layout(cr, layout);
pango_font_description_free(font_desc);
g_object_unref(layout);
cairo_surface_flush(surface);
OpenGL::render_begin();
cairo_surface_upload_to_texture(surface, tex);
OpenGL::render_end();
return ret;
}
/**
* Standalone function version to render text to an OpenGL texture
*/
static wf::dimensions_t cairo_render_text_to_texture(const std::string& text,
const wf::cairo_text_t::params& par, wf::simple_texture_t& tex)
{
wf::cairo_text_t ct;
/* note: we "borrow" the texture from what was supplied (if any) */
ct.tex.tex = tex.tex;
auto ret = ct.render_text(text, par);
if (tex.tex == (GLuint) - 1)
{
tex.tex = ct.tex.tex;
}
tex.width = ct.tex.width;
tex.height = ct.tex.height;
ct.tex.tex = -1;
return ret;
}
cairo_text_t() = default;
~cairo_text_t()
{
cairo_free();
}
cairo_text_t(const cairo_text_t &) = delete;
cairo_text_t& operator =(const cairo_text_t&) = delete;
cairo_text_t(cairo_text_t && o) noexcept : tex(std::move(o.tex)), cr(o.cr),
surface(o.surface), surface_size(o.surface_size)
{
o.cr = nullptr;
o.surface = nullptr;
}
cairo_text_t& operator =(cairo_text_t&& o) noexcept
{
if (&o == this)
{
return *this;
}
cairo_free();
tex = std::move(o.tex);
cr = o.cr;
surface = o.surface;
surface_size = o.surface_size;
o.cr = nullptr;
o.surface = nullptr;
return *this;
}
/**
* Calculate the height of text rendered with a given font size.
*
* @param font_size Desired font size.
* @param bg_rect Whether a background rectangle should be taken into account.
*
* @returns Required height of the surface.
*/
static unsigned int measure_height(int font_size, bool bg_rect = true)
{
cairo_text_t dummy;
dummy.surface_size.width = 1;
dummy.surface_size.height = 1;
dummy.cairo_create_surface();
cairo_font_extents_t font_extents;
/* TODO: font properties could be made parameters! */
cairo_select_font_face(dummy.cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(dummy.cr, font_size);
cairo_font_extents(dummy.cr, &font_extents);
double ypad = bg_rect ? 0.2 * (font_extents.ascent +
font_extents.descent) : 0.0;
unsigned int h = (unsigned int)std::ceil(font_extents.ascent +
font_extents.descent + 2 * ypad);
return h;
}
wf::dimensions_t get_size() const
{
return surface_size;
}
protected:
/* cairo context and surface for the text */
cairo_t *cr = nullptr;
cairo_surface_t *surface = nullptr;
/* current width and height of the above surface */
wf::dimensions_t surface_size = {400, 100};
void cairo_free()
{
if (cr)
{
cairo_destroy(cr);
}
if (surface)
{
cairo_surface_destroy(surface);
}
cr = nullptr;
surface = nullptr;
}
void cairo_create_surface()
{
cairo_free();
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, surface_size.width,
surface_size.height);
cr = cairo_create(surface);
}
};
}
wayfire-0.9.0/plugins/common/wayfire/plugins/common/geometry-animation.hpp 0000664 0000000 0000000 00000003016 14662337126 0027111 0 ustar 00root root 0000000 0000000 #pragma once
#include
#include
#include
namespace wf
{
using namespace wf::animation;
class geometry_animation_t : public duration_t
{
public:
using duration_t::duration_t;
timed_transition_t x{*this};
timed_transition_t y{*this};
timed_transition_t width{*this};
timed_transition_t height{*this};
void set_start(wf::geometry_t geometry)
{
copy_fields(geometry, &timed_transition_t::start);
}
void set_end(wf::geometry_t geometry)
{
copy_fields(geometry, &timed_transition_t::end);
}
operator wf::geometry_t() const
{
return {(int)x, (int)y, (int)width, (int)height};
}
protected:
void copy_fields(wf::geometry_t geometry, double timed_transition_t::*member)
{
this->x.*member = geometry.x;
this->y.*member = geometry.y;
this->width.*member = geometry.width;
this->height.*member = geometry.height;
}
};
/** Interpolate the geometry between a and b with alpha (in [0..1]), i.e a *
* (1-alpha) + b * alpha */
static inline wf::geometry_t interpolate(wf::geometry_t a, wf::geometry_t b,
double alpha)
{
const auto& interp = [=] (int32_t wf::geometry_t::*member) -> int32_t
{
return std::round((1 - alpha) * a.*member + alpha * b.*member);
};
return {
interp(&wf::geometry_t::x),
interp(&wf::geometry_t::y),
interp(&wf::geometry_t::width),
interp(&wf::geometry_t::height)
};
}
}
wayfire-0.9.0/plugins/common/wayfire/plugins/common/input-grab.hpp 0000664 0000000 0000000 00000012261 14662337126 0025353 0 ustar 00root root 0000000 0000000 #pragma once
#include "wayfire/core.hpp"
#include "wayfire/output.hpp"
#include "wayfire/scene-input.hpp"
#include "wayfire/scene-operations.hpp"
#include "wayfire/scene.hpp"
#include
#include
#include
#include
namespace wf
{
namespace scene
{
/**
* A scene node which can be used to implement input grab on a particular output.
*/
class grab_node_t : public node_t
{
std::string name;
wf::output_t *output;
keyboard_interaction_t *keyboard = nullptr;
pointer_interaction_t *pointer = nullptr;
touch_interaction_t *touch = nullptr;
node_flags_bitmask_t m_flags = 0;
public:
grab_node_t(std::string name, wf::output_t *output,
keyboard_interaction_t *keyboard = NULL,
pointer_interaction_t *pointer = NULL,
touch_interaction_t *touch = NULL) :
node_t(false), name(name), output(output),
keyboard(keyboard), pointer(pointer), touch(touch)
{}
node_flags_bitmask_t flags() const override
{
return node_t::flags() | m_flags;
}
void set_additional_flags(node_flags_bitmask_t add_flags)
{
this->m_flags = add_flags;
}
std::optional find_node_at(const wf::pointf_t& at) override
{
if (output->get_layout_geometry() & at)
{
input_node_t result;
result.node = this;
result.local_coords = to_local(at);
return result;
}
return {};
}
wf::keyboard_focus_node_t keyboard_refocus(wf::output_t *output) override
{
if (output != this->output)
{
return wf::keyboard_focus_node_t{};
}
return wf::keyboard_focus_node_t{
.node = this,
.importance = focus_importance::REGULAR,
.allow_focus_below = false,
};
}
/**
* Get a textual representation of the node, used for debugging purposes.
* For example, see wf::dump_scene().
* The representation should therefore not contain any newline characters.
*/
std::string stringify() const override
{
return name + "-input-grab " + std::string(output ? output->to_string() : "null");
}
keyboard_interaction_t& keyboard_interaction() override
{
return keyboard ? *keyboard : node_t::keyboard_interaction();
}
pointer_interaction_t& pointer_interaction() override
{
return pointer ? *pointer : node_t::pointer_interaction();
}
touch_interaction_t& touch_interaction() override
{
return touch ? *touch : node_t::touch_interaction();
}
};
}
/**
* A helper class for managing input grabs on an output.
*/
class input_grab_t
{
wf::output_t *output;
std::shared_ptr grab_node;
public:
input_grab_t(std::string name, wf::output_t *output,
keyboard_interaction_t *keyboard = NULL,
pointer_interaction_t *pointer = NULL,
touch_interaction_t *touch = NULL)
{
this->output = output;
grab_node = std::make_shared(name, output, keyboard, pointer, touch);
}
/**
* Set/unset the RAW_INPUT flag on the grab node.
*/
void set_wants_raw_input(bool wants_raw)
{
grab_node->set_additional_flags(wants_raw ? (uint64_t)wf::scene::node_flags::RAW_INPUT : 0);
}
bool is_grabbed() const
{
return grab_node->parent() != nullptr;
}
/**
* Grab input from all layers from background to @layer_below.
*/
void grab_input(wf::scene::layer layer_below)
{
wf::dassert(grab_node->parent() == nullptr, "Trying to grab twice!");
auto& root = wf::get_core().scene();
auto children = root->get_children();
auto idx = std::find(children.begin(), children.end(),
root->layers[(int)layer_below]);
wf::dassert(idx != children.end(), "Could not find node for a layer: " +
std::to_string((int)layer_below));
children.insert(idx, grab_node);
root->set_children_list(children);
if (output == wf::get_core().seat->get_active_output())
{
wf::get_core().transfer_grab(grab_node);
}
scene::update(root, scene::update_flag::CHILDREN_LIST | scene::update_flag::REFOCUS);
// Set cursor to default.
wf::get_core().set_cursor("default");
}
void regrab_input()
{
const auto& check_focus = [&] (wf::scene::node_ptr focused)
{
return (focused == nullptr) || (focused == grab_node);
};
if ((wf::get_core().seat->get_active_node() == grab_node) &&
check_focus(wf::get_core().get_cursor_focus()) &&
check_focus(wf::get_core().get_touch_focus()))
{
return;
}
if (output == wf::get_core().seat->get_active_output())
{
wf::get_core().transfer_grab(grab_node);
}
scene::update(wf::get_core().scene(), scene::update_flag::REFOCUS);
}
/**
* Ungrab the input.
*/
void ungrab_input()
{
if (grab_node->parent())
{
wf::scene::remove_child(grab_node, scene::update_flag::REFOCUS);
}
}
};
}
wayfire-0.9.0/plugins/common/wayfire/plugins/common/key-repeat.hpp 0000664 0000000 0000000 00000001665 14662337126 0025357 0 ustar 00root root 0000000 0000000 #pragma once
#include
#include
namespace wf
{
struct key_repeat_t
{
wf::option_wrapper_t delay{"input/kb_repeat_delay"};
wf::option_wrapper_t rate{"input/kb_repeat_rate"};
wf::wl_timer timer_delay;
wf::wl_timer timer_rate;
using callback_t = std::function;
key_repeat_t()
{}
key_repeat_t(uint32_t key, callback_t handler)
{
set_callback(key, handler);
}
void set_callback(uint32_t key, callback_t handler)
{
disconnect();
timer_delay.set_timeout(delay, [=] ()
{
timer_rate.set_timeout(1000 / rate, [=] ()
{
// handle can determine if key should be repeated
return handler(key);
});
});
}
void disconnect()
{
timer_delay.disconnect();
timer_rate.disconnect();
}
};
}
wayfire-0.9.0/plugins/common/wayfire/plugins/common/move-drag-interface.hpp 0000664 0000000 0000000 00000064024 14662337126 0027126 0 ustar 00root root 0000000 0000000 #pragma once
#include "wayfire/core.hpp"
#include "wayfire/debug.hpp"
#include "wayfire/geometry.hpp"
#include "wayfire/opengl.hpp"
#include "wayfire/region.hpp"
#include "wayfire/scene-input.hpp"
#include "wayfire/scene-operations.hpp"
#include "wayfire/scene-render.hpp"
#include "wayfire/scene.hpp"
#include "wayfire/seat.hpp"
#include "wayfire/signal-definitions.hpp"
#include "wayfire/view-helpers.hpp"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace wf
{
/**
* A collection of classes and interfaces which can be used by plugins which
* support dragging views to move them.
*
* A plugin using these APIs would get support for:
*
* - Moving views on the same output, following the pointer or touch position.
* - Holding views in place until a certain threshold is reached
* - Wobbly windows (if enabled)
* - Move the view freely between different outputs with different plugins active
* on them, as long as all of these plugins support this interface.
* - Show smooth transitions of the moving view when moving between different
* outputs.
*
* A plugin using these APIs is expected to:
* - Grab input on its respective output and forward any events to the core_drag_t
* singleton.
* - Have activated itself with CAPABILITY_MANAGE_COMPOSITOR
* - Connect to and handle the signals described below.
*/
namespace move_drag
{
/**
* name: focus-output
* on: core_drag_t
* when: Emitted output whenever the output where the drag happens changes,
* including when the drag begins.
*/
struct drag_focus_output_signal
{
/** The output which was focused up to now, might be null. */
wf::output_t *previous_focus_output;
/** The output which was focused now. */
wf::output_t *focus_output;
};
/**
* Emitted on core_drag_t when input motion is triggered.
*/
struct drag_motion_signal
{
wf::point_t current_position;
};
/**
* name: snap-off
* on: core_drag_t
* when: Emitted if snap-off is enabled and the view was moved more than the
* threshold.
*/
struct snap_off_signal
{
/** The output which is focused now. */
wf::output_t *focus_output;
};
/**
* name: done
* on: core_drag_t
* when: Emitted after the drag operation has ended, and if the view is unmapped
* while being dragged.
*/
struct drag_done_signal
{
/** The output where the view was dropped. */
wf::output_t *focused_output;
/** Whether join-views was enabled for this drag. */
bool join_views;
struct view_t
{
/** Dragged view. */
wayfire_toplevel_view view;
/**
* The position relative to the view where the grab was.
* See scale_around_grab_t::relative_grab
*/
wf::pointf_t relative_grab;
};
/** All views which were dragged. */
std::vector all_views;
/** The main view which was dragged. */
wayfire_toplevel_view main_view;
/**
* The position of the input when the view was dropped.
* In output-layout coordinates.
*/
wf::point_t grab_position;
};
/**
* Find the geometry of a view, if it has size @size, it is grabbed at point @grab,
* and the grab is at position @relative relative to the view.
*/
inline static wf::geometry_t find_geometry_around(
wf::dimensions_t size, wf::point_t grab, wf::pointf_t relative)
{
return wf::geometry_t{
grab.x - (int)std::floor(relative.x * size.width),
grab.y - (int)std::floor(relative.y * size.height),
size.width,
size.height,
};
}
/**
* Find the position of grab relative to the view.
* Example: returns [0.5, 0.5] if the grab is the midpoint of the view.
*/
inline static wf::pointf_t find_relative_grab(
wf::geometry_t view, wf::point_t grab)
{
return wf::pointf_t{
1.0 * (grab.x - view.x) / view.width,
1.0 * (grab.y - view.y) / view.height,
};
}
/**
* A transformer used while dragging.
*
* It is primarily used to scale the view is a plugin needs it, and also to keep it
* centered around the `grab_position`.
*/
class scale_around_grab_t : public wf::scene::transformer_base_node_t
{
public:
/**
* Factor for scaling down the view.
* A factor 2.0 means that the view will have half of its width and height.
*/
wf::animation::simple_animation_t scale_factor{wf::create_option(300)};
wf::animation::simple_animation_t alpha_factor{wf::create_option(300)};
/**
* A place relative to the view, where it is grabbed.
*
* Coordinates are [0, 1]. A grab at (0.5, 0.5) means that the view is grabbed
* at its center.
*/
wf::pointf_t relative_grab;
/**
* The position where the grab appears on the outputs, in output-layout
* coordinates.
*/
wf::point_t grab_position;
scale_around_grab_t() : transformer_base_node_t(false)
{}
std::string stringify() const override
{
return "move-drag";
}
wf::pointf_t scale_around_grab(wf::pointf_t point, double factor)
{
auto bbox = get_children_bounding_box();
auto gx = bbox.x + bbox.width * relative_grab.x;
auto gy = bbox.y + bbox.height * relative_grab.y;
return {
(point.x - gx) * factor + gx,
(point.y - gy) * factor + gy,
};
}
wf::pointf_t to_local(const wf::pointf_t& point) override
{
return scale_around_grab(point, scale_factor);
}
wf::pointf_t to_global(const wf::pointf_t& point) override
{
return scale_around_grab(point, 1.0 / scale_factor);
}
wf::geometry_t get_bounding_box() override
{
auto bbox = get_children_bounding_box();
int w = std::floor(bbox.width / scale_factor);
int h = std::floor(bbox.height / scale_factor);
return find_geometry_around({w, h}, grab_position, relative_grab);
}
class render_instance_t :
public scene::transformer_render_instance_t
{
public:
using transformer_render_instance_t::transformer_render_instance_t;
void transform_damage_region(wf::region_t& region) override
{
region |= self->get_bounding_box();
}
void render(const wf::render_target_t& target,
const wf::region_t& region) override
{
auto bbox = self->get_bounding_box();
auto tex = this->get_texture(target.scale);
OpenGL::render_begin(target);
for (auto& rect : region)
{
target.logic_scissor(wlr_box_from_pixman_box(rect));
OpenGL::render_texture(tex, target, bbox, glm::vec4{1, 1, 1, (double)self->alpha_factor});
}
OpenGL::render_end();
}
};
void gen_render_instances(std::vector& instances,
scene::damage_callback push_damage, wf::output_t *shown_on) override
{
instances.push_back(std::make_unique(this,
push_damage, shown_on));
}
};
static const std::string move_drag_transformer = "move-drag-transformer";
/**
* Represents a view which is being dragged.
* Multiple views exist only if join_views is set to true.
*/
struct dragged_view_t
{
// The view being dragged
wayfire_toplevel_view view;
// Its transformer
std::shared_ptr transformer;
// The last bounding box used for damage.
// This is needed in case the view resizes or something like that, in which
// case we don't have access to the previous bbox.
wf::geometry_t last_bbox;
};
inline std::vector get_target_views(wayfire_toplevel_view grabbed,
bool join_views)
{
std::vector r = {grabbed};
if (join_views)
{
r = grabbed->enumerate_views();
}
return r;
}
// A node to render the dragged views in global coordinates.
// The assumption is that all nodes have a view transformer which transforms them to global (not output-local)
// coordinates and thus we just need to schedule them for rendering.
class dragged_view_node_t : public wf::scene::node_t
{
public:
std::vector views;
dragged_view_node_t(std::vector views) : node_t(false)
{
this->views = views;
}
std::string stringify() const override
{
return "move-drag-view " + stringify_flags();
}
void gen_render_instances(std::vector& instances,
scene::damage_callback push_damage, wf::output_t *output = nullptr) override
{
instances.push_back(std::make_unique(
std::dynamic_pointer_cast(shared_from_this()), push_damage, output));
}
wf::geometry_t get_bounding_box() override
{
wf::region_t bounding;
for (auto& view : views)
{
// Note: bbox will be in output layout coordinates now, since this is
// how the transformer works
auto bbox = view.view->get_transformed_node()->get_bounding_box();
bounding |= bbox;
}
return wlr_box_from_pixman_box(bounding.get_extents());
}
class dragged_view_render_instance_t : public wf::scene::render_instance_t
{
wf::geometry_t last_bbox = {0, 0, 0, 0};
wf::scene::damage_callback push_damage;
std::vector children;
wf::signal::connection_t on_node_damage =
[=] (scene::node_damage_signal *data)
{
push_damage(data->region);
};
public:
dragged_view_render_instance_t(std::shared_ptr self,
wf::scene::damage_callback push_damage, wf::output_t *shown_on)
{
auto push_damage_child = [=] (wf::region_t child_damage)
{
push_damage(last_bbox);
last_bbox = self->get_bounding_box();
push_damage(last_bbox);
};
for (auto& view : self->views)
{
auto node = view.view->get_transformed_node();
node->gen_render_instances(children, push_damage_child, shown_on);
}
}
void schedule_instructions(std::vector& instructions,
const wf::render_target_t& target, wf::region_t& damage) override
{
for (auto& inst : children)
{
inst->schedule_instructions(instructions, target, damage);
}
}
void presentation_feedback(wf::output_t *output) override
{
for (auto& instance : children)
{
instance->presentation_feedback(output);
}
}
void compute_visibility(wf::output_t *output, wf::region_t& visible) override
{
for (auto& instance : children)
{
const int BIG_NUMBER = 1e5;
wf::region_t big_region =
wf::geometry_t{-BIG_NUMBER, -BIG_NUMBER, 2 * BIG_NUMBER, 2 * BIG_NUMBER};
instance->compute_visibility(output, big_region);
}
}
};
};
struct drag_options_t
{
/**
* Whether to enable snap off, that is, hold the view in place until
* a certain threshold is reached.
*/
bool enable_snap_off = false;
/**
* If snap-off is enabled, the amount of pixels to wait for motion until
* snap-off is triggered.
*/
int snap_off_threshold = 0;
/**
* Join views together, i.e move main window and dialogues together.
*/
bool join_views = false;
double initial_scale = 1.0;
};
/**
* An object for storing global move drag data (i.e shared between all outputs).
*
* Intended for use via wf::shared_data::ref_ptr_t.
*/
class core_drag_t : public signal::provider_t
{
/**
* Rebuild the wobbly model after a change in the scaling, so that the wobbly
* model does not try to animate the scaling change itself.
*/
void rebuild_wobbly(wayfire_toplevel_view view, wf::point_t grab, wf::pointf_t relative)
{
auto dim = wf::dimensions(wf::view_bounding_box_up_to(view, "wobbly"));
modify_wobbly(view, find_geometry_around(dim, grab, relative));
}
public:
std::optional tentative_grab_position;
core_drag_t()
{
wf::get_core().output_layout->connect(&on_output_removed);
}
/**
* A button has been pressed which might start a drag action.
*/
template
void set_pending_drag(const Point& current_position)
{
this->tentative_grab_position = {(int)current_position.x, (int)current_position.y};
}
/**
* Check whether a motion event makes a sufficient drag so that the drag operation may start at all.
*
* Note that in some cases this functionality is not used at all, if the action for example was triggered
* by a binding.
*/
bool should_start_pending_drag(wf::point_t current_position)
{
if (!tentative_grab_position.has_value())
{
return false;
}
return distance_to_grab_origin(current_position) > 5;
}
/**
* Start the actual dragging operation. Note: this should be called **after** set_pending_drag().
*
* @param grab_view The view which is being dragged.
* @param grab_position The position of the input, in output-layout coordinates.
* @param relative The position of the grab_position relative to view.
*/
void start_drag(wayfire_toplevel_view grab_view, wf::pointf_t relative, const drag_options_t& options)
{
wf::dassert(tentative_grab_position.has_value(),
"First, the drag operation should be set as pending!");
wf::dassert(grab_view->is_mapped(), "Dragged view should be mapped!");
wf::dassert(!this->view, "Drag operation already in progress!");
auto bbox = wf::view_bounding_box_up_to(grab_view, "wobbly");
wf::point_t rel_grab_pos = {
int(bbox.x + relative.x * bbox.width),
int(bbox.y + relative.y * bbox.height),
};
if (options.join_views)
{
grab_view = find_topmost_parent(grab_view);
}
this->view = grab_view;
this->params = options;
wf::get_core().default_wm->set_view_grabbed(view, true);
auto target_views = get_target_views(grab_view, options.join_views);
for (auto& v : target_views)
{
dragged_view_t dragged;
dragged.view = v;
// Setup view transform
auto tr = std::make_shared();
dragged.transformer = {tr};
tr->relative_grab = find_relative_grab(
wf::view_bounding_box_up_to(v, "wobbly"), rel_grab_pos);
tr->grab_position = *tentative_grab_position;
tr->scale_factor.animate(options.initial_scale, options.initial_scale);
tr->alpha_factor.animate(1, 1);
v->get_transformed_node()->add_transformer(
tr, wf::TRANSFORMER_HIGHLEVEL - 1);
// Hide the view, we will render it as an overlay
wf::scene::set_node_enabled(v->get_transformed_node(), false);
v->damage();
// Make sure that wobbly has the correct geometry from the start!
rebuild_wobbly(v, *tentative_grab_position, dragged.transformer->relative_grab);
// TODO: make this configurable!
start_wobbly_rel(v, dragged.transformer->relative_grab);
this->all_views.push_back(dragged);
v->connect(&on_view_unmap);
}
// Setup overlay hooks
render_node = std::make_shared(all_views);
wf::scene::add_front(wf::get_core().scene(), render_node);
wf::get_core().set_cursor("grabbing");
// Set up snap-off
if (params.enable_snap_off)
{
for (auto& v : all_views)
{
set_tiled_wobbly(v.view, true);
}
view_held_in_place = true;
}
}
void start_drag(wayfire_toplevel_view view, const drag_options_t& options)
{
wf::dassert(tentative_grab_position.has_value(),
"First, the drag operation should be set as pending!");
if (options.join_views)
{
view = find_topmost_parent(view);
}
auto bbox = view->get_transformed_node()->get_bounding_box() +
wf::origin(view->get_output()->get_layout_geometry());
start_drag(view, find_relative_grab(bbox, *tentative_grab_position), options);
}
void handle_motion(wf::point_t to)
{
if (view_held_in_place)
{
if (distance_to_grab_origin(to) >= (double)params.snap_off_threshold)
{
view_held_in_place = false;
for (auto& v : all_views)
{
set_tiled_wobbly(v.view, false);
}
snap_off_signal data;
data.focus_output = current_output;
emit(&data);
}
}
// Update wobbly independently of the grab position.
// This is because while held in place, wobbly is anchored to its edges
// so we can still move the grabbed point without moving the view.
for (auto& v : all_views)
{
move_wobbly(v.view, to.x, to.y);
if (!view_held_in_place)
{
v.view->get_transformed_node()->begin_transform_update();
v.transformer->grab_position = to;
v.view->get_transformed_node()->end_transform_update();
}
}
update_current_output(to);
drag_motion_signal data;
data.current_position = to;
emit(&data);
}
double distance_to_grab_origin(wf::point_t to) const
{
return abs(to - *tentative_grab_position);
}
void handle_input_released()
{
if (!view || all_views.empty())
{
this->tentative_grab_position = {};
// Input already released => don't do anything
return;
}
// Store data for the drag done signal
drag_done_signal data;
data.grab_position = all_views.front().transformer->grab_position;
for (auto& v : all_views)
{
data.all_views.push_back(
{v.view, v.transformer->relative_grab});
}
data.main_view = this->view;
data.focused_output = current_output;
data.join_views = params.join_views;
// Remove overlay hooks and damage outputs BEFORE popping the transformer
wf::scene::remove_child(render_node);
render_node->views.clear();
render_node = nullptr;
for (auto& v : all_views)
{
auto grab_position = v.transformer->grab_position;
auto rel_pos = v.transformer->relative_grab;
// Restore view to where it was before
wf::scene::set_node_enabled(v.view->get_transformed_node(), true);
v.view->get_transformed_node()->rem_transformer();
// Reset wobbly and leave it in output-LOCAL coordinates
end_wobbly(v.view);
// Important! If the view scale was not 1.0, the wobbly model needs to be
// updated with the new size. Since this is an artificial resize, we need
// to make sure that the resize happens smoothly.
rebuild_wobbly(v.view, grab_position, rel_pos);
// Put wobbly back in output-local space, the plugins will take it from
// here.
translate_wobbly(v.view,
-wf::origin(v.view->get_output()->get_layout_geometry()));
}
// Reset our state
wf::get_core().default_wm->set_view_grabbed(view, false);
view = nullptr;
all_views.clear();
if (current_output)
{
current_output->render->rem_effect(&on_pre_frame);
current_output = nullptr;
}
wf::get_core().set_cursor("default");
// Lastly, let the plugins handle what happens on drag end.
emit(&data);
view_held_in_place = false;
on_view_unmap.disconnect();
this->tentative_grab_position = {};
}
void set_scale(double new_scale, double alpha = 1.0)
{
for (auto& view : all_views)
{
view.transformer->scale_factor.animate(new_scale);
view.transformer->alpha_factor.animate(alpha);
}
}
bool is_view_held_in_place()
{
return view_held_in_place;
}
// View currently being moved.
wayfire_toplevel_view view;
// Output where the action is happening.
wf::output_t *current_output = NULL;
private:
// All views being dragged, more than one in case of join_views.
std::vector all_views;
// Current parameters
drag_options_t params;
// View is held in place, waiting for snap-off
bool view_held_in_place = false;
std::shared_ptr render_node;
void update_current_output(wf::point_t grab)
{
wf::pointf_t origin = {1.0 * grab.x, 1.0 * grab.y};
auto output = wf::get_core().output_layout->get_output_coords_at(origin, origin);
update_current_output(output);
}
void update_current_output(wf::output_t *output)
{
if (output != current_output)
{
if (current_output)
{
current_output->render->rem_effect(&on_pre_frame);
}
drag_focus_output_signal data;
data.previous_focus_output = current_output;
current_output = output;
data.focus_output = output;
if (output)
{
wf::get_core().seat->focus_output(output);
output->render->add_effect(&on_pre_frame, OUTPUT_EFFECT_PRE);
}
emit(&data);
}
}
wf::effect_hook_t on_pre_frame = [=] ()
{
for (auto& v : this->all_views)
{
if (v.transformer->scale_factor.running())
{
v.view->damage();
}
}
};
wf::signal::connection_t on_view_unmap = [=] (auto *ev)
{
handle_input_released();
};
wf::signal::connection_t on_output_removed = [=] (wf::output_removed_signal *ev)
{
if (current_output == ev->output)
{
update_current_output(nullptr);
}
};
};
/**
* Move the view to the target output and put it at the coordinates of the grab.
* Also take into account view's fullscreen and tiled state.
*
* Unmapped views are ignored.
*/
inline void adjust_view_on_output(drag_done_signal *ev)
{
// Any one of the views that are being dragged.
// They are all part of the same view tree.
auto parent = find_topmost_parent(ev->main_view);
if (!parent->is_mapped())
{
return;
}
const bool change_output = parent->get_output() != ev->focused_output;
auto old_wset = parent->get_wset();
if (change_output)
{
start_move_view_to_wset(parent, ev->focused_output->wset());
}
// Calculate the position we're leaving the view on
auto output_delta = -wf::origin(ev->focused_output->get_layout_geometry());
auto grab = ev->grab_position + output_delta;
auto output_geometry = ev->focused_output->get_relative_geometry();
auto current_ws = ev->focused_output->wset()->get_current_workspace();
wf::point_t target_ws{
(int)std::floor(1.0 * grab.x / output_geometry.width),
(int)std::floor(1.0 * grab.y / output_geometry.height),
};
target_ws = target_ws + current_ws;
auto gsize = ev->focused_output->wset()->get_workspace_grid_size();
target_ws.x = wf::clamp(target_ws.x, 0, gsize.width - 1);
target_ws.y = wf::clamp(target_ws.y, 0, gsize.height - 1);
// view to focus at the end of drag
auto focus_view = ev->main_view;
for (auto& v : ev->all_views)
{
if (!v.view->is_mapped())
{
// Maybe some dialog got unmapped
continue;
}
auto bbox = wf::view_bounding_box_up_to(v.view, "wobbly");
auto wm = v.view->get_geometry();
wf::point_t wm_offset = wf::origin(wm) + -wf::origin(bbox);
bbox = wf::move_drag::find_geometry_around(
wf::dimensions(bbox), grab, v.relative_grab);
wf::point_t target = wf::origin(bbox) + wm_offset;
v.view->move(target.x, target.y);
if (v.view->pending_fullscreen())
{
wf::get_core().default_wm->fullscreen_request(v.view, ev->focused_output, true, target_ws);
} else if (v.view->pending_tiled_edges())
{
wf::get_core().default_wm->tile_request(v.view, v.view->pending_tiled_edges(), target_ws);
}
// check focus timestamp and select the last focused view to (re)focus
if (get_focus_timestamp(v.view) > get_focus_timestamp(focus_view))
{
focus_view = v.view;
}
}
// Ensure that every view is visible on parent's main workspace
for (auto& v : parent->enumerate_views())
{
ev->focused_output->wset()->move_to_workspace(v, target_ws);
}
if (change_output)
{
emit_view_moved_to_wset(parent, old_wset, ev->focused_output->wset());
}
wf::get_core().default_wm->focus_raise_view(focus_view);
}
/**
* Adjust the view's state after snap-off.
*/
inline void adjust_view_on_snap_off(wayfire_toplevel_view view)
{
if (view->pending_tiled_edges() && !view->pending_fullscreen())
{
wf::get_core().default_wm->tile_request(view, 0);
}
}
}
}
wayfire-0.9.0/plugins/common/wayfire/plugins/common/preview-indication.hpp 0000664 0000000 0000000 00000011513 14662337126 0027102 0 ustar 00root root 0000000 0000000 #pragma once
#include
#include
#include
#include
#include "geometry-animation.hpp"
#include "wayfire/view.hpp"
#include
#include
namespace wf
{
using namespace wf::animation;
class preview_indication_animation_t : public geometry_animation_t
{
public:
using geometry_animation_t::geometry_animation_t;
timed_transition_t alpha{*this};
};
/**
* A view which can be used to show previews for different actions on the
* screen, for ex. when snapping a view
*/
class preview_indication_t : public std::enable_shared_from_this
{
wf::effect_hook_t pre_paint;
wf::output_t *output;
preview_indication_animation_t animation;
bool should_close = false;
/* Default colors */
const wf::option_wrapper_t base_color;
const wf::option_wrapper_t base_border;
const wf::option_wrapper_t base_border_w;
std::shared_ptr _self_reference;
public:
std::shared_ptr view;
/**
* Create a new indication preview on the indicated output.
*
* @param start_geometry The geometry the preview should have, relative to
* the output
*/
preview_indication_t(wf::geometry_t start_geometry, wf::output_t *output, const std::string& prefix) :
animation(wf::create_option(200)),
base_color(prefix + "/preview_base_color"),
base_border(prefix + "/preview_base_border"),
base_border_w(prefix + "/preview_border_width")
{
animation.set_start(start_geometry);
animation.set_end(start_geometry);
animation.alpha.set(0, 1);
this->output = output;
pre_paint = [=] () { update_animation(); };
output->render->add_effect(&pre_paint, wf::OUTPUT_EFFECT_PRE);
view = color_rect_view_t::create(VIEW_ROLE_DESKTOP_ENVIRONMENT, output, wf::scene::layer::TOP);
view->set_color(base_color);
view->set_border_color(base_border);
view->set_border(base_border_w);
}
/** A convenience wrapper around the full version */
preview_indication_t(wf::point_t start, wf::output_t *output, const std::string & prefix) :
preview_indication_t(wf::geometry_t{start.x, start.y, 1, 1}, output, prefix)
{}
/**
* Animate the preview to the given target geometry and alpha.
*
* @param close Whether the view should be closed when the target is
* reached.
*/
void set_target_geometry(wf::geometry_t target, float alpha, bool close = false)
{
animation.x.restart_with_end(target.x);
animation.y.restart_with_end(target.y);
animation.width.restart_with_end(target.width);
animation.height.restart_with_end(target.height);
animation.alpha.restart_with_end(alpha);
animation.start();
this->should_close = close;
if (should_close)
{
// Take a reference until we finally close the view
_self_reference = shared_from_this();
}
}
/**
* A wrapper around set_target_geometry(wf::geometry_t, double, bool)
*/
void set_target_geometry(wf::point_t point, double alpha,
bool should_close = false)
{
return set_target_geometry({point.x, point.y, 1, 1},
alpha, should_close);
}
wf::geometry_t get_target_geometry() const
{
return wf::geometry_t{
.x = int(animation.x.end),
.y = int(animation.y.end),
.width = int(animation.width.end),
.height = int(animation.height.end),
};
}
wf::output_t *get_output() const
{
return output;
}
virtual ~preview_indication_t()
{
if (this->output)
{
this->output->render->rem_effect(&pre_paint);
}
}
protected:
/** Update the current state */
void update_animation()
{
wf::geometry_t current = animation;
if (current != view->get_geometry())
{
view->set_geometry(current);
}
double alpha = animation.alpha;
auto cur_color = view->get_color();
auto cur_border_color = view->get_border_color();
if (base_color.value().a * alpha != cur_color.a)
{
cur_color.a = alpha * base_color.value().a;
cur_border_color.a = alpha * base_border.value().a;
view->set_color(cur_color);
view->set_border_color(cur_border_color);
}
/* The end of unmap animation, just exit */
if (!animation.running() && should_close)
{
view->close();
view->damage();
_self_reference.reset();
}
}
};
}
wayfire-0.9.0/plugins/common/wayfire/plugins/common/shared-core-data.hpp 0000664 0000000 0000000 00000003636 14662337126 0026414 0 ustar 00root root 0000000 0000000 #pragma once
#include
#include
namespace wf
{
/**
* The purpose of shared is to allow multiple plugins or plugin instances to
* have shared global custom data.
*
* While this is already possible if the shared data is stored as custom data on
* `wf::get_core()`, the classes here provide convenient wrappers for managing
* the lifetime of the shared data by utilizing RAII.
*/
namespace shared_data
{
namespace detail
{
/** Implementation detail: the actual data stored in core. */
template
class shared_data_t : public wf::custom_data_t
{
public:
T data;
int32_t use_count = 0;
};
}
/**
* A pointer to shared data which holds a reference to it (similar to
* std::shared_ptr). Once the last reference is destroyed, data will be freed
* from core.
*/
template
class ref_ptr_t
{
public:
ref_ptr_t()
{
update_use_count(+1);
this->data = &wf::get_core().get_data_safe>()->data;
}
ref_ptr_t(const ref_ptr_t& other)
{
this->data = other.data;
update_use_count(+1);
}
ref_ptr_t& operator =(const ref_ptr_t& other)
{
this->data = other.data;
update_use_count(+1);
}
ref_ptr_t(ref_ptr_t&& other) = default;
ref_ptr_t& operator =(ref_ptr_t&& other) = default;
~ref_ptr_t()
{
update_use_count(-1);
}
T *get()
{
return data;
}
T*operator ->()
{
return data;
}
private:
// Update the use count, and delete data if necessary.
void update_use_count(int32_t delta)
{
auto instance = wf::get_core().get_data_safe>();
instance->use_count += delta;
if (instance->use_count <= 0)
{
wf::get_core().erase_data>();
}
}
// Pointer to the global data
T *data;
};
}
}
wayfire-0.9.0/plugins/common/wayfire/plugins/common/simple-text-node.hpp 0000664 0000000 0000000 00000003757 14662337126 0026513 0 ustar 00root root 0000000 0000000 #include "wayfire/opengl.hpp"
#include "wayfire/output.hpp"
#include "wayfire/scene.hpp"
#include
class simple_text_node_t : public wf::scene::node_t
{
class render_instance_t : public wf::scene::simple_render_instance_t
{
public:
using simple_render_instance_t::simple_render_instance_t;
void render(const wf::render_target_t& target, const wf::region_t& region)
{
OpenGL::render_begin(target);
auto g = self->get_bounding_box();
for (auto box : region)
{
target.logic_scissor(wlr_box_from_pixman_box(box));
OpenGL::render_texture(self->cr_text.tex.tex, target, g, glm::vec4(1.0f),
OpenGL::TEXTURE_TRANSFORM_INVERT_Y);
}
OpenGL::render_end();
}
};
wf::cairo_text_t cr_text;
public:
simple_text_node_t() : node_t(false)
{}
void gen_render_instances(std::vector& instances,
wf::scene::damage_callback push_damage, wf::output_t *output) override
{
instances.push_back(std::make_unique(this, push_damage, output));
}
wf::geometry_t get_bounding_box() override
{
return wf::construct_box(position, size.value_or(cr_text.get_size()));
}
void set_position(wf::point_t position)
{
this->position = position;
}
void set_size(wf::dimensions_t size)
{
this->size = size;
}
void set_text_params(wf::cairo_text_t::params params)
{
this->params = params;
}
void set_text(std::string text)
{
wf::scene::damage_node(this->shared_from_this(), get_bounding_box());
cr_text.render_text(text, params);
wf::scene::damage_node(this->shared_from_this(), get_bounding_box());
}
private:
wf::cairo_text_t::params params;
std::optional