chore: import SwayFX 0.6 base

This commit is contained in:
fy59 2026-10-10 06:26:32 +02:00
commit a57e3f2c4d
394 changed files with 63458 additions and 0 deletions

22
.editorconfig Normal file
View file

@ -0,0 +1,22 @@
# For the full list of code style requirements, see CONTRIBUTING.md
root = true
[*]
charset = utf-8
end_of_line = lf
[*.{c,h,cmake,txt}]
indent_style = tab
indent_size = 4
[*.{xml,yml}]
indent_style = space
indent_size = 2
[config]
indent_style = space
indent_size = 4
[*.md]
trim_trailing_whitespace = false

34
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,34 @@
---
name: Bugs
about: Crashes and other bugs
labels: 'bug'
---
### Please read the following before submitting:
- Proprietary graphics drivers, including nvidia, are not supported. Please use the open source equivalents, such as nouveau, if you would like to use Sway.
- Please do NOT submit issues for information from the github wiki. The github wiki is community maintained and therefore may contain outdated information, scripts that don't work or obsolete workarounds.
If you fix a script or find outdated information, don't hesitate to adjust the wiki page.
### Please fill out the following:
- **Swayfx Version:**
- `sway -v`
- **Debug Log:**
- Run `sway -d 2> ~/sway.log` from a TTY and upload it to a pastebin, such as gist.github.com.
- This will record information about sway's activity. Please try to keep the reproduction as brief as possible and exit sway.
- Attach the **full** file, do not truncate it.
- **Configuration File:**
- Please try to produce with the default configuration.
- If you cannot reproduce with the default configuration, please try to find the minimal configuration to reproduce.
- Upload the config to a pastebin such as gist.github.com.
- **Stack Trace:**
- This is only needed if sway crashes.
- If you use systemd, you should be able to open the coredump of the most recent crash with gdb with
`coredumpctl gdb sway` and then `bt full` to obtain the stack trace.
- If the lines mentioning sway or wlroots have `??` for the location, your binaries were built without debug symbols. Please compile both sway and wlroots from source and try to reproduce.
- **Description:**
- The steps you took in plain English to reproduce the problem.

2
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,2 @@
blank_issues_enabled: false

10
.github/ISSUE_TEMPLATE/enhancement.md vendored Normal file
View file

@ -0,0 +1,10 @@
---
name: Enhancements
about: New functionality
labels: 'enhancement'
---
### Please fill out the following:
- **Description:**
Please describe in plain English what the enhancement is and what the use case is.

18
.gitignore vendored Normal file
View file

@ -0,0 +1,18 @@
install_manifest.txt
*.swp
*.o
*.a
bin/
test/
build/
build-*/
.cache/
.lvimrc
config-debug
wayland-*-protocol.*
/subprojects/wlroots
subprojects
result
# ignore the build output from build.sh
opt/

245
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,245 @@
# Contributing to sway
Contributing just involves sending a pull request. You will probably be more
successful with your contribution if you visit #sway-devel on Libera Chat
upfront and discuss your plans.
Note: rules are made to be broken. Adjust or ignore any/all of these as you see
fit, but be prepared to justify it to your peers.
## Scope of future changes to sway
**Important**: Sway has completed its core value proposition: it is a fully
featured Wayland-compatible replacement for i3. It is not our intention to
expand on the scope of what i3 aims to accomplish. Our priorities now are
increasing the stability, reliability, and performance of sway within its
current scope. For this reason, most new window management feature requests are
not accepted, even if accompanied by a patch.
## Pull Requests
If you already have your own pull request habits, feel free to use them. If you
don't, however, allow me to make a suggestion: feature branches pulled from
upstream. Try this:
1. Fork sway
2. `git clone https://github.com/username/sway && cd sway`
3. `git remote add upstream https://github.com/swaywm/sway`
You only need to do this once. You're never going to use your fork's master
branch. Instead, when you start working on a feature, do this:
1. `git fetch upstream`
2. `git checkout -b add-so-and-so-feature upstream/master`
3. Add and commit your changes
4. `git push -u origin add-so-and-so-feature`
5. Make a pull request from your feature branch
When you submit your pull request, your commit log should do most of the talking
when it comes to describing your changes and their motivation. In addition to
this, your pull request's comments will ideally include a test plan that the
reviewers can use to (1) demonstrate the problem on master, if applicable and
(2) verify that the problem no longer exists with your changes applied (or that
your new features work correctly). Document all of the edge cases you're aware
of so we can adequately test them - then verify the test plan yourself before
submitting.
## Commit Messages
Please strive to write good commit messages. Here's some guidelines to follow:
The first line should be limited to 50 characters and should be a sentence that
completes the thought [When applied, this commit will...] *"Implement
cmd_move"* or *"Fix #742"* or *"Improve performance of arrange_windows on ARM"*
or similar.
The subsequent lines should be separated from the subject line by a single
blank line, and include optional details. In this you can give justification
for the change, [reference Github
issues](https://help.github.com/articles/closing-issues-via-commit-messages/),
or explain some of the subtler details of your patch. This is important because
when someone finds a line of code they don't understand later, they can use the
`git blame` command to find out what the author was thinking when they wrote
it. It's also easier to review your pull requests if they're separated into
logical commits that have good commit messages and justify themselves in the
extended commit description.
As a good rule of thumb, anything you might put into the pull request
description on Github is probably fair game for going into the extended commit
message as well.
See [here](https://chris.beams.io/posts/git-commit/) for more details.
## Code Review
When your changes are submitted for review, one or more core committers will
look over them. Smaller changes might be merged with little fanfare, but larger
changes will typically see review from several people. Be prepared to receive
some feedback - you may be asked to make changes to your work. Our code review
process is:
1. **Triage** the pull request. Do the commit messages make sense? Is a test
plan necessary and/or present? Add anyone as reviewers that you think should
be there (using the relevant GitHub feature, if you have the permissions, or
with an @mention if necessary).
2. **Review** the code. Look for code style violations, naming convention
violations, buffer overflows, memory leaks, logic errors, non-portable code
(including GNU-isms), etc. For significant changes to the public API, loop in
a couple more people for discussion.
3. **Execute** the test plan, if present.
4. **Merge** the pull request when all reviewers approve.
5. **File** follow-up tickets if appropriate.
## Style Reference
Sway is written in C with a style similar to the [kernel
style](https://www.kernel.org/doc/Documentation/process/coding-style.rst), but
with a few notable differences.
Try to keep your code conforming to C11 and POSIX as much as possible, and do
not use GNU extensions.
### Brackets
Brackets always go on the same line, including in functions.
Always include brackets for if/while/for, even if it's a single statement.
```c
void function(void) {
if (condition1) {
do_thing1();
}
if (condition2) {
do_thing2();
} else {
do_thing3();
}
}
```
### Indentation
Indentations are a single tab.
For long lines that need to be broken, the continuation line should be indented
with an additional tab.
If the line being broken is opening a new block (functions, if, while, etc.),
the continuation line should be indented with two tabs, so they can't be
misread as being part of the block.
```c
really_long_function(argument1, argument2, ...,
argument3, argument4);
if (condition1 && condition2 && ...
condition3 && condition4) {
do_thing();
}
```
Try to break the line in the place which you think is the most appropriate to
balance the lines.
### Line Length
Try to keep your lines under 80 columns, assuming a tab width equal to 4 spaces,
but you can go up to 100 if it improves readability. Don't break lines
indiscriminately, try to find nice breaking points so your code is easy to read.
### Names
Global function and type names should be prefixed with `sway_submodule_` (e.g.
`struct sway_output`, `sway_output_destroy`). For static functions and
types local to a file, the names chosen aren't as important. Static functions
shouldn't have a `sway_` prefix.
For include guards, use the header's filename relative to include. Uppercase
all of the characters, and replace any invalid characters with an underscore.
### Construction/Destruction Functions
For functions that are responsible for constructing and destructing an object,
they should be written as a pair of one of two forms:
* `init`/`finish`: These initialize/deinitialize a type, but are **NOT**
responsible for allocating it. They should accept a pointer to some
pre-allocated memory (e.g. a member of a struct).
* `create`/`destroy`: These also initialize/deinitialize, but will return a
pointer to a `malloc`ed chunk of memory, and will `free` it in `destroy`.
A destruction function should always be able to accept a NULL pointer or a
zeroed value and exit cleanly; this simplifies error handling a lot.
### Error Codes
For functions not returning a value, they should return a (stdbool.h) bool to
indicated if they succeeded or not.
### Macros
Keep the use of macros to a minimum, especially if a function can do the job. If
you do need to use them, try to keep them close to where they're being used and
`#undef` them after.
### Example
```c
struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) {
struct wlr_backend *backend;
if (getenv("WAYLAND_DISPLAY") || getenv("_WAYLAND_DISPLAY")) {
backend = attempt_wl_backend(display);
if (backend) {
return backend;
}
}
const char *x11_display = getenv("DISPLAY");
if (x11_display) {
return wlr_x11_backend_create(display, x11_display);
}
// Attempt DRM+libinput
struct wlr_session *session = wlr_session_create(display);
if (!session) {
wlr_log(WLR_ERROR, "Failed to start a DRM session");
return NULL;
}
int gpu = wlr_session_find_gpu(session);
if (gpu == -1) {
wlr_log(WLR_ERROR, "Failed to open DRM device");
goto error_session;
}
backend = wlr_multi_backend_create(session);
if (!backend) {
goto error_gpu;
}
struct wlr_backend *libinput = wlr_libinput_backend_create(display, session);
if (!libinput) {
goto error_multi;
}
struct wlr_backend *drm = wlr_drm_backend_create(display, session, gpu);
if (!drm) {
goto error_libinput;
}
wlr_multi_backend_add(backend, libinput);
wlr_multi_backend_add(backend, drm);
return backend;
error_libinput:
wlr_backend_destroy(libinput);
error_multi:
wlr_backend_destroy(backend);
error_gpu:
wlr_session_close_file(session, gpu);
error_session:
wlr_session_destroy(session);
return NULL;
}
```

95
Dockerfile Normal file
View file

@ -0,0 +1,95 @@
# syntax=docker.io/docker/dockerfile:1
ARG BASE_IMAGE=docker.io/debian:trixie
FROM ${BASE_IMAGE}
SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"]
ENV LANG=C.UTF-8
RUN <<EOF
apt-get update
apt-get --yes install --no-install-recommends \
build-essential \
cmake \
cdbs \
devscripts \
equivs \
meson \
wayland-protocols \
libwayland-dev \
libwayland-bin \
libwayland-client0 \
libdrm-dev \
libxkbcommon-dev \
libudev-dev \
hwdata \
libseat-dev \
libgles-dev \
libavutil-dev \
libavcodec-dev \
libavformat-dev \
libgbm-dev \
xwayland \
libxcb-composite0-dev \
libxcb-icccm4-dev \
libxcb-res0-dev \
libxcb-errors-dev \
libinput-dev \
libxcb-present-dev \
libxcb-render-util0-dev \
libxcb-xinput-dev \
glslang-tools \
glslang-dev \
libpcre2-dev \
libjson-c-dev \
libgdk-pixbuf-2.0-dev \
libsystemd-dev \
scdoc \
bash-completion \
libpango1.0-dev \
libcairo2-dev \
libxcb-ewmh-dev \
libdisplay-info-dev \
libliftoff-dev \
liblcms2-dev \
libvulkan-dev \
wget \
bash \
git \
ca-certificates
EOF
WORKDIR /build
ARG WLROOTSVERSION WLROOTSLIBVERSION SWAYFXVERSION SCENEFXVERSION SCENEFXLIBVERSION OPT_SWAYFX
ENV WLROOTSVERSION=${WLROOTSVERSION}
ENV WLROOTSLIBVERSION=${WLROOTSLIBVERSION}
ENV SWAYFXVERSION=${SWAYFXVERSION}
ENV SCENEFXVERSION=${SCENEFXVERSION}
ENV SCENEFXLIBVERSION=${SCENEFXLIBVERSION}
ENV OPT_SWAYFX=${OPT_SWAYFX}
RUN <<EOF
wget "https://gitlab.freedesktop.org/wlroots/wlroots/-/archive/${WLROOTSVERSION}/wlroots-${WLROOTSVERSION}.tar.gz"
tar -xf "wlroots-${WLROOTSVERSION}.tar.gz"
rm "wlroots-${WLROOTSVERSION}.tar.gz"
EOF
RUN <<EOF
wget "https://github.com/WillPower3309/swayfx/archive/refs/tags/${SWAYFXVERSION}.tar.gz"
tar -xf "${SWAYFXVERSION}.tar.gz"
rm "${SWAYFXVERSION}.tar.gz"
EOF
RUN <<EOF
wget "https://github.com/wlrfx/scenefx/archive/refs/tags/${SCENEFXVERSION}.tar.gz"
tar -xf "${SCENEFXVERSION}.tar.gz"
rm "${SCENEFXVERSION}.tar.gz"
EOF
COPY build.sh .
RUN chmod 755 build.sh
ENTRYPOINT ["/build/build.sh"]

97
INSTALL-deb.md Normal file
View file

@ -0,0 +1,97 @@
# A guide to installing SwayFX on Debian 13 (Trixie/Sid)
> **Note:** This guide targets **SwayFX 0.5.3** (based on Sway 1.11). It manually builds the required dependencies (**wlroots 0.19.0** and **scenefx 0.4.1**) using Meson subprojects to ensure compatibility and stability.
## 1\. Install Dependencies
Debian Trixie requires a specific set of development headers, particularly for the newer `wlroots` 0.19 backend (which needs `liblcms2`, `libliftoff`, and `libdisplay-info`).
```bash
sudo apt update && sudo apt install -y \
meson pkg-config cmake git scdoc \
wayland-protocols libwayland-dev libpcre2-dev libjson-c-dev \
libpango1.0-dev libcairo2-dev libgdk-pixbuf-2.0-dev \
libdrm-dev libgbm-dev libinput-dev libseat-dev libxkbcommon-dev \
libxcb-dri3-dev libxcb-present-dev libxcb-res0-dev \
libxcb-render-util0-dev libxcb-ewmh-dev libxcb-icccm4-dev \
libliftoff-dev libdisplay-info-dev liblcms2-dev libpixman-1-dev \
libgles2-mesa-dev hwdata libudev-dev
```
## 2\. Setup Build Environment
We will use the **Meson Subprojects** method. This places the specific versions of `wlroots` and `scenefx` directly inside the build folder, preventing conflicts with system libraries.
```bash
# Create a clean build directory
mkdir -p ~/build
cd ~/build
# 1. Clone SwayFX 0.5.3 (The Window Manager)
git clone https://github.com/WillPower3309/swayfx.git
cd swayfx
git checkout 0.5.3
# 2. Setup Subprojects Directory
mkdir subprojects
cd subprojects
# 3. Clone SceneFX 0.4.1 (The Rendering FX Library)
# Note: 0.4.1 is required for wlroots 0.19 support
git clone https://github.com/wlrfx/scenefx.git
cd scenefx
git checkout 0.4.1
cd ..
# 4. Clone Wlroots 0.19.0 (The Wayland Compositor Backend)
git clone https://gitlab.freedesktop.org/wlroots/wlroots.git
cd wlroots
git checkout 0.19.0
# Return to source root
cd ../..
```
Your directory structure should now look like this:
```text
~/build/swayfx
└── subprojects
├── scenefx (v0.4.1)
└── wlroots (v0.19.0)
```
## 3\. Compile and Install
Now we build everything in one go. Meson will detect the code in `subprojects/` and build it automatically.
```bash
# Configure the build
meson setup build/
# Compile
ninja -C build/
# Install
sudo ninja -C build/ install
```
## 4\. Finalize
Debian does not automatically link new libraries in `/usr/local/lib` immediately. You must update the linker cache to avoid "shared object not found" errors.
```bash
sudo ldconfig
```
## 5\. Verification
Check that the installation was successful and is using the correct version base.
```bash
sway --version
# Expected Output:
# swayfx version 0.5.3... (based on sway 1.11.0)
```
+ Guide updated for Debian 13 / SwayFX 0.5.3 with ♥️

19
LICENSE Normal file
View file

@ -0,0 +1,19 @@
Copyright (c) 2016-2017 Drew DeVault
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.

166
README.md Normal file
View file

@ -0,0 +1,166 @@
<p align="center">
<img src="assets/swayfx_logo.svg" width="256" alt="swayfx logo">
</p>
Sway is an incredible window manager, and certainly one of the most well established wayland window managers. However, it is restricted to only include the functionality that existed in i3. This fork ditches the simple wlr_renderer, and replaces it with our fx_renderer, capable of rendering with fancy GLES2 effects. This, along with a couple of minor changes, expands sway's featureset to include the following:
+ **Blur**
+ **Anti-aliased rounded corners, borders, and titlebars**
+ **Shadows**
+ **Dim unfocused windows**
+ **Scratchpad treated as minimize**: Allows docks, or panels with a taskbar, to correctly interpret minimize / unminimize requests ([thanks to LCBCrion](https://github.com/swaywm/sway/issues/6457))
+ **nixify the repo**: Allows nixos users to easily contribute to and test this project
<p align="center">
<a href="https://repology.org/project/swayfx/versions"><img src="https://repology.org/badge/vertical-allrepos/swayfx.svg" height="282"/></a>
<img src="assets/swayfx_screenshot.jpg" width="500"/>
</p>
For Fedora users, SwayFX is also available in [copr](https://copr.fedorainfracloud.org/coprs/swayfx/swayfx/) or in the [Terra repository](https://terra.fyralabs.com).
[Join our Discord](https://discord.gg/qsSx397rkh)
## New Configuration Options
+ Window blur:
- `blur enable|disable`
- `blur_xray enable|disable`: this will set floating windows to blur based on the background, not the windows below. You probably want to set this to `disable` :)
- `blur_passes <integer value 0 - 10>`
- `blur_radius <integer value 0 - 10>`
- `blur_noise <float value 0 - 1>`
- `blur_brightness <float value 0 - 2>`
- `blur_contrast <float value 0 - 2>`
- `blur_saturation <float value 0 - 2>`
+ Corner radius: `corner_radius <val>`
+ Window shadows:
- `shadows enable|disable`
- `shadows_on_csd enable|disable` (**Note**: The shadow might not fit some windows)
- `shadow_blur_radius <integer value 0 - 99>`
- `shadow_color <hex color with alpha> ex, #0000007F`
- `shadow_offset <x offset> <y offset>`
- `shadow_inactive_color <hex color with alpha> ex, #0000007F`
+ LayerShell effects (to blur panels / notifications etc):
- `layer_effects <layer namespace> <effects>`
- The current layer namespaces can be shown with `swaymsg -r -t get_outputs | jq '.[0].layer_shell_surfaces | .[] | .namespace'`
- Example: `layer_effects "waybar" blur enable; shadows enable; corner_radius 6`
- Note: If an application uses gtk, its namespace is likely to be "gtk-layer-shell"
- SwayIPC Example: `swaymsg layer_effects "waybar" "blur enable"` (you can only set one effect at a time through `swaymsg`)
- Config Example:
```
layer_effects "waybar" {
blur enable;
blur_xray enable;
blur_ignore_transparent enable;
shadows enable;
corner_radius 20;
}
```
- Available Effects:
- `blur <enable|disable>`
- `blur_xray <enable|disable>`
- `blur_ignore_transparent <enable|disable>`
- `shadows <enable|disable>`
- `corner_radius <int>`
- `reset`: To reset/disable all previously applied effects to the layer application
+ Dim unfocused windows:
- `default_dim_inactive <float value 0.0 - 1.0>`
- `for_window [CRITERIA_HERE] dim_inactive <float value 0.0 - 1.0>`
- `dim_inactive_colors.unfocused <hex color> ex, #000000FF`
- `dim_inactive_colors.urgent <hex color> ex, #900000FF`
+ Keep/remove separator border between titlebar and content: `titlebar_separator enable|disable`
+ Treat Scratchpad as minimized: `scratchpad_minimize enable|disable`: **we recommend keeping this setting off, as there are many kinks to iron out here**
## Roadmap
+ fade in / out animations
+ window movement animations
## Compiling From Source
### Nix
If you have Nix installed, you can build and run SwayFX easily:
```
nix build
./result/bin/sway
```
You can also bring up a development shell and follow the build instructions below, without installing all of the dependencies manually:
```
nix develop
```
### Debian
Check [INSTALL-deb.md](/INSTALL-deb.md)
### Container (Docker)
To build SwayFX inside a container, install Docker and run the following commands from inside this repository:
```bash
# build the container and run it (which builds SwayFX)
docker compose up --build
# become root to install the previously built files
sudo bash
# copy all files into the host file system at /usr/local/
while read -r FILE; do
NEW_FILE=/usr/local${FILE#opt}
NEW_DIR=$(dirname "${NEW_FILE}")
[[ -d ${NEW_DIR} ]] || mkdir -p "${NEW_DIR}"
echo "Creating '${NEW_FILE}'"
cp "${FILE}" "${NEW_FILE}"
done < <(command find opt/ -type f)
```
### Manual Steps
Install dependencies:
* meson \*
* wlroots
* wayland
* wayland-protocols \*
* pcre2
* json-c
* pango
* cairo
* [scenefx](https://github.com/wlrfx/scenefx)
* gdk-pixbuf2 (optional: additional image formats for system tray)
* [swaybg] (optional: wallpaper)
* [scdoc] (optional: man pages) \*
* git (optional: version info) \*
_\* Compile-time dep_
Run these commands:
meson build/
ninja -C build/
sudo ninja -C build/ install
On systems without logind nor seatd, you need to suid the sway binary:
sudo chmod a+s /usr/local/bin/sway
SwayFX will drop root permissions shortly after startup.
## Contributing
SwayFX would love to receive any new features that you're willing to build! Generally, we'd like to focus on eye-candy type improvements to keep our scope appropriate. If you'd like to build something that you think may be out of that focus, please raise an issue and we can discuss whether or not it will fit within this project.
## Acknowledgements
The SwayFX team would like to first and foremost thank the maintainers and contributors of the Sway window manager. We are but a humble group of Sway enthusiasts who wanted to expand upon your creation.
We would also like to thank the talented artists in our community for contibuting the visual assets that give this project charm:
+ pkdesuwu and honchokomodo for creating the swayfx mascot: https://twitter.com/pkdesuwu/status/1664517033017368576
+ spooky_skeleton for the swayfx logo, and [Basil](https://basil.cafe) for making some fine adjustments to it
Lastly, we would like to thank you, the community, for enjoying and using window manager that we have spent so much time maintaining.

121
assets/LICENSE Normal file
View file

@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

191
assets/swayfx_logo.svg Normal file
View file

@ -0,0 +1,191 @@
<svg width="460" height="540" viewBox="0 0 460 540" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_dd_1507_417)">
<path d="M115.288 499.64C109.869 499.64 104.792 498.616 100.056 496.568C99.544 496.355 99.1173 496.013 98.776 495.544C98.4347 495.032 98.264 494.499 98.264 493.944C98.264 493.219 98.4987 492.6 98.968 492.088C99.48 491.533 100.12 491.256 100.888 491.256C101.315 491.256 101.72 491.341 102.104 491.512C106.029 493.261 110.232 494.136 114.712 494.136C122.179 494.136 125.912 491.683 125.912 486.776C125.912 485.496 125.421 484.429 124.44 483.576C123.501 482.723 122.328 482.061 120.92 481.592C119.512 481.08 117.507 480.483 114.904 479.8C111.448 478.904 108.653 478.051 106.52 477.24C104.387 476.387 102.552 475.128 101.016 473.464C99.48 471.8 98.712 469.581 98.712 466.808C98.712 464.376 99.352 462.179 100.632 460.216C101.912 458.211 103.789 456.632 106.264 455.48C108.781 454.285 111.789 453.688 115.288 453.688C119.981 453.688 124.227 454.392 128.024 455.8C129.219 456.227 129.816 457.08 129.816 458.36C129.816 459.043 129.581 459.661 129.112 460.216C128.643 460.771 128.024 461.048 127.256 461.048C127 461.048 126.659 460.963 126.232 460.792C122.904 459.64 119.469 459.064 115.928 459.064C112.557 459.064 109.805 459.704 107.672 460.984C105.581 462.264 104.536 464.056 104.536 466.36C104.536 467.896 105.027 469.155 106.008 470.136C107.032 471.075 108.291 471.821 109.784 472.376C111.32 472.888 113.389 473.443 115.992 474.04C119.363 474.851 122.072 475.661 124.12 476.472C126.211 477.283 127.981 478.541 129.432 480.248C130.925 481.955 131.672 484.259 131.672 487.16C131.672 489.549 130.989 491.704 129.624 493.624C128.259 495.501 126.339 496.973 123.864 498.04C121.389 499.107 118.531 499.64 115.288 499.64ZM147.159 499.32C146.306 499.32 145.538 499.064 144.855 498.552C144.172 498.04 143.703 497.4 143.447 496.632L134.359 470.008C134.231 469.624 134.167 469.261 134.167 468.92C134.167 468.109 134.444 467.427 134.999 466.872C135.554 466.317 136.236 466.04 137.047 466.04C137.644 466.04 138.178 466.211 138.647 466.552C139.159 466.851 139.5 467.256 139.671 467.768L147.159 492.408L154.583 468.344C154.796 467.661 155.18 467.107 155.735 466.68C156.332 466.253 156.994 466.04 157.719 466.04C158.444 466.04 159.084 466.253 159.639 466.68C160.236 467.107 160.642 467.661 160.855 468.344L168.279 492.408L175.767 467.768C175.938 467.256 176.258 466.851 176.727 466.552C177.239 466.211 177.794 466.04 178.391 466.04C179.202 466.04 179.884 466.317 180.439 466.872C180.994 467.427 181.271 468.109 181.271 468.92C181.271 469.261 181.207 469.624 181.079 470.008L171.991 496.632C171.735 497.4 171.266 498.04 170.583 498.552C169.9 499.064 169.132 499.32 168.279 499.32C167.426 499.32 166.658 499.064 165.975 498.552C165.292 498.04 164.802 497.379 164.503 496.568L157.719 475.384L150.935 496.568C150.636 497.379 150.146 498.04 149.463 498.552C148.78 499.064 148.012 499.32 147.159 499.32ZM196.064 499.64C194.186 499.64 192.437 499.256 190.816 498.488C189.237 497.72 187.978 496.611 187.04 495.16C186.101 493.667 185.632 491.96 185.632 490.04C185.632 486.883 186.869 484.365 189.344 482.488C191.861 480.611 195.53 479.672 200.352 479.672H208.096V479.16C208.096 476.344 207.392 474.317 205.984 473.08C204.618 471.843 202.464 471.224 199.52 471.224C197.898 471.224 196.448 471.352 195.168 471.608C193.93 471.864 192.544 472.248 191.008 472.76C190.666 472.845 190.389 472.888 190.176 472.888C189.536 472.888 188.981 472.653 188.512 472.184C188.042 471.715 187.808 471.139 187.808 470.456C187.808 469.304 188.362 468.493 189.472 468.024C193.098 466.488 196.789 465.72 200.544 465.72C203.488 465.72 205.962 466.317 207.968 467.512C210.016 468.707 211.509 470.264 212.448 472.184C213.429 474.061 213.92 476.109 213.92 478.328V496.44C213.92 497.251 213.621 497.933 213.024 498.488C212.469 499.043 211.786 499.32 210.976 499.32C210.165 499.32 209.482 499.043 208.928 498.488C208.373 497.933 208.096 497.251 208.096 496.44V494.776C204.938 498.019 200.928 499.64 196.064 499.64ZM198.24 494.52C200.117 494.52 201.93 494.072 203.68 493.176C205.429 492.237 206.901 491.085 208.096 489.72V484.344H201.12C194.677 484.344 191.456 486.029 191.456 489.4C191.456 490.936 191.968 492.173 192.992 493.112C194.058 494.051 195.808 494.52 198.24 494.52ZM230.415 514.04C229.647 514.04 228.985 513.763 228.431 513.208C227.919 512.653 227.663 511.992 227.663 511.224C227.663 510.883 227.727 510.541 227.855 510.2L232.015 499.512L219.983 470.2C219.812 469.773 219.727 469.368 219.727 468.984C219.727 468.173 220.004 467.491 220.559 466.936C221.113 466.339 221.796 466.04 222.607 466.04C223.204 466.04 223.737 466.211 224.207 466.552C224.719 466.893 225.081 467.32 225.295 467.832L235.151 492.28L245.199 467.96C245.753 466.68 246.649 466.04 247.887 466.04C248.697 466.04 249.38 466.339 249.935 466.936C250.489 467.491 250.767 468.173 250.767 468.984C250.767 469.368 250.703 469.731 250.575 470.072L233.103 512.056C232.505 513.379 231.609 514.04 230.415 514.04Z" fill="#49D1F8"/>
</g>
<g filter="url(#filter1_dd_1507_417)">
<path d="M275.784 489C275.784 488.872 275.784 488.744 275.848 488.552C273.928 488.936 272.072 489.384 270.216 489.832C268.68 490.152 267.144 490.536 265.608 490.984C265.224 491.048 264.904 491.304 264.584 491.432C263.304 491.688 262.088 491.944 260.872 491.56C260.808 491.56 260.744 491.56 260.744 491.56C260.424 491.304 260.168 491.048 259.848 490.792C260.104 490.472 260.296 490.088 260.616 489.96C262.792 488.744 265.16 488.04 267.592 487.4C270.408 486.696 273.288 485.992 276.168 485.288C276.552 485.16 276.744 484.968 276.872 484.584C277.32 482.536 277.896 480.488 278.28 478.44C278.472 477.672 278.344 476.776 278.216 475.944C277.192 470.376 273.928 466.664 268.68 464.616C265.736 463.464 262.728 462.824 259.656 462.184C257.928 461.8 256.2 461.288 254.472 460.776C253.896 460.648 253.384 460.328 252.936 459.944C251.912 459.176 251.656 458.088 252.36 457C252.936 456.168 253.64 455.4 254.408 454.76C256.84 452.84 259.592 451.432 262.344 450.152C268.936 447.016 275.848 444.648 282.888 442.6C291.784 439.912 300.808 437.736 309.896 436.008C317.704 434.536 325.448 433.192 333.256 431.784C334.344 431.592 335.432 431.336 336.52 431.08C336.904 431.016 337.224 430.824 337.608 430.696C339.336 429.928 341.064 429.864 342.856 430.632C343.88 431.144 343.88 431.784 343.176 432.744C342.536 433.64 341.704 433.64 340.744 433.704C339.848 433.832 338.952 434.152 338.056 434.344C333.64 435.112 329.224 435.88 324.808 436.648C309.448 439.208 294.28 442.216 279.432 447.016C273.992 448.808 268.488 450.728 263.368 453.352C261.64 454.248 260.04 455.336 258.376 456.36C257.928 456.68 257.544 457.128 257.224 457.512C256.52 458.408 256.712 459.112 257.736 459.432C258.952 459.88 260.168 460.2 261.384 460.456C264.648 461.288 267.976 461.992 271.176 463.272C273.736 464.296 276.232 465.576 278.088 467.688C278.856 468.584 279.496 469.608 280.2 470.632C280.456 469.736 280.712 468.776 280.904 467.816C282.376 462.184 283.72 456.488 285.576 450.92C285.96 449.832 286.472 448.68 286.92 447.592C287.24 446.568 288.008 446.12 288.968 446.12C289.736 446.12 290.568 446.184 291.272 446.376C292.296 446.696 292.488 447.144 292.296 448.168C291.848 450.28 291.4 452.392 290.952 454.568C290.696 455.592 290.568 456.616 290.312 457.64C289.992 459.048 289.544 460.456 289.224 461.928C287.624 468.904 286.088 475.88 284.488 482.856C284.424 482.984 284.424 483.176 284.36 483.368C284.872 483.304 285.32 483.176 285.768 483.112C288.776 482.536 291.72 481.96 294.728 481.448C296.072 481.192 297.416 481.192 298.76 481.576C299.208 481.768 299.72 482.024 300.104 482.344C300.616 482.792 300.616 483.304 300.04 483.752C299.784 483.944 299.528 484.136 299.272 484.264C296.904 485.416 294.536 486.376 291.976 486.696C290.632 486.888 289.288 486.888 288.072 486.184C287.944 486.12 287.752 486.12 287.56 486.184C286.344 486.376 285.128 486.632 283.912 486.888C283.72 486.952 283.528 487.144 283.464 487.336C281.992 493.224 280.52 499.112 279.112 505.064C278.792 506.344 278.6 507.624 278.28 508.904C277.64 511.144 276.296 513.064 275.08 515.048C274.888 515.368 274.376 515.624 273.928 515.688C272.904 515.944 271.944 515.816 270.984 515.304C270.6 515.112 270.344 514.856 270.472 514.344C271.88 507.624 273.224 500.84 274.632 494.056C274.952 492.328 275.4 490.664 275.784 489ZM326.957 480.744C326.445 479.912 325.997 479.08 325.485 478.184C324.845 478.888 324.269 479.592 323.693 480.232C317.869 487.144 312.365 494.312 307.309 501.8C306.221 503.4 305.389 505.128 304.429 506.856C304.429 506.92 304.365 506.984 304.365 507.048C303.981 507.496 302.701 507.688 301.869 507.304C301.229 507.048 300.909 506.472 301.165 505.768C301.421 504.872 301.741 504.04 302.125 503.272C304.685 498.6 307.181 493.928 310.189 489.64C313.453 484.968 317.101 480.616 320.749 476.264C321.389 475.496 322.029 474.728 322.733 473.96C323.053 473.64 323.053 473.384 322.861 473C320.685 468.52 318.701 463.976 317.357 459.24C316.781 457.192 316.269 455.08 315.885 453.032C315.565 451.304 316.077 450.728 317.741 450.6C318.061 450.6 318.317 450.6 318.637 450.6C319.661 450.664 320.429 451.112 320.813 452.2C322.157 455.912 323.565 459.624 325.037 463.272C325.677 464.936 326.381 466.6 327.085 468.2C327.149 468.392 327.213 468.52 327.341 468.712C327.597 468.392 327.789 468.2 328.045 467.944C335.597 459.432 343.853 451.496 352.237 443.816C354.477 441.832 356.589 439.848 358.829 437.864C360.685 436.328 362.861 435.752 365.293 436.328C366.957 436.776 367.021 437.8 366.125 439.08C365.677 439.848 364.909 440.424 364.269 441C359.021 445.608 353.773 450.216 348.525 454.824C342.125 460.584 336.045 466.664 330.157 473C329.453 473.768 329.453 473.448 329.965 474.408C335.085 484.584 340.845 494.376 347.885 503.336C349.037 504.872 350.189 506.408 351.341 507.944C351.789 508.456 351.661 508.776 351.021 508.968C349.997 509.224 349.037 509.096 348.205 508.264C339.885 500.072 332.589 491.048 326.957 480.744Z" fill="#FF7070"/>
</g>
<g filter="url(#filter2_dd_1507_417)">
<path d="M229.232 390.316L230.299 390.722L231.367 390.316L432.8 313.701V338.646L230.301 415.901L28 338.646V313.665L229.232 390.316Z" stroke="#FF7070" stroke-width="6"/>
</g>
<g filter="url(#filter3_dd_1507_417)">
<path d="M66.5 289.434C62.7345 290.794 58.9314 292.097 55.16 293.389C50.774 294.892 46.43 296.38 42.181 297.947C40.962 298.369 37.071 299.857 33.363 301.287L230.301 376.302L427.398 301.336C417.116 297.431 406.906 293.62 396.714 289.815C378.857 283.15 361.052 276.504 343.002 269.404L342.992 269.4C313.96 257.867 283.919 249.923 253.174 255.757C245.264 257.339 237.513 259.546 229.65 261.785C228.961 261.981 228.272 262.177 227.582 262.373C219.05 264.796 210.378 267.19 201.493 268.671L201.474 268.674L201.455 268.677C193.53 269.893 185.838 269.246 178.403 268.379C177.111 268.229 175.83 268.072 174.557 267.917C168.399 267.164 162.414 266.432 156.242 266.512C139.521 266.761 122.728 269.589 106.5 274.378" stroke="#F5E755" stroke-width="6" stroke-linecap="round"/>
</g>
<g filter="url(#filter4_dd_1507_417)">
<path d="M186.455 188.736C187.159 188.349 187.86 187.965 188.563 187.579C207.223 177.396 227.746 165.892 242.459 150.898C251.254 141.935 257.901 131.804 260.791 120L251.073 117C247.695 132.008 236.928 144.049 224.313 153.602C209.23 165.045 192.372 174.082 175.789 182.972L175.783 182.975L175.704 183.017C169.762 186.203 163.856 189.369 158.078 192.623C117.392 215.759 76.605 251.626 78.595 301.132C78.87 304.42 81.46 306.187 84.388 306.187C85.841 306.187 87.104 305.72 87.932 304.98C88.689 304.304 89.288 303.229 89.204 301.455L89.203 301.443C87.161 254.895 123.715 225.552 159.427 204.058C160.354 203.5 163 204.058 163 204.058C199.6 211.687 238.997 207.877 272.5 192.731L249.5 190.607C227.885 197.443 204.884 199.835 182.222 197.282C180.924 197.136 179.87 196.166 179.615 194.885C179.361 193.603 179.966 192.305 181.11 191.674C182.911 190.681 184.696 189.701 186.455 188.736Z" stroke="#FEDEDC" stroke-width="6" stroke-linejoin="round"/>
</g>
<g filter="url(#filter5_dd_1507_417)">
<path d="M258.177 47.973C252.162 50.673 246.09 53.167 239.968 55.682C238.658 56.22 237.346 56.759 236.031 57.301C228.599 60.366 221.125 63.522 213.783 67.116C211.358 68.297 208.326 69.991 205.009 71.846C204.329 72.225 203.638 72.612 202.937 73.002C198.761 75.327 194.159 77.839 189.465 80.063C184.763 82.292 180.055 84.189 175.681 85.314C171.277 86.447 167.461 86.731 164.416 85.999C163.059 85.658 161.842 85.108 161.121 84.507L161.028 84.43L160.93 84.361C159.252 83.177 158.253 81.222 158.038 78.831C157.822 76.42 158.44 73.796 159.747 71.698L159.761 71.674L159.775 71.651C162.102 67.758 166.125 63.75 170.814 60.072C175.466 56.423 180.586 53.243 184.901 50.965L184.913 50.958C196.538 44.752 208.65 39.73 221.148 35.99C222.596 35.569 224.039 35.145 225.479 34.723C236.493 31.488 247.298 28.316 258.401 27.197L258.416 27.195L258.431 27.194C261.326 26.872 267.423 26.828 272.629 28.046C275.243 28.657 277.355 29.524 278.732 30.606C279.998 31.602 280.558 32.684 280.502 34.094L280.501 34.135L280.5 34.175C280.489 35.057 279.977 36.236 278.413 37.723C276.878 39.182 274.673 40.603 272.119 41.943C268.586 43.797 264.966 45.23 261.993 46.408C260.537 46.985 259.236 47.5 258.177 47.973Z" stroke="#C7E133" stroke-width="6"/>
</g>
<g filter="url(#filter6_dd_1507_417)">
<path d="M389.71 76.516L390.083 76.265C392.8 74.437 395.722 72.465 398.535 70.44C401.352 68.412 404.008 66.367 406.196 64.405C408.422 62.408 409.983 60.655 410.79 59.232C412.739 55.784 411.898 52.084 408.781 48.435C405.631 44.747 400.553 41.719 395.715 40.407C385.786 37.722 375.207 37.265 364.398 37.709C357.435 37.996 350.552 38.641 343.709 39.283C339.838 39.646 335.981 40.008 332.129 40.303H332.125C308.736 42.065 284.825 50.104 263.934 59.999C263.119 60.423 262.33 60.819 261.56 61.205L256.484 63.919C250.793 67.157 245.838 70.557 242.166 74.678C236.743 81.094 235.556 86.226 236.371 90.213C237.206 94.303 240.319 98.067 245.348 101.301C255.444 107.793 271.605 111.042 283.846 110.416C285.729 110.319 287.621 110.202 289.52 110.065C290.985 109.959 292.312 110.93 292.654 112.36C292.665 112.409 292.678 112.458 292.691 112.508C294.263 117.829 299.155 122.194 304.922 124.057C310.84 125.969 317.441 125.916 324.113 125.518C348.176 123.939 371.949 118.316 394.144 109.044C394.155 109.039 394.166 109.034 394.177 109.03C394.187 109.026 394.197 109.022 394.207 109.018C398.721 107.252 402.432 105.467 405.227 102.452C407.812 99.224 408.756 95.346 407.322 92.464C406.41 90.681 404.774 89.417 402.499 88.555C400.193 87.681 397.434 87.305 394.697 87.21L394.67 87.209C390.951 87.047 387.255 87.235 383.539 87.619C382.173 87.76 380.887 86.957 380.414 85.668C379.941 84.38 380.403 82.935 381.536 82.16L389.71 76.516Z" stroke="#C7E133" stroke-width="6" stroke-linejoin="round"/>
</g>
<g filter="url(#filter7_dd_1507_417)">
<path d="M311.562 204.936C311.265 203.386 311.733 201.847 313.059 200.137C314.398 198.409 316.403 196.801 318.52 195.437C324.363 191.703 340.499 183.83 356.211 179.635C364.083 177.534 371.566 176.435 377.48 177.079C383.336 177.716 387.067 179.953 388.719 184.037C389.803 186.722 389.839 188.968 389.239 190.918C388.624 192.919 387.254 194.88 385.078 196.782C380.663 200.642 373.486 203.776 365.152 206.152C356.898 208.505 347.846 210.022 339.975 210.837C332.041 211.659 325.555 211.741 322.38 211.336L322.37 211.335L322.359 211.334C319.712 211.014 317.009 210.272 314.952 209.096C312.91 207.927 311.819 206.534 311.562 204.936Z" stroke="#C7E133" stroke-width="6"/>
</g>
<g filter="url(#filter8_dd_1507_417)">
<path d="M187.525 143.975C182.106 145.895 174.583 144.865 169.358 141.584C166.794 139.974 165.019 137.968 164.219 135.783C163.45 133.681 163.455 131.074 165.072 127.877C166.558 124.994 169.678 121.27 173.963 117.393C178.205 113.554 183.406 109.731 188.842 106.615C194.297 103.487 199.861 101.144 204.839 100.147C209.861 99.142 213.86 99.583 216.651 101.418L216.665 101.427L216.678 101.435C219.596 103.312 221.015 107.453 220.433 111.366C219.484 117.612 214.631 124.654 207.988 130.872C201.407 137.03 193.586 141.893 187.525 143.975Z" stroke="#C7E133" stroke-width="6"/>
</g>
<g filter="url(#filter9_dd_1507_417)">
<path d="M261.356 181.033C259.417 180.802 257.464 180.358 255.939 179.615C254.438 178.884 253.669 178.031 253.386 177.091C253.113 176.075 253.391 174.914 254.643 173.448C255.916 171.959 257.877 170.571 259.92 169.455C267.612 165.388 275.796 161.94 284.175 159.3C284.412 159.225 284.64 159.121 284.852 158.989C285.052 158.865 285.254 158.747 285.457 158.634C285.474 158.625 285.491 158.615 285.508 158.606C308.412 145.294 335.096 138.705 361.545 138.312C361.571 138.311 361.598 138.311 361.625 138.309C363.725 138.222 365.9 138.521 367.51 139.209C369.077 139.878 369.686 140.693 369.83 141.539C369.928 142.366 369.647 143.291 368.788 144.387C367.904 145.517 366.587 146.579 365.174 147.491L365.168 147.495C355.489 153.77 344.655 158.785 333.358 162.04C332.058 162.415 331.169 163.614 331.189 164.967C331.2 165.707 331.074 166.432 330.816 167.095C329.552 170.158 326.275 171.992 321.875 173.593L321.84 173.605C302.684 180.838 281.769 183.475 261.356 181.033Z" stroke="#C7E133" stroke-width="6" stroke-linejoin="round"/>
</g>
<g filter="url(#filter10_dd_1507_417)">
<path d="M147.692 120.75L147.731 120.889C148.017 121.825 147.93 122.941 147.37 124.322C146.805 125.716 145.837 127.173 144.676 128.614C138.353 136.251 127.33 143.121 117.173 143.312C113.983 143.31 111.862 142.908 110.564 142.373C109.308 141.855 109.12 141.356 109.076 141.201C109.002 140.94 108.963 140.229 109.694 138.89C110.408 137.582 111.695 135.993 113.626 134.225L113.635 134.216C113.813 134.052 114.006 133.873 114.212 133.683C117.839 130.325 125.598 123.142 133.118 118.827C137.17 116.502 140.592 115.348 143.016 115.553C144.114 115.646 144.956 116.011 145.65 116.676C146.381 117.377 147.148 118.606 147.692 120.75Z" stroke="#C7E133" stroke-width="6"/>
</g>
<defs>
<filter id="filter0_dd_1507_417" x="74.264" y="429.688" width="200.502" height="108.352" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="6"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.286275 0 0 0 0 0.819608 0 0 0 0 0.972549 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1507_417"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="12"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.286275 0 0 0 0 0.819608 0 0 0 0 0.972549 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1507_417" result="effect2_dropShadow_1507_417"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_1507_417" result="shape"/>
</filter>
<filter id="filter1_dd_1507_417" x="227.656" y="405.864" width="163.365" height="134.08" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="4"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.439216 0 0 0 0 0.439216 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1507_417"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="12"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.439216 0 0 0 0 0.439216 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1507_417" result="effect2_dropShadow_1507_417"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_1507_417" result="shape"/>
</filter>
<filter id="filter2_dd_1507_417" x="1" y="285.312" width="458.8" height="157.8" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="6"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.439216 0 0 0 0 0.439216 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1507_417"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="12"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.439216 0 0 0 0 0.439216 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1507_417" result="effect2_dropShadow_1507_417"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_1507_417" result="shape"/>
</filter>
<filter id="filter3_dd_1507_417" x="0.980591" y="226.794" width="458.862" height="176.718" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="6"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.960784 0 0 0 0 0.905882 0 0 0 0 0.333333 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1507_417"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="12"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.960784 0 0 0 0 0.905882 0 0 0 0 0.333333 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1507_417" result="effect2_dropShadow_1507_417"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_1507_417" result="shape"/>
</filter>
<filter id="filter4_dd_1507_417" x="51.5248" y="90" width="247.975" height="243.187" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="6"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.996078 0 0 0 0 0.870588 0 0 0 0 0.862745 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1507_417"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="12"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.996078 0 0 0 0 0.870588 0 0 0 0 0.862745 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1507_417" result="effect2_dropShadow_1507_417"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_1507_417" result="shape"/>
</filter>
<filter id="filter5_dd_1507_417" x="130.996" y="0.000289917" width="176.51" height="113.402" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="6"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.780392 0 0 0 0 0.882353 0 0 0 0 0.2 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1507_417"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="12"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.780392 0 0 0 0 0.882353 0 0 0 0 0.2 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1507_417" result="effect2_dropShadow_1507_417"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_1507_417" result="shape"/>
</filter>
<filter id="filter6_dd_1507_417" x="209.137" y="10.5606" width="229.698" height="142.181" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="6"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.780392 0 0 0 0 0.882353 0 0 0 0 0.2 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1507_417"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="12"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.780392 0 0 0 0 0.882353 0 0 0 0 0.2 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1507_417" result="effect2_dropShadow_1507_417"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_1507_417" result="shape"/>
</filter>
<filter id="filter7_dd_1507_417" x="284.475" y="149.896" width="132.153" height="88.6769" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="6"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.780392 0 0 0 0 0.882353 0 0 0 0 0.2 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1507_417"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="12"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.780392 0 0 0 0 0.882353 0 0 0 0 0.2 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1507_417" result="effect2_dropShadow_1507_417"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_1507_417" result="shape"/>
</filter>
<filter id="filter8_dd_1507_417" x="136.721" y="72.6216" width="110.838" height="99.3166" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="6"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.780392 0 0 0 0 0.882353 0 0 0 0 0.2 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1507_417"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="12"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.780392 0 0 0 0 0.882353 0 0 0 0 0.2 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1507_417" result="effect2_dropShadow_1507_417"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_1507_417" result="shape"/>
</filter>
<filter id="filter9_dd_1507_417" x="226.287" y="111.294" width="170.562" height="97.6261" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="6"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.780392 0 0 0 0 0.882353 0 0 0 0 0.2 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1507_417"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="12"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.780392 0 0 0 0 0.882353 0 0 0 0 0.2 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1507_417" result="effect2_dropShadow_1507_417"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_1507_417" result="shape"/>
</filter>
<filter id="filter10_dd_1507_417" x="82.0369" y="88.53" width="92.8538" height="81.7821" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="6"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.780392 0 0 0 0 0.882353 0 0 0 0 0.2 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1507_417"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="12"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.780392 0 0 0 0 0.882353 0 0 0 0 0.2 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1507_417" result="effect2_dropShadow_1507_417"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_1507_417" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 28 KiB

BIN
assets/swayfx_mascot.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

40
build.sh Normal file
View file

@ -0,0 +1,40 @@
#! /bin/bash
# shellcheck disable=SC2154
set -eE -u -o pipefail
shopt -s inherit_errexit
DEB_BUILD_GNU_TYPE=$(dpkg-architecture -q DEB_BUILD_GNU_TYPE)
meson setup --prefix ${OPT_SWAYFX} "wlroots-${WLROOTSVERSION}/build/" "wlroots-${WLROOTSVERSION}"
ninja -C "wlroots-${WLROOTSVERSION}/build/"
ninja -C "wlroots-${WLROOTSVERSION}/build/" install
ls -l ${OPT_SWAYFX}/lib/${DEB_BUILD_GNU_TYPE}/pkgconfig
echo "wlroots DONE"
PKG_CONFIG_PATH="${OPT_SWAYFX}/lib/${DEB_BUILD_GNU_TYPE}/pkgconfig/${PKG_CONFIG_PATH+:${PKG_CONFIG_PATH}}" \
meson setup --prefix ${OPT_SWAYFX} --cmake-prefix-path ${OPT_SWAYFX} "scenefx-${SCENEFXVERSION}/build/" "scenefx-${SCENEFXVERSION}"
ninja -C "scenefx-${SCENEFXVERSION}/build/"
ninja -C "scenefx-${SCENEFXVERSION}/build/" install
echo "scenefx DONE"
PKG_CONFIG_PATH="${OPT_SWAYFX}/lib/${DEB_BUILD_GNU_TYPE}/pkgconfig/${PKG_CONFIG_PATH+:${PKG_CONFIG_PATH}}" \
meson setup --prefix ${OPT_SWAYFX} --cmake-prefix-path ${OPT_SWAYFX} "swayfx-${SWAYFXVERSION}/build/" "swayfx-${SWAYFXVERSION}"
ninja -C "swayfx-${SWAYFXVERSION}/build/"
ninja -C "swayfx-${SWAYFXVERSION}/build/" install
echo "swayfx DONE"
mv ${OPT_SWAYFX}/bin/sway ${OPT_SWAYFX}/bin/swayfx
cat >${OPT_SWAYFX}/bin/swayfx.sh <<EOF
#!/bin/sh
export PATH=${OPT_SWAYFX}/bin:\${PATH}
export LD_LIBRARY_PATH=\${LD_LIBRARY_PATH}:${OPT_SWAYFX}/lib/${DEB_BUILD_GNU_TYPE}/
exec ${OPT_SWAYFX}/bin/swayfx
EOF
chmod 755 ${OPT_SWAYFX}/bin/swayfx.sh
echo
echo "Successfully build swayfx. Find it in your hosts bind directory (default: .${OPT_SWAYFX})."

14
client/meson.build Normal file
View file

@ -0,0 +1,14 @@
lib_sway_client = static_library(
'sway-client',
files(
'pool-buffer.c',
),
dependencies: [
cairo,
pango,
pangocairo,
wayland_client
],
link_with: [lib_sway_common],
include_directories: sway_inc
)

131
client/pool-buffer.c Normal file
View file

@ -0,0 +1,131 @@
#include <assert.h>
#include <cairo.h>
#include <errno.h>
#include <fcntl.h>
#include <pango/pangocairo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <wayland-client.h>
#include "config.h"
#include "pool-buffer.h"
#include "util.h"
static int anonymous_shm_open(void) {
int retries = 100;
do {
// try a probably-unique name
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
pid_t pid = getpid();
char name[50];
snprintf(name, sizeof(name), "/sway-%x-%x",
(unsigned int)pid, (unsigned int)ts.tv_nsec);
// shm_open guarantees that O_CLOEXEC is set
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd >= 0) {
shm_unlink(name);
return fd;
}
--retries;
} while (retries > 0 && errno == EEXIST);
return -1;
}
static void buffer_release(void *data, struct wl_buffer *wl_buffer) {
struct pool_buffer *buffer = data;
buffer->busy = false;
}
static const struct wl_buffer_listener buffer_listener = {
.release = buffer_release
};
static struct pool_buffer *create_buffer(struct wl_shm *shm,
struct pool_buffer *buf, int32_t width, int32_t height,
uint32_t format) {
uint32_t stride = width * 4;
size_t size = stride * height;
int fd = anonymous_shm_open();
if (fd == -1) {
return NULL;
}
if (ftruncate(fd, size) < 0) {
close(fd);
return NULL;
}
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
buf->buffer = wl_shm_pool_create_buffer(pool, 0,
width, height, stride, format);
wl_shm_pool_destroy(pool);
close(fd);
buf->size = size;
buf->width = width;
buf->height = height;
buf->data = data;
buf->surface = cairo_image_surface_create_for_data(data,
CAIRO_FORMAT_ARGB32, width, height, stride);
buf->cairo = cairo_create(buf->surface);
buf->pango = pango_cairo_create_context(buf->cairo);
wl_buffer_add_listener(buf->buffer, &buffer_listener, buf);
return buf;
}
void destroy_buffer(struct pool_buffer *buffer) {
if (buffer->buffer) {
wl_buffer_destroy(buffer->buffer);
}
if (buffer->cairo) {
cairo_destroy(buffer->cairo);
}
if (buffer->surface) {
cairo_surface_destroy(buffer->surface);
}
if (buffer->pango) {
g_object_unref(buffer->pango);
}
if (buffer->data) {
munmap(buffer->data, buffer->size);
}
memset(buffer, 0, sizeof(struct pool_buffer));
}
struct pool_buffer *get_next_buffer(struct wl_shm *shm,
struct pool_buffer pool[static 2], uint32_t width, uint32_t height) {
struct pool_buffer *buffer = NULL;
for (size_t i = 0; i < 2; ++i) {
if (pool[i].busy) {
continue;
}
buffer = &pool[i];
}
if (!buffer) {
return NULL;
}
if (buffer->width != width || buffer->height != height) {
destroy_buffer(buffer);
}
if (!buffer->buffer) {
if (!create_buffer(shm, buffer, width, height,
WL_SHM_FORMAT_ARGB8888)) {
return NULL;
}
}
buffer->busy = true;
return buffer;
}

44
common/cairo.c Normal file
View file

@ -0,0 +1,44 @@
#include <stdint.h>
#include <cairo.h>
#include "cairo_util.h"
void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
cairo_set_source_rgba(cairo,
(color >> (3*8) & 0xFF) / 255.0,
(color >> (2*8) & 0xFF) / 255.0,
(color >> (1*8) & 0xFF) / 255.0,
(color >> (0*8) & 0xFF) / 255.0);
}
cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel) {
switch (subpixel) {
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
return CAIRO_SUBPIXEL_ORDER_RGB;
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
return CAIRO_SUBPIXEL_ORDER_BGR;
case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
return CAIRO_SUBPIXEL_ORDER_VRGB;
case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
return CAIRO_SUBPIXEL_ORDER_VBGR;
default:
return CAIRO_SUBPIXEL_ORDER_DEFAULT;
}
return CAIRO_SUBPIXEL_ORDER_DEFAULT;
}
cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image,
int width, int height) {
int image_width = cairo_image_surface_get_width(image);
int image_height = cairo_image_surface_get_height(image);
cairo_surface_t *new =
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
cairo_t *cairo = cairo_create(new);
cairo_scale(cairo, (double)width / image_width,
(double)height / image_height);
cairo_set_source_surface(cairo, image, 0, 0);
cairo_paint(cairo);
cairo_destroy(cairo);
return new;
}

332
common/gesture.c Normal file
View file

@ -0,0 +1,332 @@
#include "gesture.h"
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
#include "log.h"
#include "stringop.h"
const uint8_t GESTURE_FINGERS_ANY = 0;
char *gesture_parse(const char *input, struct gesture *output) {
// Clear output in case of failure
output->type = GESTURE_TYPE_NONE;
output->fingers = GESTURE_FINGERS_ANY;
output->directions = GESTURE_DIRECTION_NONE;
// Split input type, fingers and directions
list_t *split = split_string(input, ":");
if (split->length < 1 || split->length > 3) {
return format_str(
"expected <gesture>[:<fingers>][:direction], got %s",
input);
}
// Parse gesture type
if (strcmp(split->items[0], "hold") == 0) {
output->type = GESTURE_TYPE_HOLD;
} else if (strcmp(split->items[0], "pinch") == 0) {
output->type = GESTURE_TYPE_PINCH;
} else if (strcmp(split->items[0], "swipe") == 0) {
output->type = GESTURE_TYPE_SWIPE;
} else {
return format_str("expected hold|pinch|swipe, got %s",
(const char *)split->items[0]);
}
// Parse optional arguments
if (split->length > 1) {
char *next = split->items[1];
// Try to parse as finger count (1-9)
if (strlen(next) == 1 && '1' <= next[0] && next[0] <= '9') {
output->fingers = atoi(next);
// Move to next if available
next = split->length == 3 ? split->items[2] : NULL;
} else if (split->length == 3) {
// Fail here if argument can only be finger count
return format_str("expected 1-9, got %s", next);
}
// If there is an argument left, try to parse as direction
if (next) {
list_t *directions = split_string(next, "+");
for (int i = 0; i < directions->length; ++i) {
const char *item = directions->items[i];
if (strcmp(item, "any") == 0) {
continue;
} else if (strcmp(item, "up") == 0) {
output->directions |= GESTURE_DIRECTION_UP;
} else if (strcmp(item, "down") == 0) {
output->directions |= GESTURE_DIRECTION_DOWN;
} else if (strcmp(item, "left") == 0) {
output->directions |= GESTURE_DIRECTION_LEFT;
} else if (strcmp(item, "right") == 0) {
output->directions |= GESTURE_DIRECTION_RIGHT;
} else if (strcmp(item, "inward") == 0) {
output->directions |= GESTURE_DIRECTION_INWARD;
} else if (strcmp(item, "outward") == 0) {
output->directions |= GESTURE_DIRECTION_OUTWARD;
} else if (strcmp(item, "clockwise") == 0) {
output->directions |= GESTURE_DIRECTION_CLOCKWISE;
} else if (strcmp(item, "counterclockwise") == 0) {
output->directions |= GESTURE_DIRECTION_COUNTERCLOCKWISE;
} else {
return format_str("expected direction, got %s", item);
}
}
list_free_items_and_destroy(directions);
}
} // if optional args
list_free_items_and_destroy(split);
return NULL;
}
const char *gesture_type_string(enum gesture_type type) {
switch (type) {
case GESTURE_TYPE_NONE:
return "none";
case GESTURE_TYPE_HOLD:
return "hold";
case GESTURE_TYPE_PINCH:
return "pinch";
case GESTURE_TYPE_SWIPE:
return "swipe";
}
return NULL;
}
const char *gesture_direction_string(enum gesture_direction direction) {
switch (direction) {
case GESTURE_DIRECTION_NONE:
return "none";
case GESTURE_DIRECTION_UP:
return "up";
case GESTURE_DIRECTION_DOWN:
return "down";
case GESTURE_DIRECTION_LEFT:
return "left";
case GESTURE_DIRECTION_RIGHT:
return "right";
case GESTURE_DIRECTION_INWARD:
return "inward";
case GESTURE_DIRECTION_OUTWARD:
return "outward";
case GESTURE_DIRECTION_CLOCKWISE:
return "clockwise";
case GESTURE_DIRECTION_COUNTERCLOCKWISE:
return "counterclockwise";
}
return NULL;
}
// Helper to turn combination of directions flags into string representation.
static char *gesture_directions_to_string(uint32_t directions) {
char *result = NULL;
for (uint8_t bit = 0; bit < 32; bit++) {
uint32_t masked = directions & (1 << bit);
if (masked) {
const char *name = gesture_direction_string(masked);
if (!name) {
name = "unknown";
}
if (!result) {
result = strdup(name);
} else {
char *new = format_str("%s+%s", result, name);
free(result);
result = new;
}
}
}
if(!result) {
return strdup("any");
}
return result;
}
char *gesture_to_string(struct gesture *gesture) {
char *directions = gesture_directions_to_string(gesture->directions);
char *result = format_str("%s:%u:%s",
gesture_type_string(gesture->type),
gesture->fingers, directions);
free(directions);
return result;
}
bool gesture_check(struct gesture *target, enum gesture_type type, uint8_t fingers) {
// Check that gesture type matches
if (target->type != type) {
return false;
}
// Check that finger count matches
if (target->fingers != GESTURE_FINGERS_ANY && target->fingers != fingers) {
return false;
}
return true;
}
bool gesture_match(struct gesture *target, struct gesture *to_match, bool exact) {
// Check type and fingers
if (!gesture_check(target, to_match->type, to_match->fingers)) {
return false;
}
// Enforce exact matches ...
if (exact && target->directions != to_match->directions) {
return false;
}
// ... or ensure all target directions are matched
return (target->directions & to_match->directions) == target->directions;
}
bool gesture_equal(struct gesture *a, struct gesture *b) {
return a->type == b->type
&& a->fingers == b->fingers
&& a->directions == b->directions;
}
// Return count of set bits in directions bit field.
static uint8_t gesture_directions_count(uint32_t directions) {
uint8_t count = 0;
for (; directions; directions >>= 1) {
count += directions & 1;
}
return count;
}
// Compare direction bit count of two direction.
static int8_t gesture_directions_compare(uint32_t a, uint32_t b) {
return gesture_directions_count(a) - gesture_directions_count(b);
}
// Compare two direction based on their direction bit count
int8_t gesture_compare(struct gesture *a, struct gesture *b) {
return gesture_directions_compare(a->directions, b->directions);
}
void gesture_tracker_begin(struct gesture_tracker *tracker,
enum gesture_type type, uint8_t fingers) {
tracker->type = type;
tracker->fingers = fingers;
tracker->dx = 0.0;
tracker->dy = 0.0;
tracker->scale = 1.0;
tracker->rotation = 0.0;
sway_log(SWAY_DEBUG, "begin tracking %s:%u:? gesture",
gesture_type_string(type), fingers);
}
bool gesture_tracker_check(struct gesture_tracker *tracker, enum gesture_type type) {
return tracker->type == type;
}
void gesture_tracker_update(struct gesture_tracker *tracker,
double dx, double dy, double scale, double rotation) {
if (tracker->type == GESTURE_TYPE_HOLD) {
sway_assert(false, "hold does not update.");
return;
}
tracker->dx += dx;
tracker->dy += dy;
if (tracker->type == GESTURE_TYPE_PINCH) {
tracker->scale = scale;
tracker->rotation += rotation;
}
sway_log(SWAY_DEBUG, "update tracking %s:%u:? gesture: %f %f %f %f",
gesture_type_string(tracker->type),
tracker->fingers,
tracker->dx, tracker->dy,
tracker->scale, tracker->rotation);
}
void gesture_tracker_cancel(struct gesture_tracker *tracker) {
sway_log(SWAY_DEBUG, "cancel tracking %s:%u:? gesture",
gesture_type_string(tracker->type), tracker->fingers);
tracker->type = GESTURE_TYPE_NONE;
}
struct gesture *gesture_tracker_end(struct gesture_tracker *tracker) {
struct gesture *result = calloc(1, sizeof(struct gesture));
// Ignore gesture under some threshold
// TODO: Make configurable
const double min_rotation = 5;
const double min_scale_delta = 0.1;
// Determine direction
switch(tracker->type) {
// Gestures with scale and rotation
case GESTURE_TYPE_PINCH:
if (tracker->rotation > min_rotation) {
result->directions |= GESTURE_DIRECTION_CLOCKWISE;
}
if (tracker->rotation < -min_rotation) {
result->directions |= GESTURE_DIRECTION_COUNTERCLOCKWISE;
}
if (tracker->scale > (1.0 + min_scale_delta)) {
result->directions |= GESTURE_DIRECTION_OUTWARD;
}
if (tracker->scale < (1.0 - min_scale_delta)) {
result->directions |= GESTURE_DIRECTION_INWARD;
}
__attribute__ ((fallthrough));
// Gestures with dx and dy
case GESTURE_TYPE_SWIPE:
if (fabs(tracker->dx) > fabs(tracker->dy)) {
if (tracker->dx > 0) {
result->directions |= GESTURE_DIRECTION_RIGHT;
} else {
result->directions |= GESTURE_DIRECTION_LEFT;
}
} else {
if (tracker->dy > 0) {
result->directions |= GESTURE_DIRECTION_DOWN;
} else {
result->directions |= GESTURE_DIRECTION_UP;
}
}
// Gesture without any direction
case GESTURE_TYPE_HOLD:
break;
// Not tracking any gesture
case GESTURE_TYPE_NONE:
sway_assert(false, "Not tracking any gesture.");
return result;
}
result->type = tracker->type;
result->fingers = tracker->fingers;
char *description = gesture_to_string(result);
sway_log(SWAY_DEBUG, "end tracking gesture: %s", description);
free(description);
tracker->type = GESTURE_TYPE_NONE;
return result;
}

148
common/ipc-client.c Normal file
View file

@ -0,0 +1,148 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "ipc-client.h"
#include "log.h"
static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
#define IPC_HEADER_SIZE (sizeof(ipc_magic) + 8)
char *get_socketpath(void) {
const char *swaysock = getenv("SWAYSOCK");
if (swaysock) {
return strdup(swaysock);
}
char *line = NULL;
size_t line_size = 0;
FILE *fp = popen("sway --get-socketpath 2>/dev/null", "r");
if (fp) {
ssize_t nret = getline(&line, &line_size, fp);
pclose(fp);
if (nret > 0) {
// remove trailing newline, if there is one
if (line[nret - 1] == '\n') {
line[nret - 1] = '\0';
}
return line;
}
}
const char *i3sock = getenv("I3SOCK");
if (i3sock) {
free(line);
return strdup(i3sock);
}
fp = popen("i3 --get-socketpath 2>/dev/null", "r");
if (fp) {
ssize_t nret = getline(&line, &line_size, fp);
pclose(fp);
if (nret > 0) {
// remove trailing newline, if there is one
if (line[nret - 1] == '\n') {
line[nret - 1] = '\0';
}
return line;
}
}
free(line);
return NULL;
}
int ipc_open_socket(const char *socket_path) {
struct sockaddr_un addr;
int socketfd;
if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
sway_abort("Unable to open Unix socket");
}
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
int l = sizeof(struct sockaddr_un);
if (connect(socketfd, (struct sockaddr *)&addr, l) == -1) {
sway_abort("Unable to connect to %s", socket_path);
}
return socketfd;
}
bool ipc_set_recv_timeout(int socketfd, struct timeval tv) {
if (setsockopt(socketfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
sway_log_errno(SWAY_ERROR, "Failed to set ipc recv timeout");
return false;
}
return true;
}
struct ipc_response *ipc_recv_response(int socketfd) {
char data[IPC_HEADER_SIZE];
size_t total = 0;
while (total < IPC_HEADER_SIZE) {
ssize_t received = recv(socketfd, data + total, IPC_HEADER_SIZE - total, 0);
if (received <= 0) {
sway_abort("Unable to receive IPC response");
}
total += received;
}
struct ipc_response *response = malloc(sizeof(struct ipc_response));
if (!response) {
goto error_1;
}
memcpy(&response->size, data + sizeof(ipc_magic), sizeof(uint32_t));
memcpy(&response->type, data + sizeof(ipc_magic) + sizeof(uint32_t), sizeof(uint32_t));
char *payload = malloc(response->size + 1);
if (!payload) {
goto error_2;
}
total = 0;
while (total < response->size) {
ssize_t received = recv(socketfd, payload + total, response->size - total, 0);
if (received < 0) {
sway_abort("Unable to receive IPC response");
}
total += received;
}
payload[response->size] = '\0';
response->payload = payload;
return response;
error_2:
free(response);
error_1:
sway_log(SWAY_ERROR, "Unable to allocate memory for IPC response");
return NULL;
}
void free_ipc_response(struct ipc_response *response) {
free(response->payload);
free(response);
}
char *ipc_single_command(int socketfd, uint32_t type, const char *payload, uint32_t *len) {
char data[IPC_HEADER_SIZE];
memcpy(data, ipc_magic, sizeof(ipc_magic));
memcpy(data + sizeof(ipc_magic), len, sizeof(*len));
memcpy(data + sizeof(ipc_magic) + sizeof(*len), &type, sizeof(type));
if (write(socketfd, data, IPC_HEADER_SIZE) == -1) {
sway_abort("Unable to send IPC header");
}
if (write(socketfd, payload, *len) == -1) {
sway_abort("Unable to send IPC payload");
}
struct ipc_response *resp = ipc_recv_response(socketfd);
char *response = resp->payload;
*len = resp->size;
free(resp);
return response;
}

160
common/list.c Normal file
View file

@ -0,0 +1,160 @@
#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "log.h"
list_t *create_list(void) {
list_t *list = malloc(sizeof(list_t));
if (!list) {
return NULL;
}
list->capacity = 10;
list->length = 0;
list->items = malloc(sizeof(void*) * list->capacity);
return list;
}
static void list_resize(list_t *list) {
if (list->length == list->capacity) {
list->capacity *= 2;
list->items = realloc(list->items, sizeof(void*) * list->capacity);
}
}
void list_free(list_t *list) {
if (list == NULL) {
return;
}
free(list->items);
free(list);
}
void list_add(list_t *list, void *item) {
list_resize(list);
list->items[list->length++] = item;
}
void list_insert(list_t *list, int index, void *item) {
list_resize(list);
memmove(&list->items[index + 1], &list->items[index], sizeof(void*) * (list->length - index));
list->length++;
list->items[index] = item;
}
void list_del(list_t *list, int index) {
list->length--;
memmove(&list->items[index], &list->items[index + 1], sizeof(void*) * (list->length - index));
}
void list_cat(list_t *list, list_t *source) {
for (int i = 0; i < source->length; ++i) {
list_add(list, source->items[i]);
}
}
void list_qsort(list_t *list, int compare(const void *left, const void *right)) {
qsort(list->items, list->length, sizeof(void *), compare);
}
int list_seq_find(list_t *list, int compare(const void *item, const void *data), const void *data) {
for (int i = 0; i < list->length; i++) {
void *item = list->items[i];
if (compare(item, data) == 0) {
return i;
}
}
return -1;
}
int list_find(list_t *list, const void *item) {
for (int i = 0; i < list->length; i++) {
if (list->items[i] == item) {
return i;
}
}
return -1;
}
void list_swap(list_t *list, int src, int dest) {
void *tmp = list->items[src];
list->items[src] = list->items[dest];
list->items[dest] = tmp;
}
void list_move_to_end(list_t *list, void *item) {
int i;
for (i = 0; i < list->length; ++i) {
if (list->items[i] == item) {
break;
}
}
if (!sway_assert(i < list->length, "Item not found in list")) {
return;
}
list_del(list, i);
list_add(list, item);
}
static void list_rotate(list_t *list, int from, int to) {
void *tmp = list->items[to];
while (to > from) {
list->items[to] = list->items[to - 1];
to--;
}
list->items[from] = tmp;
}
static void list_inplace_merge(list_t *list, int left, int last, int mid, int compare(const void *a, const void *b)) {
int right = mid + 1;
if (compare(&list->items[mid], &list->items[right]) <= 0) {
return;
}
while (left <= mid && right <= last) {
if (compare(&list->items[left], &list->items[right]) <= 0) {
left++;
} else {
list_rotate(list, left, right);
left++;
mid++;
right++;
}
}
}
static void list_inplace_sort(list_t *list, int first, int last, int compare(const void *a, const void *b)) {
if (first >= last) {
return;
} else if ((last - first) == 1) {
if (compare(&list->items[first], &list->items[last]) > 0) {
list_swap(list, first, last);
}
} else {
int mid = (int)((last + first) / 2);
list_inplace_sort(list, first, mid, compare);
list_inplace_sort(list, mid + 1, last, compare);
list_inplace_merge(list, first, last, mid, compare);
}
}
void list_stable_sort(list_t *list, int compare(const void *a, const void *b)) {
if (list->length > 1) {
list_inplace_sort(list, 0, list->length - 1, compare);
}
}
void list_free_items_and_destroy(list_t *list) {
if (!list) {
return;
}
for (int i = 0; i < list->length; ++i) {
free(list->items[i]);
}
list_free(list);
}

125
common/log.c Normal file
View file

@ -0,0 +1,125 @@
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "log.h"
static terminate_callback_t log_terminate = exit;
void _sway_abort(const char *format, ...) {
va_list args;
va_start(args, format);
_sway_vlog(SWAY_ERROR, format, args);
va_end(args);
log_terminate(EXIT_FAILURE);
}
bool _sway_assert(bool condition, const char *format, ...) {
if (condition) {
return true;
}
va_list args;
va_start(args, format);
_sway_vlog(SWAY_ERROR, format, args);
va_end(args);
#ifndef NDEBUG
raise(SIGABRT);
#endif
return false;
}
static bool colored = true;
static sway_log_importance_t log_importance = SWAY_ERROR;
static struct timespec start_time = {-1, -1};
static const char *verbosity_colors[] = {
[SWAY_SILENT] = "",
[SWAY_ERROR ] = "\x1B[1;31m",
[SWAY_INFO ] = "\x1B[1;34m",
[SWAY_DEBUG ] = "\x1B[1;90m",
};
static const char *verbosity_headers[] = {
[SWAY_SILENT] = "",
[SWAY_ERROR] = "[ERROR]",
[SWAY_INFO] = "[INFO]",
[SWAY_DEBUG] = "[DEBUG]",
};
static void timespec_sub(struct timespec *r, const struct timespec *a,
const struct timespec *b) {
const long NSEC_PER_SEC = 1000000000;
r->tv_sec = a->tv_sec - b->tv_sec;
r->tv_nsec = a->tv_nsec - b->tv_nsec;
if (r->tv_nsec < 0) {
r->tv_sec--;
r->tv_nsec += NSEC_PER_SEC;
}
}
static void init_start_time(void) {
if (start_time.tv_sec >= 0) {
return;
}
clock_gettime(CLOCK_MONOTONIC, &start_time);
}
static void sway_log_stderr(sway_log_importance_t verbosity, const char *fmt,
va_list args) {
init_start_time();
if (verbosity > log_importance) {
return;
}
struct timespec ts = {0};
clock_gettime(CLOCK_MONOTONIC, &ts);
timespec_sub(&ts, &ts, &start_time);
fprintf(stderr, "%02d:%02d:%02d.%03ld ", (int)(ts.tv_sec / 60 / 60),
(int)(ts.tv_sec / 60 % 60), (int)(ts.tv_sec % 60),
ts.tv_nsec / 1000000);
unsigned c = (verbosity < SWAY_LOG_IMPORTANCE_LAST) ? verbosity :
SWAY_LOG_IMPORTANCE_LAST - 1;
if (colored && isatty(STDERR_FILENO)) {
fprintf(stderr, "%s", verbosity_colors[c]);
} else {
fprintf(stderr, "%s ", verbosity_headers[c]);
}
vfprintf(stderr, fmt, args);
if (colored && isatty(STDERR_FILENO)) {
fprintf(stderr, "\x1B[0m");
}
fprintf(stderr, "\n");
}
void sway_log_init(sway_log_importance_t verbosity, terminate_callback_t callback) {
init_start_time();
if (verbosity < SWAY_LOG_IMPORTANCE_LAST) {
log_importance = verbosity;
}
if (callback) {
log_terminate = callback;
}
}
void _sway_vlog(sway_log_importance_t verbosity, const char *fmt, va_list args) {
sway_log_stderr(verbosity, fmt, args);
}
void _sway_log(sway_log_importance_t verbosity, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
sway_log_stderr(verbosity, fmt, args);
va_end(args);
}

183
common/loop.c Normal file
View file

@ -0,0 +1,183 @@
#include <limits.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <poll.h>
#include <time.h>
#include <unistd.h>
#include "list.h"
#include "log.h"
#include "loop.h"
struct loop_fd_event {
void (*callback)(int fd, short mask, void *data);
void *data;
};
struct loop_timer {
void (*callback)(void *data);
void *data;
struct timespec expiry;
};
struct loop {
struct pollfd *fds;
int fd_length;
int fd_capacity;
list_t *fd_events; // struct loop_fd_event
list_t *timers; // struct loop_timer
};
struct loop *loop_create(void) {
struct loop *loop = calloc(1, sizeof(struct loop));
if (!loop) {
sway_log(SWAY_ERROR, "Unable to allocate memory for loop");
return NULL;
}
loop->fd_capacity = 10;
loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity);
loop->fd_events = create_list();
loop->timers = create_list();
return loop;
}
void loop_destroy(struct loop *loop) {
list_free_items_and_destroy(loop->fd_events);
list_free_items_and_destroy(loop->timers);
free(loop->fds);
free(loop);
}
void loop_poll(struct loop *loop) {
// Calculate next timer in ms
int ms = INT_MAX;
if (loop->timers->length) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
for (int i = 0; i < loop->timers->length; ++i) {
struct loop_timer *timer = loop->timers->items[i];
int timer_ms = (timer->expiry.tv_sec - now.tv_sec) * 1000;
timer_ms += (timer->expiry.tv_nsec - now.tv_nsec) / 1000000;
if (timer_ms < ms) {
ms = timer_ms;
}
}
}
if (ms < 0) {
ms = 0;
}
poll(loop->fds, loop->fd_length, ms);
// Dispatch fds
for (int i = 0; i < loop->fd_length; ++i) {
struct pollfd pfd = loop->fds[i];
struct loop_fd_event *event = loop->fd_events->items[i];
// Always send these events
unsigned events = pfd.events | POLLHUP | POLLERR;
if (pfd.revents & events) {
event->callback(pfd.fd, pfd.revents, event->data);
}
}
// Dispatch timers
if (loop->timers->length) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
for (int i = 0; i < loop->timers->length; ++i) {
struct loop_timer *timer = loop->timers->items[i];
bool expired = timer->expiry.tv_sec < now.tv_sec ||
(timer->expiry.tv_sec == now.tv_sec &&
timer->expiry.tv_nsec < now.tv_nsec);
if (expired) {
timer->callback(timer->data);
loop_remove_timer(loop, timer);
--i;
}
}
}
}
void loop_add_fd(struct loop *loop, int fd, short mask,
void (*callback)(int fd, short mask, void *data), void *data) {
struct loop_fd_event *event = calloc(1, sizeof(struct loop_fd_event));
if (!event) {
sway_log(SWAY_ERROR, "Unable to allocate memory for event");
return;
}
event->callback = callback;
event->data = data;
list_add(loop->fd_events, event);
struct pollfd pfd = {fd, mask, 0};
if (loop->fd_length == loop->fd_capacity) {
int capacity = loop->fd_capacity + 10;
struct pollfd *tmp = realloc(loop->fds,
sizeof(struct pollfd) * capacity);
if (!tmp) {
sway_log(SWAY_ERROR, "Unable to allocate memory for pollfd");
return;
}
loop->fds = tmp;
loop->fd_capacity = capacity;
}
loop->fds[loop->fd_length++] = pfd;
}
struct loop_timer *loop_add_timer(struct loop *loop, int ms,
void (*callback)(void *data), void *data) {
struct loop_timer *timer = calloc(1, sizeof(struct loop_timer));
if (!timer) {
sway_log(SWAY_ERROR, "Unable to allocate memory for timer");
return NULL;
}
timer->callback = callback;
timer->data = data;
clock_gettime(CLOCK_MONOTONIC, &timer->expiry);
timer->expiry.tv_sec += ms / 1000;
long int nsec = (ms % 1000) * 1000000;
if (timer->expiry.tv_nsec + nsec >= 1000000000) {
timer->expiry.tv_sec++;
nsec -= 1000000000;
}
timer->expiry.tv_nsec += nsec;
list_add(loop->timers, timer);
return timer;
}
bool loop_remove_fd(struct loop *loop, int fd) {
for (int i = 0; i < loop->fd_length; ++i) {
if (loop->fds[i].fd == fd) {
free(loop->fd_events->items[i]);
list_del(loop->fd_events, i);
loop->fd_length--;
memmove(&loop->fds[i], &loop->fds[i + 1],
sizeof(struct pollfd) * (loop->fd_length - i));
return true;
}
}
return false;
}
bool loop_remove_timer(struct loop *loop, struct loop_timer *timer) {
for (int i = 0; i < loop->timers->length; ++i) {
if (loop->timers->items[i] == timer) {
list_del(loop->timers, i);
free(timer);
return true;
}
}
return false;
}

21
common/meson.build Normal file
View file

@ -0,0 +1,21 @@
lib_sway_common = static_library(
'sway-common',
files(
'cairo.c',
'gesture.c',
'ipc-client.c',
'log.c',
'loop.c',
'list.c',
'pango.c',
'stringop.c',
'util.c'
),
dependencies: [
cairo,
pango,
pangocairo,
wayland_client.partial_dependency(compile_args: true)
],
include_directories: sway_inc
)

171
common/pango.c Normal file
View file

@ -0,0 +1,171 @@
#include <cairo.h>
#include <pango/pangocairo.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cairo_util.h"
#include "log.h"
#include "stringop.h"
size_t escape_markup_text(const char *src, char *dest) {
size_t length = 0;
if (dest) {
dest[0] = '\0';
}
while (src[0]) {
switch (src[0]) {
case '&':
length += 5;
lenient_strcat(dest, "&amp;");
break;
case '<':
length += 4;
lenient_strcat(dest, "&lt;");
break;
case '>':
length += 4;
lenient_strcat(dest, "&gt;");
break;
case '\'':
length += 6;
lenient_strcat(dest, "&apos;");
break;
case '"':
length += 6;
lenient_strcat(dest, "&quot;");
break;
default:
if (dest) {
dest[length] = *src;
dest[length + 1] = '\0';
}
length += 1;
}
src++;
}
return length;
}
PangoLayout *get_pango_layout(cairo_t *cairo, const PangoFontDescription *desc,
const char *text, double scale, bool markup) {
PangoLayout *layout = pango_cairo_create_layout(cairo);
pango_context_set_round_glyph_positions(pango_layout_get_context(layout), false);
PangoAttrList *attrs;
if (markup) {
char *buf;
GError *error = NULL;
if (pango_parse_markup(text, -1, 0, &attrs, &buf, NULL, &error)) {
pango_layout_set_text(layout, buf, -1);
free(buf);
} else {
sway_log(SWAY_ERROR, "pango_parse_markup '%s' -> error %s", text,
error->message);
g_error_free(error);
markup = false; // fallback to plain text
}
}
if (!markup) {
attrs = pango_attr_list_new();
pango_layout_set_text(layout, text, -1);
}
pango_attr_list_insert(attrs, pango_attr_scale_new(scale));
pango_layout_set_font_description(layout, desc);
pango_layout_set_single_paragraph_mode(layout, 1);
pango_layout_set_attributes(layout, attrs);
pango_attr_list_unref(attrs);
return layout;
}
void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width, int *height,
int *baseline, double scale, bool markup, const char *fmt, ...) {
if (width) {
*width = 0;
}
if (height) {
*height = 0;
}
if (baseline) {
*baseline = 0;
}
va_list args;
va_start(args, fmt);
char *buf = vformat_str(fmt, args);
va_end(args);
if (buf == NULL) {
sway_log(SWAY_ERROR, "Failed to format string");
return;
}
PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup);
pango_cairo_update_layout(cairo, layout);
cairo_status_t status = cairo_status(cairo);
if (status != CAIRO_STATUS_SUCCESS) {
sway_log(SWAY_ERROR, "pango_cairo_update_layout() failed: %s",
cairo_status_to_string(status));
goto out;
}
pango_layout_get_pixel_size(layout, width, height);
if (baseline) {
*baseline = pango_layout_get_baseline(layout) / PANGO_SCALE;
}
out:
g_object_unref(layout);
free(buf);
}
void get_text_metrics(const PangoFontDescription *description, int *height, int *baseline) {
PangoFontMap *fontmap = pango_cairo_font_map_get_default();
PangoContext *pango = pango_font_map_create_context(fontmap);
pango_context_set_round_glyph_positions(pango, false);
// When passing NULL as a language, pango uses the current locale.
PangoFontMetrics *metrics = pango_context_get_metrics(pango, description, NULL);
*baseline = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
*height = *baseline + pango_font_metrics_get_descent(metrics) / PANGO_SCALE;
pango_font_metrics_unref(metrics);
g_object_unref(pango);
}
void render_text(cairo_t *cairo, const PangoFontDescription *desc,
double scale, bool markup, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
char *buf = vformat_str(fmt, args);
va_end(args);
if (buf == NULL) {
sway_log(SWAY_ERROR, "Failed to format string");
return;
}
PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup);
cairo_font_options_t *fo = cairo_font_options_create();
cairo_get_font_options(cairo, fo);
pango_cairo_context_set_font_options(pango_layout_get_context(layout), fo);
cairo_font_options_destroy(fo);
pango_cairo_update_layout(cairo, layout);
cairo_status_t status = cairo_status(cairo);
if (status != CAIRO_STATUS_SUCCESS) {
sway_log(SWAY_ERROR, "pango_cairo_update_layout() failed: %s",
cairo_status_to_string(status));
goto out;
}
pango_cairo_show_layout(cairo, layout);
out:
g_object_unref(layout);
free(buf);
}

366
common/stringop.c Normal file
View file

@ -0,0 +1,366 @@
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <wordexp.h>
#include "list.h"
#include "log.h"
#include "stringop.h"
static const char whitespace[] = " \f\n\r\t\v";
void strip_whitespace(char *str) {
size_t len = strlen(str);
size_t start = strspn(str, whitespace);
memmove(str, &str[start], len + 1 - start);
if (*str) {
for (len -= start + 1; isspace(str[len]); --len) {}
str[len + 1] = '\0';
}
}
void strip_quotes(char *str) {
bool in_str = false;
bool in_chr = false;
bool escaped = false;
char *end = strchr(str,0);
while (*str) {
if (*str == '\'' && !in_str && !escaped) {
in_chr = !in_chr;
goto shift_over;
} else if (*str == '\"' && !in_chr && !escaped) {
in_str = !in_str;
goto shift_over;
} else if (*str == '\\') {
escaped = !escaped;
++str;
continue;
}
escaped = false;
++str;
continue;
shift_over:
memmove(str, str+1, end-- - str);
}
*end = '\0';
}
char *lenient_strcat(char *dest, const char *src) {
if (dest && src) {
return strcat(dest, src);
}
return dest;
}
char *lenient_strncat(char *dest, const char *src, size_t len) {
if (dest && src) {
return strncat(dest, src, len);
}
return dest;
}
// strcmp that also handles null pointers.
int lenient_strcmp(const char *a, const char *b) {
if (a == b) {
return 0;
} else if (!a) {
return -1;
} else if (!b) {
return 1;
} else {
return strcmp(a, b);
}
}
list_t *split_string(const char *str, const char *delims) {
list_t *res = create_list();
char *copy = strdup(str);
char *token = strtok(copy, delims);
while (token) {
list_add(res, strdup(token));
token = strtok(NULL, delims);
}
free(copy);
return res;
}
char **split_args(const char *start, int *argc) {
*argc = 0;
int alloc = 2;
char **argv = malloc(sizeof(char *) * alloc);
bool in_token = false;
bool in_string = false;
bool in_char = false;
bool in_brackets = false; // brackets are used for criteria
bool escaped = false;
const char *end = start;
if (start) {
while (*start) {
if (!in_token) {
start = (end += strspn(end, whitespace));
in_token = true;
}
if (*end == '"' && !in_char && !escaped) {
in_string = !in_string;
} else if (*end == '\'' && !in_string && !escaped) {
in_char = !in_char;
} else if (*end == '[' && !in_string && !in_char && !in_brackets && !escaped) {
in_brackets = true;
} else if (*end == ']' && !in_string && !in_char && in_brackets && !escaped) {
in_brackets = false;
} else if (*end == '\\') {
escaped = !escaped;
} else if (*end == '\0' || (!in_string && !in_char && !in_brackets
&& !escaped && strchr(whitespace, *end))) {
goto add_token;
}
if (*end != '\\') {
escaped = false;
}
++end;
continue;
add_token:
if (end - start > 0) {
char *token = malloc(end - start + 1);
strncpy(token, start, end - start + 1);
token[end - start] = '\0';
argv[*argc] = token;
if (++*argc + 1 == alloc) {
argv = realloc(argv, (alloc *= 2) * sizeof(char *));
}
}
in_token = false;
escaped = false;
}
}
argv[*argc] = NULL;
return argv;
}
void free_argv(int argc, char **argv) {
while (argc-- > 0) {
free(argv[argc]);
}
free(argv);
}
int unescape_string(char *string) {
/* TODO: More C string escapes */
int len = strlen(string);
int i;
for (i = 0; string[i]; ++i) {
if (string[i] == '\\') {
switch (string[++i]) {
case '0':
string[i - 1] = '\0';
return i - 1;
case 'a':
string[i - 1] = '\a';
string[i] = '\0';
break;
case 'b':
string[i - 1] = '\b';
string[i] = '\0';
break;
case 'f':
string[i - 1] = '\f';
string[i] = '\0';
break;
case 'n':
string[i - 1] = '\n';
string[i] = '\0';
break;
case 'r':
string[i - 1] = '\r';
string[i] = '\0';
break;
case 't':
string[i - 1] = '\t';
string[i] = '\0';
break;
case 'v':
string[i - 1] = '\v';
string[i] = '\0';
break;
case '\\':
string[i] = '\0';
break;
case '\'':
string[i - 1] = '\'';
string[i] = '\0';
break;
case '\"':
string[i - 1] = '\"';
string[i] = '\0';
break;
case '?':
string[i - 1] = '?';
string[i] = '\0';
break;
case 'x':
{
unsigned char c = 0;
if (string[i+1] >= '0' && string[i+1] <= '9') {
c = string[i+1] - '0';
if (string[i+2] >= '0' && string[i+2] <= '9') {
c *= 0x10;
c += string[i+2] - '0';
string[i+2] = '\0';
}
string[i+1] = '\0';
}
string[i] = '\0';
string[i - 1] = c;
}
}
}
}
// Shift characters over nullspaces
int shift = 0;
for (i = 0; i < len; ++i) {
if (string[i] == 0) {
shift++;
continue;
}
string[i-shift] = string[i];
}
string[len - shift] = 0;
return len - shift;
}
char *join_args(char **argv, int argc) {
if (!sway_assert(argc > 0, "argc should be positive")) {
return NULL;
}
int len = 0, i;
for (i = 0; i < argc; ++i) {
len += strlen(argv[i]) + 1;
}
char *res = malloc(len);
len = 0;
for (i = 0; i < argc; ++i) {
strcpy(res + len, argv[i]);
len += strlen(argv[i]);
res[len++] = ' ';
}
res[len - 1] = '\0';
return res;
}
static inline char *argsep_next_interesting(const char *src, const char *delim) {
char *special = strpbrk(src, "\"'\\");
char *next_delim = strpbrk(src, delim);
if (!special) {
return next_delim;
}
if (!next_delim) {
return special;
}
return (next_delim < special) ? next_delim : special;
}
char *argsep(char **stringp, const char *delim, char *matched) {
char *start = *stringp;
char *end = start;
bool in_string = false;
bool in_char = false;
bool escaped = false;
char *interesting = NULL;
while ((interesting = argsep_next_interesting(end, delim))) {
if (escaped && interesting != end) {
escaped = false;
}
if (*interesting == '"' && !in_char && !escaped) {
in_string = !in_string;
end = interesting + 1;
} else if (*interesting == '\'' && !in_string && !escaped) {
in_char = !in_char;
end = interesting + 1;
} else if (*interesting == '\\') {
escaped = !escaped;
end = interesting + 1;
} else if (!in_string && !in_char && !escaped) {
// We must have matched a separator
end = interesting;
if (matched) {
*matched = *end;
}
if (end - start) {
*(end++) = 0;
*stringp = end;
break;
} else {
end = ++start;
}
} else {
end++;
}
}
if (!interesting) {
*stringp = NULL;
if (matched) {
*matched = '\0';
}
}
return start;
}
bool expand_path(char **path) {
wordexp_t p = {0};
while (strstr(*path, " ")) {
*path = realloc(*path, strlen(*path) + 2);
char *ptr = strstr(*path, " ") + 1;
memmove(ptr + 1, ptr, strlen(ptr) + 1);
*ptr = '\\';
}
if (wordexp(*path, &p, 0) != 0 || p.we_wordv[0] == NULL) {
wordfree(&p);
return false;
}
free(*path);
*path = join_args(p.we_wordv, p.we_wordc);
wordfree(&p);
return true;
}
char *vformat_str(const char *fmt, va_list args) {
char *str = NULL;
va_list args_copy;
va_copy(args_copy, args);
int len = vsnprintf(NULL, 0, fmt, args);
if (len < 0) {
sway_log_errno(SWAY_ERROR, "vsnprintf(\"%s\") failed", fmt);
goto out;
}
str = malloc(len + 1);
if (str == NULL) {
sway_log_errno(SWAY_ERROR, "malloc() failed");
goto out;
}
vsnprintf(str, len + 1, fmt, args_copy);
out:
va_end(args_copy);
return str;
}
char *format_str(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
char *str = vformat_str(fmt, args);
va_end(args);
return str;
}
bool has_prefix(const char *str, const char *prefix) {
return strncmp(str, prefix, strlen(prefix)) == 0;
}

149
common/util.c Normal file
View file

@ -0,0 +1,149 @@
#include <ctype.h>
#include <fcntl.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <wayland-server-protocol.h>
#include "log.h"
#include "util.h"
int wrap(int i, int max) {
return ((i % max) + max) % max;
}
bool parse_color(const char *color, uint32_t *result) {
if (color[0] == '#') {
++color;
}
int len = strlen(color);
if ((len != 6 && len != 8) || !isxdigit(color[0]) || !isxdigit(color[1])) {
return false;
}
char *ptr;
uint32_t parsed = strtoul(color, &ptr, 16);
if (*ptr != '\0') {
return false;
}
*result = len == 6 ? ((parsed << 8) | 0xFF) : parsed;
return true;
}
void color_to_rgba(float dest[static 4], uint32_t color) {
dest[0] = ((color >> 24) & 0xff) / 255.0;
dest[1] = ((color >> 16) & 0xff) / 255.0;
dest[2] = ((color >> 8) & 0xff) / 255.0;
dest[3] = (color & 0xff) / 255.0;
}
bool parse_boolean(const char *boolean, bool current) {
if (strcasecmp(boolean, "1") == 0
|| strcasecmp(boolean, "yes") == 0
|| strcasecmp(boolean, "on") == 0
|| strcasecmp(boolean, "true") == 0
|| strcasecmp(boolean, "enable") == 0
|| strcasecmp(boolean, "enabled") == 0
|| strcasecmp(boolean, "active") == 0) {
return true;
} else if (strcasecmp(boolean, "toggle") == 0) {
return !current;
}
// All other values are false to match i3
return false;
}
float parse_float(const char *value) {
errno = 0;
char *end;
float flt = strtof(value, &end);
if (*end || errno) {
sway_log(SWAY_DEBUG, "Invalid float value '%s', defaulting to NAN", value);
return NAN;
}
return flt;
}
enum movement_unit parse_movement_unit(const char *unit) {
if (strcasecmp(unit, "px") == 0) {
return MOVEMENT_UNIT_PX;
}
if (strcasecmp(unit, "ppt") == 0) {
return MOVEMENT_UNIT_PPT;
}
if (strcasecmp(unit, "default") == 0) {
return MOVEMENT_UNIT_DEFAULT;
}
return MOVEMENT_UNIT_INVALID;
}
int parse_movement_amount(int argc, char **argv,
struct movement_amount *amount) {
if (!sway_assert(argc > 0, "Expected args in parse_movement_amount")) {
amount->amount = 0;
amount->unit = MOVEMENT_UNIT_INVALID;
return 0;
}
char *err;
amount->amount = (int)strtol(argv[0], &err, 10);
if (*err) {
// e.g. 10px
amount->unit = parse_movement_unit(err);
return 1;
}
if (argc == 1) {
amount->unit = MOVEMENT_UNIT_DEFAULT;
return 1;
}
// Try the second argument
amount->unit = parse_movement_unit(argv[1]);
if (amount->unit == MOVEMENT_UNIT_INVALID) {
amount->unit = MOVEMENT_UNIT_DEFAULT;
return 1;
}
return 2;
}
const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel) {
switch (subpixel) {
case WL_OUTPUT_SUBPIXEL_UNKNOWN:
return "unknown";
case WL_OUTPUT_SUBPIXEL_NONE:
return "none";
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
return "rgb";
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
return "bgr";
case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
return "vrgb";
case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
return "vbgr";
}
sway_assert(false, "Unknown value for wl_output_subpixel.");
return NULL;
}
bool sway_set_cloexec(int fd, bool cloexec) {
int flags = fcntl(fd, F_GETFD);
if (flags == -1) {
sway_log_errno(SWAY_ERROR, "fcntl failed");
return false;
}
if (cloexec) {
flags = flags | FD_CLOEXEC;
} else {
flags = flags & ~FD_CLOEXEC;
}
if (fcntl(fd, F_SETFD, flags) == -1) {
sway_log_errno(SWAY_ERROR, "fcntl failed");
return false;
}
return true;
}
uint32_t get_current_time_in_msec(void) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return now.tv_sec * 1000 + now.tv_nsec / 1000000;
}

46
completions/bash/sway Normal file
View file

@ -0,0 +1,46 @@
# sway(1) completion
_sway()
{
local cur prev short long
_get_comp_words_by_ref cur prev
short=(
-h
-c
-C
-d
-v
-V
)
long=(
--help
--config
--validate
--debug
--version
--verbose
--get-socketpath
)
case $prev in
-c|--config)
_filedir
return
;;
esac
if [[ $cur == --* ]]; then
COMPREPLY=($(compgen -W "${long[*]}" -- "$cur"))
elif [[ $cur == -* ]]; then
COMPREPLY=($(compgen -W "${short[*]}" -- "$cur"))
COMPREPLY+=($(compgen -W "${long[*]}" -- "$cur"))
else
COMPREPLY=($(compgen -W "${short[*]}" -- "$cur"))
COMPREPLY+=($(compgen -W "${long[*]}" -- "$cur"))
COMPREPLY+=($(compgen -c -- "$cur"))
fi
} &&
complete -F _sway sway

44
completions/bash/swaybar Normal file
View file

@ -0,0 +1,44 @@
# swaybar(1) completion
_swaybar()
{
local cur prev short long
_get_comp_words_by_ref cur prev
short=(
-h
-v
-s
-b
-d
)
long=(
--help
--version
--socket
--bar_id
--debug
)
case $prev in
-s|--socket)
_filedir
return
;;
-b|--bar_id)
bars=($(swaymsg -t get_bar_config | jq -r '.[]'))
COMPREPLY=($(compgen -W "${bars[*]}" -- "$cur"))
return
;;
esac
if [[ $cur == --* ]]; then
COMPREPLY=($(compgen -W "${long[*]}" -- "$cur"))
else
COMPREPLY=($(compgen -W "${short[*]}" -- "$cur"))
COMPREPLY+=($(compgen -W "${long[*]}" -- "$cur"))
fi
} &&
complete -F _swaybar swaybar

65
completions/bash/swaymsg Normal file
View file

@ -0,0 +1,65 @@
# swaymsg(1) completion
_swaymsg()
{
local cur prev types short long
_get_comp_words_by_ref cur prev
types=(
'get_workspaces'
'get_seats'
'get_inputs'
'get_outputs'
'get_tree'
'get_marks'
'get_bar_config'
'get_version'
'get_binding_modes'
'get_binding_state'
'get_config'
'send_tick'
'subscribe'
)
short=(
-h
-m
-p
-q
-r
-s
-t
-v
)
long=(
--help
--monitor
--pretty
--quiet
--raw
--socket
--type
--version
)
case $prev in
-s|--socket)
_filedir
return
;;
-t|--type)
COMPREPLY=($(compgen -W "${types[*]}" -- "$cur"))
return
;;
esac
if [[ $cur == --* ]]; then
COMPREPLY=($(compgen -W "${long[*]}" -- "$cur"))
else
COMPREPLY=($(compgen -W "${short[*]}" -- "$cur"))
COMPREPLY+=($(compgen -W "${long[*]}" -- "$cur"))
fi
} &&
complete -F _swaymsg swaymsg

View file

@ -0,0 +1,11 @@
# sway(1) completion
complete -f -c sway
complete -c sway -s h -l help --description "Show help message and quit."
complete -c sway -s c -l config --description "Specifies a config file." -r
complete -c sway -s C -l validate --description "Check the validity of the config file, then exit."
complete -c sway -s d -l debug --description "Enables full logging, including debug information."
complete -c sway -s v -l version --description "Show the version number and quit."
complete -c sway -s V -l verbose --description "Enables more verbose logging."
complete -c sway -l get-socketpath --description "Gets the IPC socket path and prints it, then exits."

View file

@ -0,0 +1,25 @@
# swaymsg(1) completion
complete -f -c swaymsg
complete -c swaymsg -s h -l help --description "Show help message and quit."
complete -c swaymsg -s m -l monitor --description "Monitor subscribed events until killed."
complete -c swaymsg -s p -l pretty --description "Use pretty output even when not using a tty."
complete -c swaymsg -s q -l quiet --description "Sends the IPC message but does not print the response from sway."
complete -c swaymsg -s r -l raw --description "Use raw output even if using tty."
complete -c swaymsg -s s -l socket -r --description "Use the specified socket path. Otherwise, swaymsg will ask where the socket is (which is the value of $SWAYSOCK, then of $I3SOCK)."
complete -c swaymsg -s v -l version --description "Print the version (of swaymsg) and quit."
complete -c swaymsg -s t -l type -fr --description "Specify the type of IPC message."
complete -c swaymsg -s t -l type -fra 'get_workspaces' --description "Gets a JSON-encoded list of workspaces and their status."
complete -c swaymsg -s t -l type -fra 'get_inputs' --description "Gets a JSON-encoded list of current inputs."
complete -c swaymsg -s t -l type -fra 'get_outputs' --description "Gets a JSON-encoded list of current outputs."
complete -c swaymsg -s t -l type -fra 'get_tree' --description "Gets a JSON-encoded layout tree of all open windows, containers, outputs, workspaces, and so on."
complete -c swaymsg -s t -l type -fra 'get_marks' --description "Get a JSON-encoded list of marks."
complete -c swaymsg -s t -l type -fra 'get_bar_config' --description "Get a JSON-encoded configuration for swaybar."
complete -c swaymsg -s t -l type -fra 'get_version' --description "Get JSON-encoded version information for the running instance of sway."
complete -c swaymsg -s t -l type -fra 'get_binding_modes' --description "Gets a JSON-encoded list of currently configured binding modes."
complete -c swaymsg -s t -l type -fra 'get_binding_state' --description "Get JSON-encoded info about the current binding state."
complete -c swaymsg -s t -l type -fra 'get_config' --description "Gets a JSON-encoded copy of the current configuration."
complete -c swaymsg -s t -l type -fra 'get_seats' --description "Gets a JSON-encoded list of all seats, its properties and all assigned devices."
complete -c swaymsg -s t -l type -fra 'send_tick' --description "Sends a tick event to all subscribed clients."
complete -c swaymsg -s t -l type -fra 'subscribe' --description "Subscribe to a list of event types."

View file

@ -0,0 +1,30 @@
# swaynag
complete -f -c swaynag
complete -c swaynag -s C -l config -r --description 'The config file to use. Default: $HOME/.swaynag/config, $XDG_CONFIG_HOME/swaynag/config, and SYSCONFDIR/swaynag/config.'
complete -c swaynag -s d -l debug --description 'Enable debugging.'
complete -c swaynag -s e -l edge -fr --description 'Set the edge to use: top or bottom'
complete -c swaynag -s f -l font -r --description 'Set the font to use.'
complete -c swaynag -s h -l help --description 'Show help message and quit.'
complete -c swaynag -s b -l button -fr --description 'Create a button with a text and an action which is executed when pressed. Multiple buttons can be defined by providing the flag multiple times.'
complete -c swaynag -s l -l detailed-message --description 'Read a detailed message from stdin. A button to toggle details will be added. Details are shown in a scrollable multi-line text area.'
complete -c swaynag -s L -l detailed-button -fr --description 'Set the text for the button that toggles details. This has no effect if there is not a detailed message. The default is "Toggle details".'
complete -c swaynag -s m -l message -fr --description 'Set the message text.'
complete -c swaynag -s o -l output -fr --description 'Set the output to use.'
complete -c swaynag -s s -l dismiss-button -fr --description 'Sets the text for the dismiss nagbar button. The default is "X".'
complete -c swaynag -s t -l type -fr --description 'Set the message type. Two types are created by default "error" and "warning". Custom types can be defined in the config file.'
complete -c swaynag -s v -l version --description 'Show the version number and quit.'
# Appearance
complete -c swaynag -l background -fr --description 'Set the color of the background.'
complete -c swaynag -l border -fr --description 'Set the color of the border.'
complete -c swaynag -l border-bottom -fr --description 'Set the color of the bottom border.'
complete -c swaynag -l button-background -fr --description 'Set the color for the background for buttons.'
complete -c swaynag -l text -fr --description 'Set the text color.'
complete -c swaynag -l border-bottom-size -fr --description 'Set the thickness of the bottom border.'
complete -c swaynag -l message-padding -fr --description 'Set the padding for the message.'
complete -c swaynag -l details-border-size -fr --description 'Set the thickness for the details border.'
complete -c swaynag -l button-border-size -fr --description 'Set the thickness for the button border.'
complete -c swaynag -l button-gap -fr --description 'Set the size of the gap between buttons.'
complete -c swaynag -l button-dismiss-gap -fr --description 'Set the size of the gap between the dismiss button and another button.'
complete -c swaynag -l button-margin-right -fr --description 'Set the margin from the right of the dismiss button to edge.'
complete -c swaynag -l button-padding -fr --description 'Set the padding for the button text.'

57
completions/meson.build Normal file
View file

@ -0,0 +1,57 @@
if get_option('zsh-completions')
zsh_files = files(
'zsh/_sway',
'zsh/_swaymsg',
)
zsh_install_dir = join_paths(datadir, 'zsh', 'site-functions')
install_data(zsh_files, install_dir: zsh_install_dir)
endif
if get_option('bash-completions')
bash_comp = dependency('bash-completion', required: false)
bash_files = files(
'bash/sway',
'bash/swaymsg',
)
if get_option('swaybar')
bash_files += files('bash/swaybar')
endif
if bash_comp.found()
bash_install_dir = bash_comp.get_variable(
pkgconfig: 'completionsdir',
pkgconfig_define: ['datadir', datadir]
)
else
bash_install_dir = join_paths(datadir, 'bash-completion', 'completions')
endif
install_data(bash_files, install_dir: bash_install_dir)
endif
if get_option('fish-completions')
fish_comp = dependency('fish', required: false)
fish_files = files(
'fish/sway.fish',
'fish/swaymsg.fish',
)
if get_option('swaynag')
fish_files += files('fish/swaynag.fish')
endif
if fish_comp.found()
fish_install_dir = fish_comp.get_variable(
pkgconfig: 'completionsdir',
pkgconfig_define: ['datadir', datadir]
)
else
fish_install_dir = join_paths(datadir, 'fish', 'vendor_completions.d')
endif
install_data(fish_files, install_dir: fish_install_dir)
endif

22
completions/zsh/_sway Normal file
View file

@ -0,0 +1,22 @@
#compdef sway
#------------
# Description
# -----------
#
# Completion script for the sway window manager (http://swaywm.org)
#
# ---------------------------------------------
# Author
# -------
#
# * Seth Barberee <seth.barberee@gmail.com>
#
# -------------------------------
_arguments -s \
'(-v --version)'{-v,--version}'[Show the version number and quit]' \
'(-h --help)'{-h,--help}'[Show help message and quit]' \
'(-c --config)'{-c,--config}'[Specify a config file]:files:_files' \
'(-C --validate)'{-C,--validate}'[Check validity of the config file, then exit]' \
'(-d --debug)'{-d,--debug}'[Enables full logging, including debug information]' \
'(-V --verbose)'{-V,--verbose}'[Enables more verbose logging]' \
'(--get-socketpath)'--get-socketpath'[Gets the IPC socket path and prints it, then exits]'

13
completions/zsh/_swaybar Normal file
View file

@ -0,0 +1,13 @@
#compdef swaybar
#
# Completion script for swaybar
#
local bars=($(swaymsg -t get_bar_config | jq -r '.[]'))
_arguments -s \
'(-h --help)'{-h,--help}'[Show help message and quit]' \
'(-v --version)'{-v,--version}'[Show version and quit]' \
'(-s --socket)'{-s,--socket}'[Connect to sway via socket]:filename:_files' \
'(-b --bar_id)'{-b,--bar-id}'[Bar ID for which to get the configuration]:filename:($bars)'\
'(-d --debug)'{-d,--debug}'[Enable debugging]'

40
completions/zsh/_swaymsg Normal file
View file

@ -0,0 +1,40 @@
#compdef swaymsg
#-----------------
# Description
# -----------
#
# Completion script for swaymsg in sway wm (http://swaywm.org)
#
# ------------------------------------------------------
# Author
# --------
#
# * Seth Barberee <seth.barberee@gmail.com>
#
# -------------------------------------------
types=(
'get_workspaces'
'get_seats'
'get_inputs'
'get_outputs'
'get_tree'
'get_marks'
'get_bar_config'
'get_version'
'get_binding_modes'
'get_binding_state'
'get_config'
'send_tick'
'subscribe'
)
_arguments -s \
'(-h --help)'{-h,--help}'[Show help message and quit]' \
'(-m --monitor)'{-m,--monitor}'[Monitor until killed (-t SUBSCRIBE only)]' \
'(-p --pretty)'{-p,--pretty}'[Use pretty output even when not using a tty]' \
'(-q --quiet)'{-q,--quiet}'[Be quiet]' \
'(-r --raw)'{-r,--raw}'[Use raw output even if using a tty]' \
'(-s --socket)'{-s,--socket}'[Use the specified socket path]:files:_files' \
'(-t --type)'{-t,--type}'[Specify the message type]:type:{_describe "type" types}' \
'(-v --version)'{-v,--version}'[Show the version number and quit]'

13
compose.yml Normal file
View file

@ -0,0 +1,13 @@
services:
swayfxbuild:
container_name: swayfxbuild
build:
args:
WLROOTSVERSION: 0.19.0
WLROOTSLIBVERSION: 0.19
SWAYFXVERSION: 0.5.3
SCENEFXVERSION: 0.4.1
SCENEFXLIBVERSION: 0.4
OPT_SWAYFX: /opt
volumes:
- ./opt:/opt

281
config.in Normal file
View file

@ -0,0 +1,281 @@
# SwayFX settings
animation_duration_ms 250
blur disable
# blur_xray enables wallpaper blurring without blurring windows below
blur_xray disable
blur_passes 4
blur_radius 4
# blur_noise <float value 0 - 1>
# blur_brightness <float value 0 - 2>
# blur_contrast <float value 0 - 2>
# blur_saturation <float value 0 - 2>
# Window corners can be rounded in SwayFX
# corner_radius can be any number of pixels
corner_radius 15
gaps inner 15
# corner radius needs gaps to be visible
# SwayFX also features window drop shadows, which, of course, can be enabled at any time
shadows disable
shadows_on_csd enable
# You can also offset the shadow's position, make unfocused windows have different shadows, give shadows a nondefault color, and blur shadows
# shadow_inactive_color #0000007F
# shadow_offset <x offset> <y offset>
# shadow_blur_radius <integer value 0 - 99>
# shadow_color <hex color with alpha>
# Dimming
# default_dim_inactive <float value 0.0 - 1.0>
# for_window [CRITERIA_HERE] dim_inactive <float value 0.0 - 1.0>
# dim_inactive_colors.unfocused <hex color>
# dim_inactive_colors.urgent <hex color>
# Default config for Sway
#
# Copy this to ~/.config/sway/config and edit it to your liking.
#
# Read `man 5 sway` for a complete reference.
### Variables
#
# Logo key. Use Mod1 for Alt.
set $mod Mod1
# Home row direction keys, like vim
set $left h
set $down j
set $up k
set $right l
# Your preferred terminal emulator
set $term foot
# Your preferred application launcher
set $menu wmenu-run
### Output configuration
#
# Default wallpaper (more resolutions are available in @datadir@/backgrounds/sway/)
output * bg @datadir@/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill
#
# Example configuration:
#
# output HDMI-A-1 resolution 1920x1080 position 1920,0
#
# You can get the names of your outputs by running: swaymsg -t get_outputs
### Idle configuration
#
# Example configuration:
#
# exec swayidle -w \
# timeout 300 'swaylock -f -c 000000' \
# timeout 600 'swaymsg "output * power off"' resume 'swaymsg "output * power on"' \
# before-sleep 'swaylock -f -c 000000'
#
# This will lock your screen after 300 seconds of inactivity, then turn off
# your displays after another 300 seconds, and turn your screens back on when
# resumed. It will also lock your screen before your computer goes to sleep.
### Input configuration
#
# Example configuration:
#
# input type:touchpad {
# dwt enabled
# tap enabled
# natural_scroll enabled
# middle_emulation enabled
# }
#
# input type:keyboard {
# xkb_layout "eu"
# }
#
# You can also configure each device individually.
# Read `man 5 sway-input` for more information about this section.
### Key bindings
#
# Basics:
#
# Start a terminal
bindsym $mod+Return exec $term
# Kill focused window
bindsym $mod+Shift+q kill
# Start your launcher
bindsym $mod+d exec $menu
# Drag floating windows by holding down $mod and left mouse button.
# Resize them with right mouse button + $mod.
# Despite the name, also works for non-floating windows.
# Change normal to inverse to use left mouse button for resizing and right
# mouse button for dragging.
floating_modifier $mod normal
# Reload the configuration file
bindsym $mod+Shift+c reload
# Exit SwayFX (logs you out of your Wayland session)
bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit SwayFX? This will end your Wayland session.' -B 'Yes, exit SwayFX' 'swaymsg exit'
#
# Moving around:
#
# Move your focus around
bindsym $mod+$left focus left
bindsym $mod+$down focus down
bindsym $mod+$up focus up
bindsym $mod+$right focus right
# Or use $mod+[up|down|left|right]
bindsym $mod+Left focus left
bindsym $mod+Down focus down
bindsym $mod+Up focus up
bindsym $mod+Right focus right
# Move the focused window with the same, but add Shift
bindsym $mod+Shift+$left move left
bindsym $mod+Shift+$down move down
bindsym $mod+Shift+$up move up
bindsym $mod+Shift+$right move right
# Ditto, with arrow keys
bindsym $mod+Shift+Left move left
bindsym $mod+Shift+Down move down
bindsym $mod+Shift+Up move up
bindsym $mod+Shift+Right move right
#
# Workspaces:
#
# Switch to workspace
bindsym $mod+1 workspace number 1
bindsym $mod+2 workspace number 2
bindsym $mod+3 workspace number 3
bindsym $mod+4 workspace number 4
bindsym $mod+5 workspace number 5
bindsym $mod+6 workspace number 6
bindsym $mod+7 workspace number 7
bindsym $mod+8 workspace number 8
bindsym $mod+9 workspace number 9
bindsym $mod+0 workspace number 10
# Move focused container to workspace
bindsym $mod+Shift+1 move container to workspace number 1
bindsym $mod+Shift+2 move container to workspace number 2
bindsym $mod+Shift+3 move container to workspace number 3
bindsym $mod+Shift+4 move container to workspace number 4
bindsym $mod+Shift+5 move container to workspace number 5
bindsym $mod+Shift+6 move container to workspace number 6
bindsym $mod+Shift+7 move container to workspace number 7
bindsym $mod+Shift+8 move container to workspace number 8
bindsym $mod+Shift+9 move container to workspace number 9
bindsym $mod+Shift+0 move container to workspace number 10
# Note: workspaces can have any name you want, not just numbers.
# We just use 1-10 as the default.
#
# Layout stuff:
#
# You can "split" the current object of your focus with
# $mod+b or $mod+v, for horizontal and vertical splits
# respectively.
bindsym $mod+b splith
bindsym $mod+v splitv
# Switch the current container between different layout styles
bindsym $mod+s layout stacking
bindsym $mod+w layout tabbed
bindsym $mod+e layout toggle split
# Make the current focus fullscreen
bindsym $mod+f fullscreen
# Toggle the current focus between tiling and floating mode
bindsym $mod+Shift+space floating toggle
# Swap focus between the tiling area and the floating area
bindsym $mod+space focus mode_toggle
# Move focus to the parent container
bindsym $mod+a focus parent
#
# Scratchpad:
#
# SwayFX has a "scratchpad", which is a bag of holding for windows.
# You can send windows there and get them back later.
# Move the currently focused window to the scratchpad
bindsym $mod+Shift+minus move scratchpad
# Show the next scratchpad window or hide the focused scratchpad window.
# If there are multiple scratchpad windows, this command cycles through them.
bindsym $mod+minus scratchpad show
#
# Resizing containers:
#
mode "resize" {
# left will shrink the containers width
# right will grow the containers width
# up will shrink the containers height
# down will grow the containers height
bindsym $left resize shrink width 10px
bindsym $down resize grow height 10px
bindsym $up resize shrink height 10px
bindsym $right resize grow width 10px
# Ditto, with arrow keys
bindsym Left resize shrink width 10px
bindsym Down resize grow height 10px
bindsym Up resize shrink height 10px
bindsym Right resize grow width 10px
# Return to default mode
bindsym Return mode "default"
bindsym Escape mode "default"
}
bindsym $mod+r mode "resize"
#
# Utilities:
#
# Special keys to adjust volume via PulseAudio
bindsym --locked XF86AudioMute exec pactl set-sink-mute \@DEFAULT_SINK@ toggle
bindsym --locked XF86AudioLowerVolume exec pactl set-sink-volume \@DEFAULT_SINK@ -5%
bindsym --locked XF86AudioRaiseVolume exec pactl set-sink-volume \@DEFAULT_SINK@ +5%
bindsym --locked XF86AudioMicMute exec pactl set-source-mute \@DEFAULT_SOURCE@ toggle
# Special keys to adjust brightness via brightnessctl
bindsym --locked XF86MonBrightnessDown exec brightnessctl set 5%-
bindsym --locked XF86MonBrightnessUp exec brightnessctl set 5%+
# Special keys to control media via playerctl
bindsym --locked XF86AudioPlay exec playerctl play-pause
bindsym --locked XF86AudioPause exec playerctl play-pause
bindsym --locked XF86AudioPrev exec playerctl previous
bindsym --locked XF86AudioNext exec playerctl next
bindsym --locked XF86AudioStop exec playerctl stop
# Special keys to adjust brightness via brightnessctl
bindsym --locked XF86MonBrightnessDown exec brightnessctl set 5%-
bindsym --locked XF86MonBrightnessUp exec brightnessctl set 5%+
# Special key to take a screenshot with grim
bindsym Print exec grim
#
# Status Bar:
#
# Read `man 5 sway-bar` for more information about this section.
bar {
position top
# When the status_command prints a new line to stdout, swaybar updates.
# The default just shows the current date and time.
status_command while date +'%Y-%m-%d %X'; do sleep 1; done
colors {
statusline #ffffff
background #323232
inactive_workspace #32323200 #32323200 #5c5c5c
}
}
include @sysconfdir@/sway/config.d/*

104
flake.lock Normal file
View file

@ -0,0 +1,104 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1783791668,
"narHash": "sha256-zbcZ1dmBTPfJ7Mlqh/yLEPGpgJnwuv4Xr1xucy2WqMA=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "716c7a2664ca8325617b8a7fbb609273f2c4cae7",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"scenefx": "scenefx",
"systems": "systems_2"
}
},
"scenefx": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
],
"systems": "systems"
},
"locked": {
"lastModified": 1782624992,
"narHash": "sha256-vUjLG6eubEhJJVa9LPygIcVmNoHwYbSUTJcWEcbxnU4=",
"owner": "wlrfx",
"repo": "scenefx",
"rev": "37ccd723bef49e6891156ffafce8f549f01446cc",
"type": "github"
},
"original": {
"owner": "wlrfx",
"repo": "scenefx",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1689347949,
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
"owner": "nix-systems",
"repo": "default-linux",
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default-linux",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1689347949,
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
"owner": "nix-systems",
"repo": "default-linux",
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default-linux",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

85
flake.nix Normal file
View file

@ -0,0 +1,85 @@
{
description = "Swayfx development environment";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
systems.url = "github:nix-systems/default-linux";
flake-utils = {
url = "github:numtide/flake-utils";
inputs.systems.follows = "systems";
};
scenefx = {
url = "github:wlrfx/scenefx";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
};
};
outputs = { self, nixpkgs, flake-utils, scenefx, ... }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
scenefx-git = scenefx.packages.${system}.scenefx-git;
in {
packages = rec {
swayfx-unwrapped-git = pkgs.swayfx-unwrapped.overrideAttrs(old: {
version = "git";
src = pkgs.lib.cleanSource ./.;
nativeBuildInputs = with pkgs; [
meson
ninja
pkg-config
wayland-scanner
scdoc
];
buildInputs = with pkgs; [
libGL
wayland
libxkbcommon
pcre2
json_c
libevdev
pango
cairo
libinput
gdk-pixbuf
librsvg
wayland-protocols
libdrm
libxcb-wm
wlroots_0_20
] ++ [ scenefx-git ];
});
default = swayfx-unwrapped-git;
};
devShells.default = pkgs.mkShell {
name = "swayfx-shell";
inputsFrom = [
self.packages.${system}.swayfx-unwrapped-git
scenefx-git
];
packages = [ pkgs.gdb ]; # add debugging packages
shellHook = ''
(
mkdir -p "$PWD/subprojects" && cd "$PWD/subprojects"
if [ ! -d scenefx ]; then
echo "Copying scenefx to ./subprojects..."
cp -R --no-preserve=mode,ownership ${scenefx-git.src} scenefx
fi
cd "$OLDPWD"
) || echo "Failed to copy subproject sources."
'';
hardeningDisable = [ "fortify" ];
};
formatter = pkgs.nixfmt-rfc-style;
}
);
}

14
include/cairo_util.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef _SWAY_CAIRO_UTIL_H
#define _SWAY_CAIRO_UTIL_H
#include "config.h"
#include <stdint.h>
#include <cairo.h>
#include <wayland-client-protocol.h>
void cairo_set_source_u32(cairo_t *cairo, uint32_t color);
cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel);
cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image,
int width, int height);
#endif

104
include/gesture.h Normal file
View file

@ -0,0 +1,104 @@
#ifndef _SWAY_GESTURE_H
#define _SWAY_GESTURE_H
#include <stdbool.h>
#include <stdint.h>
/**
* A gesture type used in binding.
*/
enum gesture_type {
GESTURE_TYPE_NONE = 0,
GESTURE_TYPE_HOLD,
GESTURE_TYPE_PINCH,
GESTURE_TYPE_SWIPE,
};
// Turns single type enum value to constant string representation.
const char *gesture_type_string(enum gesture_type direction);
// Value to use to accept any finger count
extern const uint8_t GESTURE_FINGERS_ANY;
/**
* A gesture direction used in binding.
*/
enum gesture_direction {
GESTURE_DIRECTION_NONE = 0,
// Directions based on delta x and y
GESTURE_DIRECTION_UP = 1 << 0,
GESTURE_DIRECTION_DOWN = 1 << 1,
GESTURE_DIRECTION_LEFT = 1 << 2,
GESTURE_DIRECTION_RIGHT = 1 << 3,
// Directions based on scale
GESTURE_DIRECTION_INWARD = 1 << 4,
GESTURE_DIRECTION_OUTWARD = 1 << 5,
// Directions based on rotation
GESTURE_DIRECTION_CLOCKWISE = 1 << 6,
GESTURE_DIRECTION_COUNTERCLOCKWISE = 1 << 7,
};
// Turns single direction enum value to constant string representation.
const char *gesture_direction_string(enum gesture_direction direction);
/**
* Struct representing a pointer gesture
*/
struct gesture {
enum gesture_type type;
uint8_t fingers;
uint32_t directions;
};
/**
* Parses gesture from <gesture>[:<fingers>][:<directions>] string.
*
* Return NULL on success, otherwise error message string
*/
char *gesture_parse(const char *input, struct gesture *output);
// Turns gesture into string representation
char *gesture_to_string(struct gesture *gesture);
// Check if gesture is of certain type and finger count.
bool gesture_check(struct gesture *target,
enum gesture_type type, uint8_t fingers);
// Check if a gesture target/binding is match by other gesture/input
bool gesture_match(struct gesture *target,
struct gesture *to_match, bool exact);
// Returns true if gesture are exactly the same
bool gesture_equal(struct gesture *a, struct gesture *b);
// Compare distance between two matched target gestures.
int8_t gesture_compare(struct gesture *a, struct gesture *b);
// Small helper struct to track gestures over time
struct gesture_tracker {
enum gesture_type type;
uint8_t fingers;
double dx, dy;
double scale;
double rotation;
};
// Begin gesture tracking
void gesture_tracker_begin(struct gesture_tracker *tracker,
enum gesture_type type, uint8_t fingers);
// Check if the provides type is currently being tracked
bool gesture_tracker_check(struct gesture_tracker *tracker,
enum gesture_type type);
// Update gesture track with new data point
void gesture_tracker_update(struct gesture_tracker *tracker, double dx,
double dy, double scale, double rotation);
// Reset tracker
void gesture_tracker_cancel(struct gesture_tracker *tracker);
// Reset tracker and return gesture tracked
struct gesture *gesture_tracker_end(struct gesture_tracker *tracker);
#endif

49
include/ipc-client.h Normal file
View file

@ -0,0 +1,49 @@
#ifndef _SWAY_IPC_CLIENT_H
#define _SWAY_IPC_CLIENT_H
// arbitrary number, it's probably sufficient, higher number = more memory usage
#define JSON_MAX_DEPTH 512
#include <stdbool.h>
#include <stdint.h>
#include <sys/time.h>
#include "ipc.h"
/**
* IPC response including type of IPC response, size of payload and the json
* encoded payload string.
*/
struct ipc_response {
uint32_t size;
uint32_t type;
char *payload;
};
/**
* Gets the path to the IPC socket from sway.
*/
char *get_socketpath(void);
/**
* Opens the sway socket.
*/
int ipc_open_socket(const char *socket_path);
/**
* Issues a single IPC command and returns the buffer. len will be updated with
* the length of the buffer returned from sway.
*/
char *ipc_single_command(int socketfd, uint32_t type, const char *payload, uint32_t *len);
/**
* Receives a single IPC response and returns an ipc_response.
*/
struct ipc_response *ipc_recv_response(int socketfd);
/**
* Free ipc_response struct
*/
void free_ipc_response(struct ipc_response *response);
/**
* Sets the receive timeout for the IPC socket
*/
bool ipc_set_recv_timeout(int socketfd, struct timeval tv);
#endif

41
include/ipc.h Normal file
View file

@ -0,0 +1,41 @@
#ifndef _SWAY_IPC_H
#define _SWAY_IPC_H
#define event_mask(ev) (1 << (ev & 0x7F))
enum ipc_command_type {
// i3 command types - see i3's I3_REPLY_TYPE constants
IPC_COMMAND = 0,
IPC_GET_WORKSPACES = 1,
IPC_SUBSCRIBE = 2,
IPC_GET_OUTPUTS = 3,
IPC_GET_TREE = 4,
IPC_GET_MARKS = 5,
IPC_GET_BAR_CONFIG = 6,
IPC_GET_VERSION = 7,
IPC_GET_BINDING_MODES = 8,
IPC_GET_CONFIG = 9,
IPC_SEND_TICK = 10,
IPC_SYNC = 11,
IPC_GET_BINDING_STATE = 12,
// sway-specific command types
IPC_GET_INPUTS = 100,
IPC_GET_SEATS = 101,
// Events sent from sway to clients. Events have the highest bits set.
IPC_EVENT_WORKSPACE = ((1<<31) | 0),
IPC_EVENT_OUTPUT = ((1<<31) | 1),
IPC_EVENT_MODE = ((1<<31) | 2),
IPC_EVENT_WINDOW = ((1<<31) | 3),
IPC_EVENT_BARCONFIG_UPDATE = ((1<<31) | 4),
IPC_EVENT_BINDING = ((1<<31) | 5),
IPC_EVENT_SHUTDOWN = ((1<<31) | 6),
IPC_EVENT_TICK = ((1<<31) | 7),
// sway-specific event types
IPC_EVENT_BAR_STATE_UPDATE = ((1<<31) | 20),
IPC_EVENT_INPUT = ((1<<31) | 21),
};
#endif

35
include/list.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef _SWAY_LIST_H
#define _SWAY_LIST_H
typedef struct {
int capacity;
int length;
void **items;
} list_t;
list_t *create_list(void);
void list_free(list_t *list);
void list_add(list_t *list, void *item);
void list_insert(list_t *list, int index, void *item);
void list_del(list_t *list, int index);
void list_cat(list_t *list, list_t *source);
// See qsort. Remember to use *_qsort functions as compare functions,
// because they dereference the left and right arguments first!
void list_qsort(list_t *list, int compare(const void *left, const void *right));
// Return index for first item in list that returns 0 for given compare
// function or -1 if none matches.
int list_seq_find(list_t *list, int compare(const void *item, const void *cmp_to), const void *cmp_to);
int list_find(list_t *list, const void *item);
// stable sort since qsort is not guaranteed to be stable
void list_stable_sort(list_t *list, int compare(const void *a, const void *b));
// swap two elements in a list
void list_swap(list_t *list, int src, int dest);
// move item to end of list
void list_move_to_end(list_t *list, void *item);
/* Calls `free` for each item in the list, then frees the list.
* Do not use this to free lists of primitives or items that require more
* complicated deallocation code.
*/
void list_free_items_and_destroy(list_t *list);
#endif

58
include/log.h Normal file
View file

@ -0,0 +1,58 @@
#ifndef _SWAY_LOG_H
#define _SWAY_LOG_H
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
typedef enum {
SWAY_SILENT = 0,
SWAY_ERROR = 1,
SWAY_INFO = 2,
SWAY_DEBUG = 3,
SWAY_LOG_IMPORTANCE_LAST,
} sway_log_importance_t;
#ifdef __GNUC__
#define ATTRIB_PRINTF(start, end) __attribute__((format(printf, start, end)))
#else
#define ATTRIB_PRINTF(start, end)
#endif
void error_handler(int sig);
typedef void (*terminate_callback_t)(int exit_code);
// Will log all messages less than or equal to `verbosity`
// The `terminate` callback is called by `sway_abort`
void sway_log_init(sway_log_importance_t verbosity, terminate_callback_t terminate);
void _sway_log(sway_log_importance_t verbosity, const char *format, ...) ATTRIB_PRINTF(2, 3);
void _sway_vlog(sway_log_importance_t verbosity, const char *format, va_list args) ATTRIB_PRINTF(2, 0);
void _sway_abort(const char *filename, ...) ATTRIB_PRINTF(1, 2);
bool _sway_assert(bool condition, const char* format, ...) ATTRIB_PRINTF(2, 3);
#ifdef SWAY_REL_SRC_DIR
// strip prefix from __FILE__, leaving the path relative to the project root
#define _SWAY_FILENAME ((const char *)__FILE__ + sizeof(SWAY_REL_SRC_DIR) - 1)
#else
#define _SWAY_FILENAME __FILE__
#endif
#define sway_log(verb, fmt, ...) \
_sway_log(verb, "[%s:%d] " fmt, _SWAY_FILENAME, __LINE__, ##__VA_ARGS__)
#define sway_vlog(verb, fmt, args) \
_sway_vlog(verb, "[%s:%d] " fmt, _SWAY_FILENAME, __LINE__, args)
#define sway_log_errno(verb, fmt, ...) \
sway_log(verb, fmt ": %s", ##__VA_ARGS__, strerror(errno))
#define sway_abort(FMT, ...) \
_sway_abort("[%s:%d] " FMT, _SWAY_FILENAME, __LINE__, ##__VA_ARGS__)
#define sway_assert(COND, FMT, ...) \
_sway_assert(COND, "[%s:%d] %s:" FMT, _SWAY_FILENAME, __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
#endif

54
include/loop.h Normal file
View file

@ -0,0 +1,54 @@
#ifndef _SWAY_LOOP_H
#define _SWAY_LOOP_H
#include <stdbool.h>
/**
* This is an event loop system designed for sway clients, not sway itself.
*
* The loop consists of file descriptors and timers. Typically the Wayland
* display's file descriptor will be one of the fds in the loop.
*/
struct loop;
struct loop_timer;
/**
* Create an event loop.
*/
struct loop *loop_create(void);
/**
* Destroy the event loop (eg. on program termination).
*/
void loop_destroy(struct loop *loop);
/**
* Poll the event loop. This will block until one of the fds has data.
*/
void loop_poll(struct loop *loop);
/**
* Add a file descriptor to the loop.
*/
void loop_add_fd(struct loop *loop, int fd, short mask,
void (*func)(int fd, short mask, void *data), void *data);
/**
* Add a timer to the loop.
*
* When the timer expires, the timer will be removed from the loop and freed.
*/
struct loop_timer *loop_add_timer(struct loop *loop, int ms,
void (*callback)(void *data), void *data);
/**
* Remove a file descriptor from the loop.
*/
bool loop_remove_fd(struct loop *loop, int fd);
/**
* Remove a timer from the loop.
*/
bool loop_remove_timer(struct loop *loop, struct loop_timer *timer);
#endif

1
include/meson.build Normal file
View file

@ -0,0 +1 @@
configure_file(output: 'config.h', configuration: conf_data)

25
include/pango.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef _SWAY_PANGO_H
#define _SWAY_PANGO_H
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <cairo.h>
#include <pango/pangocairo.h>
#include "stringop.h"
/**
* Utility function which escape characters a & < > ' ".
*
* The function returns the length of the escaped string, optionally writing the
* escaped string to dest if provided.
*/
size_t escape_markup_text(const char *src, char *dest);
PangoLayout *get_pango_layout(cairo_t *cairo, const PangoFontDescription *desc,
const char *text, double scale, bool markup);
void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width, int *height,
int *baseline, double scale, bool markup, const char *fmt, ...) _SWAY_ATTRIB_PRINTF(8, 9);
void get_text_metrics(const PangoFontDescription *desc, int *height, int *baseline);
void render_text(cairo_t *cairo, PangoFontDescription *desc,
double scale, bool markup, const char *fmt, ...) _SWAY_ATTRIB_PRINTF(5, 6);
#endif

24
include/pool-buffer.h Normal file
View file

@ -0,0 +1,24 @@
#ifndef _SWAY_BUFFERS_H
#define _SWAY_BUFFERS_H
#include <cairo.h>
#include <pango/pangocairo.h>
#include <stdbool.h>
#include <stdint.h>
#include <wayland-client.h>
struct pool_buffer {
struct wl_buffer *buffer;
cairo_surface_t *surface;
cairo_t *cairo;
PangoContext *pango;
uint32_t width, height;
void *data;
size_t size;
bool busy;
};
struct pool_buffer *get_next_buffer(struct wl_shm *shm,
struct pool_buffer pool[static 2], uint32_t width, uint32_t height);
void destroy_buffer(struct pool_buffer *buffer);
#endif

45
include/stringop.h Normal file
View file

@ -0,0 +1,45 @@
#ifndef _SWAY_STRINGOP_H
#define _SWAY_STRINGOP_H
#include <stdbool.h>
#include <stddef.h>
#include "list.h"
#ifdef __GNUC__
#define _SWAY_ATTRIB_PRINTF(start, end) __attribute__((format(printf, start, end)))
#else
#define _SWAY_ATTRIB_PRINTF(start, end)
#endif
void strip_whitespace(char *str);
void strip_quotes(char *str);
// strcat that does nothing if dest or src is NULL
char *lenient_strcat(char *dest, const char *src);
char *lenient_strncat(char *dest, const char *src, size_t len);
// strcmp that also handles null pointers.
int lenient_strcmp(const char *a, const char *b);
// Simply split a string with delims, free with `list_free_items_and_destroy`
list_t *split_string(const char *str, const char *delims);
// Splits an argument string, keeping quotes intact
char **split_args(const char *str, int *argc);
void free_argv(int argc, char **argv);
int unescape_string(char *string);
char *join_args(char **argv, int argc);
// Split string into 2 by delim, handle quotes
char *argsep(char **stringp, const char *delim, char *matched_delim);
// Expand a path using shell replacements such as $HOME and ~
bool expand_path(char **path);
char *vformat_str(const char *fmt, va_list args) _SWAY_ATTRIB_PRINTF(1, 0);
char *format_str(const char *fmt, ...) _SWAY_ATTRIB_PRINTF(1, 2);
bool has_prefix(const char *str, const char *prefix);
#endif

View file

@ -0,0 +1,37 @@
#ifndef _SWAY_ANIMATION_MANAGER_H
#define _SWAY_ANIMATION_MANAGER_H
#include <stdbool.h>
#include <wayland-util.h>
struct sway_container;
struct sway_server;
// TODO: make animation just a pointer to progress, make multiplier and callback private
struct animation {
struct wl_list link;
float progress;
void *data;
float multiplier;
bool initialized;
void (*update)(void *);
void (*complete)(void *);
};
void animation_manager_init(struct sway_server *server);
struct animation init_animation(void *data);
void refresh_animation_manager_timing();
void add_animation(struct animation *animation, void (*update_callback)(void *),
void (*complete_callback)(void *));
void finish_animation(struct animation *animation);
void start_animations();
float get_animated_value(float from, float to, const struct animation *animation);
#endif

350
include/sway/commands.h Normal file
View file

@ -0,0 +1,350 @@
#ifndef _SWAY_COMMANDS_H
#define _SWAY_COMMANDS_H
#include <wlr/util/edges.h>
#include "config.h"
#include "stringop.h"
struct sway_container;
typedef struct cmd_results *sway_cmd(int argc, char **argv);
struct cmd_handler {
const char *command;
sway_cmd *handle;
};
/**
* Indicates the result of a command's execution.
*/
enum cmd_status {
CMD_SUCCESS, /**< The command was successful */
CMD_FAILURE, /**< The command resulted in an error */
CMD_INVALID, /**< Unknown command or parser error */
CMD_DEFER, /**< Command execution deferred */
CMD_BLOCK,
CMD_BLOCK_COMMANDS,
CMD_BLOCK_END
};
/**
* Stores the result of executing a command.
*/
struct cmd_results {
enum cmd_status status;
/**
* Human friendly error message, or NULL on success
*/
char *error;
};
enum expected_args {
EXPECTED_AT_LEAST,
EXPECTED_AT_MOST,
EXPECTED_EQUAL_TO
};
struct cmd_results *checkarg(int argc, const char *name,
enum expected_args type, int val);
const struct cmd_handler *find_handler(const char *line,
const struct cmd_handler *cmd_handlers, size_t handlers_size);
/**
* Parse and executes a command.
*
* If the command string contains criteria then the command will be executed on
* all matching containers. Otherwise, it'll run on the `con` container. If
* `con` is NULL then it'll run on the currently focused container.
*/
list_t *execute_command(char *command, struct sway_seat *seat,
struct sway_container *con);
/**
* Parse and handles a command during config file loading.
*
* Do not use this under normal conditions.
*/
struct cmd_results *config_command(char *command, char **new_block);
/**
* Parse and handle a sub command
*/
struct cmd_results *config_subcommand(char **argv, int argc,
const struct cmd_handler *handlers, size_t handlers_size);
/*
* Parses a command policy rule.
*/
struct cmd_results *config_commands_command(char *exec);
/**
* Allocates a cmd_results object.
*/
struct cmd_results *cmd_results_new(enum cmd_status status, const char *error, ...) _SWAY_ATTRIB_PRINTF(2, 3);
/**
* Frees a cmd_results object.
*/
void free_cmd_results(struct cmd_results *results);
/**
* Serializes a list of cmd_results to a JSON string.
*
* Free the JSON string later on.
*/
char *cmd_results_to_json(list_t *res_list);
/**
* TODO: Move this function and its dependent functions to container.c.
*/
void container_resize_tiled(struct sway_container *parent, uint32_t axis,
int amount);
struct sway_container *container_find_resize_parent(struct sway_container *con,
uint32_t edge);
/**
* Effect handlers value parsers
*/
bool cmd_corner_radius_parse_value(char *arg, int* result);
/**
* Handlers shared by exec and exec_always.
*/
sway_cmd cmd_exec_validate;
sway_cmd cmd_exec_process;
sway_cmd cmd_allow_tearing;
sway_cmd cmd_animation_duration_ms;
sway_cmd cmd_assign;
sway_cmd cmd_bar;
sway_cmd cmd_bindcode;
sway_cmd cmd_bindgesture;
sway_cmd cmd_bindswitch;
sway_cmd cmd_bindsym;
sway_cmd cmd_blur;
sway_cmd cmd_blur_brightness;
sway_cmd cmd_blur_contrast;
sway_cmd cmd_blur_noise;
sway_cmd cmd_blur_passes;
sway_cmd cmd_blur_radius;
sway_cmd cmd_blur_saturation;
sway_cmd cmd_blur_xray;
sway_cmd cmd_border;
sway_cmd cmd_client_noop;
sway_cmd cmd_client_focused;
sway_cmd cmd_client_focused_inactive;
sway_cmd cmd_client_focused_tab_title;
sway_cmd cmd_client_unfocused;
sway_cmd cmd_client_urgent;
sway_cmd cmd_client_placeholder;
sway_cmd cmd_client_background;
sway_cmd cmd_commands;
sway_cmd cmd_corner_radius;
sway_cmd cmd_create_output;
sway_cmd cmd_default_border;
sway_cmd cmd_default_dim_inactive;
sway_cmd cmd_default_floating_border;
sway_cmd cmd_default_orientation;
sway_cmd cmd_dim_inactive;
sway_cmd cmd_dim_inactive_colors_unfocused;
sway_cmd cmd_dim_inactive_colors_urgent;
sway_cmd cmd_exec;
sway_cmd cmd_exec_always;
sway_cmd cmd_exit;
sway_cmd cmd_floating;
sway_cmd cmd_floating_maximum_size;
sway_cmd cmd_floating_minimum_size;
sway_cmd cmd_floating_modifier;
sway_cmd cmd_floating_scroll;
sway_cmd cmd_focus;
sway_cmd cmd_focus_follows_mouse;
sway_cmd cmd_focus_on_window_activation;
sway_cmd cmd_focus_wrapping;
sway_cmd cmd_font;
sway_cmd cmd_for_window;
sway_cmd cmd_force_display_urgency_hint;
sway_cmd cmd_force_focus_wrapping;
sway_cmd cmd_fullscreen;
sway_cmd cmd_gaps;
sway_cmd cmd_hide_edge_borders;
sway_cmd cmd_include;
sway_cmd cmd_inhibit_idle;
sway_cmd cmd_input;
sway_cmd cmd_seat;
sway_cmd cmd_ipc;
sway_cmd cmd_kill;
sway_cmd cmd_layer_effects;
sway_cmd cmd_layout;
sway_cmd cmd_log_colors;
sway_cmd cmd_mark;
sway_cmd cmd_max_render_time;
sway_cmd cmd_mode;
sway_cmd cmd_mouse_warping;
sway_cmd cmd_move;
sway_cmd cmd_new_float;
sway_cmd cmd_new_window;
sway_cmd cmd_nop;
sway_cmd cmd_opacity;
sway_cmd cmd_no_focus;
sway_cmd cmd_output;
sway_cmd cmd_permit;
sway_cmd cmd_popup_during_fullscreen;
sway_cmd cmd_primary_selection;
sway_cmd cmd_reject;
sway_cmd cmd_reload;
sway_cmd cmd_rename;
sway_cmd cmd_resize;
sway_cmd cmd_scratchpad;
sway_cmd cmd_scratchpad_minimize;
sway_cmd cmd_seamless_mouse;
sway_cmd cmd_set;
sway_cmd cmd_shadow_blur_radius;
sway_cmd cmd_shadow_color;
sway_cmd cmd_shadow_offset;
sway_cmd cmd_shadow_inactive_color;
sway_cmd cmd_shadows;
sway_cmd cmd_shadows_on_csd;
sway_cmd cmd_shortcuts_inhibitor;
sway_cmd cmd_show_marks;
sway_cmd cmd_smart_borders;
sway_cmd cmd_smart_corner_radius;
sway_cmd cmd_smart_gaps;
sway_cmd cmd_split;
sway_cmd cmd_splith;
sway_cmd cmd_splitt;
sway_cmd cmd_splitv;
sway_cmd cmd_sticky;
sway_cmd cmd_swaybg_command;
sway_cmd cmd_swaynag_command;
sway_cmd cmd_swap;
sway_cmd cmd_tiling_drag;
sway_cmd cmd_tiling_drag_threshold;
sway_cmd cmd_title_align;
sway_cmd cmd_title_format;
sway_cmd cmd_titlebar_border_thickness;
sway_cmd cmd_titlebar_padding;
sway_cmd cmd_titlebar_separator;
sway_cmd cmd_unbindcode;
sway_cmd cmd_unbindswitch;
sway_cmd cmd_unbindgesture;
sway_cmd cmd_unbindsym;
sway_cmd cmd_unmark;
sway_cmd cmd_urgent;
sway_cmd cmd_workspace;
sway_cmd cmd_workspace_layout;
sway_cmd cmd_ws_auto_back_and_forth;
sway_cmd cmd_xwayland;
sway_cmd bar_cmd_bindcode;
sway_cmd bar_cmd_binding_mode_indicator;
sway_cmd bar_cmd_bindsym;
sway_cmd bar_cmd_colors;
sway_cmd bar_cmd_font;
sway_cmd bar_cmd_gaps;
sway_cmd bar_cmd_mode;
sway_cmd bar_cmd_modifier;
sway_cmd bar_cmd_output;
sway_cmd bar_cmd_height;
sway_cmd bar_cmd_hidden_state;
sway_cmd bar_cmd_icon_theme;
sway_cmd bar_cmd_id;
sway_cmd bar_cmd_position;
sway_cmd bar_cmd_separator_symbol;
sway_cmd bar_cmd_status_command;
sway_cmd bar_cmd_status_edge_padding;
sway_cmd bar_cmd_status_padding;
sway_cmd bar_cmd_pango_markup;
sway_cmd bar_cmd_strip_workspace_numbers;
sway_cmd bar_cmd_strip_workspace_name;
sway_cmd bar_cmd_swaybar_command;
sway_cmd bar_cmd_tray_bindcode;
sway_cmd bar_cmd_tray_bindsym;
sway_cmd bar_cmd_tray_output;
sway_cmd bar_cmd_tray_padding;
sway_cmd bar_cmd_unbindcode;
sway_cmd bar_cmd_unbindsym;
sway_cmd bar_cmd_wrap_scroll;
sway_cmd bar_cmd_workspace_buttons;
sway_cmd bar_cmd_workspace_min_width;
sway_cmd bar_colors_cmd_active_workspace;
sway_cmd bar_colors_cmd_background;
sway_cmd bar_colors_cmd_focused_background;
sway_cmd bar_colors_cmd_binding_mode;
sway_cmd bar_colors_cmd_focused_workspace;
sway_cmd bar_colors_cmd_inactive_workspace;
sway_cmd bar_colors_cmd_separator;
sway_cmd bar_colors_cmd_focused_separator;
sway_cmd bar_colors_cmd_statusline;
sway_cmd bar_colors_cmd_focused_statusline;
sway_cmd bar_colors_cmd_urgent_workspace;
sway_cmd input_cmd_seat;
sway_cmd input_cmd_accel_profile;
sway_cmd input_cmd_calibration_matrix;
sway_cmd input_cmd_click_method;
sway_cmd input_cmd_clickfinger_button_map;
sway_cmd input_cmd_drag;
sway_cmd input_cmd_drag_lock;
sway_cmd input_cmd_dwt;
sway_cmd input_cmd_dwtp;
sway_cmd input_cmd_events;
sway_cmd input_cmd_left_handed;
sway_cmd input_cmd_map_from_region;
sway_cmd input_cmd_map_to_output;
sway_cmd input_cmd_map_to_region;
sway_cmd input_cmd_middle_emulation;
sway_cmd input_cmd_natural_scroll;
sway_cmd input_cmd_pointer_accel;
sway_cmd input_cmd_rotation_angle;
sway_cmd input_cmd_scroll_factor;
sway_cmd input_cmd_repeat_delay;
sway_cmd input_cmd_repeat_rate;
sway_cmd input_cmd_scroll_button;
sway_cmd input_cmd_scroll_button_lock;
sway_cmd input_cmd_scroll_method;
sway_cmd input_cmd_tap;
sway_cmd input_cmd_tap_button_map;
sway_cmd input_cmd_tool_mode;
sway_cmd input_cmd_xkb_capslock;
sway_cmd input_cmd_xkb_file;
sway_cmd input_cmd_xkb_layout;
sway_cmd input_cmd_xkb_model;
sway_cmd input_cmd_xkb_numlock;
sway_cmd input_cmd_xkb_options;
sway_cmd input_cmd_xkb_rules;
sway_cmd input_cmd_xkb_switch_layout;
sway_cmd input_cmd_xkb_variant;
sway_cmd output_cmd_adaptive_sync;
sway_cmd output_cmd_allow_tearing;
sway_cmd output_cmd_background;
sway_cmd output_cmd_color_profile;
sway_cmd output_cmd_disable;
sway_cmd output_cmd_dpms;
sway_cmd output_cmd_enable;
sway_cmd output_cmd_hdr;
sway_cmd output_cmd_max_render_time;
sway_cmd output_cmd_mode;
sway_cmd output_cmd_modeline;
sway_cmd output_cmd_position;
sway_cmd output_cmd_power;
sway_cmd output_cmd_render_bit_depth;
sway_cmd output_cmd_scale;
sway_cmd output_cmd_scale_filter;
sway_cmd output_cmd_subpixel;
sway_cmd output_cmd_toggle;
sway_cmd output_cmd_transform;
sway_cmd output_cmd_unplug;
sway_cmd seat_cmd_attach;
sway_cmd seat_cmd_cursor;
sway_cmd seat_cmd_fallback;
sway_cmd seat_cmd_hide_cursor;
sway_cmd seat_cmd_idle_inhibit;
sway_cmd seat_cmd_idle_wake;
sway_cmd seat_cmd_keyboard_grouping;
sway_cmd seat_cmd_pointer_constraint;
sway_cmd seat_cmd_shortcuts_inhibitor;
sway_cmd seat_cmd_xcursor_theme;
sway_cmd cmd_ipc_cmd;
sway_cmd cmd_ipc_events;
sway_cmd cmd_ipc_event_cmd;
#endif

790
include/sway/config.h Normal file
View file

@ -0,0 +1,790 @@
#ifndef _SWAY_CONFIG_H
#define _SWAY_CONFIG_H
#include <libinput.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <wlr/interfaces/wlr_switch.h>
#include <wlr/types/wlr_tablet_tool.h>
#include <wlr/util/box.h>
#include <wlr/render/color.h>
#include <xkbcommon/xkbcommon.h>
#include <xf86drmMode.h>
#include "../include/config.h"
#include "gesture.h"
#include "list.h"
#include "stringop.h"
#include "swaynag.h"
#include "tree/container.h"
#include "sway/input/tablet.h"
#include "sway/tree/root.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"
#include <pango/pangocairo.h>
// TODO: Refactor this shit
/**
* Describes a variable created via the `set` command.
*/
struct sway_variable {
char *name;
char *value;
};
enum binding_input_type {
BINDING_KEYCODE,
BINDING_KEYSYM,
BINDING_MOUSECODE,
BINDING_MOUSESYM,
BINDING_SWITCH, // dummy, only used to call seat_execute_command
BINDING_GESTURE // dummy, only used to call seat_execute_command
};
enum binding_flags {
BINDING_RELEASE = 1 << 0,
BINDING_LOCKED = 1 << 1, // keyboard only
BINDING_BORDER = 1 << 2, // mouse only; trigger on container border
BINDING_CONTENTS = 1 << 3, // mouse only; trigger on container contents
BINDING_TITLEBAR = 1 << 4, // mouse only; trigger on container titlebar
BINDING_CODE = 1 << 5, // keyboard only; convert keysyms into keycodes
BINDING_RELOAD = 1 << 6, // switch only; (re)trigger binding on reload
BINDING_INHIBITED = 1 << 7, // keyboard only: ignore shortcut inhibitor
BINDING_NOREPEAT = 1 << 8, // keyboard only; do not trigger when repeating a held key
BINDING_EXACT = 1 << 9, // gesture only; only trigger on exact match
};
/**
* A key (or mouse) binding and an associated command.
*/
struct sway_binding {
enum binding_input_type type;
int order;
char *input;
uint32_t flags;
list_t *keys; // sorted in ascending order
list_t *syms; // sorted in ascending order; NULL if BINDING_CODE is not set
uint32_t modifiers;
xkb_layout_index_t group;
char *command;
};
enum sway_switch_trigger {
SWAY_SWITCH_TRIGGER_OFF,
SWAY_SWITCH_TRIGGER_ON,
SWAY_SWITCH_TRIGGER_TOGGLE,
};
/**
* A laptop switch binding and an associated command.
*/
struct sway_switch_binding {
enum wlr_switch_type type;
enum sway_switch_trigger trigger;
uint32_t flags;
char *command;
};
/**
* A gesture binding and an associated command.
*/
struct sway_gesture_binding {
char *input;
uint32_t flags;
struct gesture gesture;
char *command;
};
/**
* Focus on window activation.
*/
enum sway_fowa {
FOWA_SMART,
FOWA_URGENT,
FOWA_FOCUS,
FOWA_NONE,
};
/**
* A "mode" of keybindings created via the `mode` command.
*/
struct sway_mode {
char *name;
list_t *keysym_bindings;
list_t *keycode_bindings;
list_t *mouse_bindings;
list_t *switch_bindings;
list_t *gesture_bindings;
bool pango;
};
struct input_config_mapped_from_region {
double x1, y1;
double x2, y2;
bool mm;
};
struct calibration_matrix {
bool configured;
float matrix[6];
};
enum input_config_mapped_to {
MAPPED_TO_DEFAULT,
MAPPED_TO_OUTPUT,
MAPPED_TO_REGION,
};
struct input_config_tool {
enum wlr_tablet_tool_type type;
enum sway_tablet_tool_mode mode;
};
/**
* options for input devices
*/
struct input_config {
char *identifier;
const char *input_type;
int accel_profile;
struct calibration_matrix calibration_matrix;
int click_method;
int clickfinger_button_map;
int drag;
int drag_lock;
int dwt;
int dwtp;
int left_handed;
int middle_emulation;
int natural_scroll;
float pointer_accel;
float rotation_angle;
float scroll_factor;
int repeat_delay;
int repeat_rate;
int scroll_button;
int scroll_button_lock;
int scroll_method;
int send_events;
int tap;
int tap_button_map;
char *xkb_layout;
char *xkb_model;
char *xkb_options;
char *xkb_rules;
char *xkb_variant;
char *xkb_file;
bool xkb_file_is_set;
int xkb_numlock;
int xkb_capslock;
struct input_config_mapped_from_region *mapped_from_region;
enum input_config_mapped_to mapped_to;
char *mapped_to_output;
struct wlr_box *mapped_to_region;
list_t *tools;
bool capturable;
struct wlr_box region;
};
/**
* Options for misc device configurations that happen in the seat block
*/
struct seat_attachment_config {
char *identifier;
// TODO other things are configured here for some reason
};
enum seat_config_hide_cursor_when_typing {
HIDE_WHEN_TYPING_DEFAULT, // the default is currently disabled
HIDE_WHEN_TYPING_ENABLE,
HIDE_WHEN_TYPING_DISABLE,
};
enum seat_config_allow_constrain {
CONSTRAIN_DEFAULT, // the default is currently enabled
CONSTRAIN_ENABLE,
CONSTRAIN_DISABLE,
};
enum seat_config_shortcuts_inhibit {
SHORTCUTS_INHIBIT_DEFAULT, // the default is currently enabled
SHORTCUTS_INHIBIT_ENABLE,
SHORTCUTS_INHIBIT_DISABLE,
};
enum seat_keyboard_grouping {
KEYBOARD_GROUP_DEFAULT, // the default is currently smart
KEYBOARD_GROUP_NONE,
KEYBOARD_GROUP_SMART, // keymap and repeat info
};
enum sway_input_idle_source {
IDLE_SOURCE_KEYBOARD = 1 << 0,
IDLE_SOURCE_POINTER = 1 << 1,
IDLE_SOURCE_TOUCH = 1 << 2,
IDLE_SOURCE_TABLET_PAD = 1 << 3,
IDLE_SOURCE_TABLET_TOOL = 1 << 4,
IDLE_SOURCE_SWITCH = 1 << 5,
};
/**
* Options for multiseat and other misc device configurations
*/
struct seat_config {
char *name;
int fallback; // -1 means not set
list_t *attachments; // list of seat_attachment configs
int hide_cursor_timeout;
enum seat_config_hide_cursor_when_typing hide_cursor_when_typing;
enum seat_config_allow_constrain allow_constrain;
enum seat_config_shortcuts_inhibit shortcuts_inhibit;
enum seat_keyboard_grouping keyboard_grouping;
uint32_t idle_inhibit_sources, idle_wake_sources;
struct {
char *name;
int size;
} xcursor_theme;
};
enum scale_filter_mode {
SCALE_FILTER_DEFAULT, // the default is currently smart
SCALE_FILTER_LINEAR,
SCALE_FILTER_NEAREST,
SCALE_FILTER_SMART,
};
enum render_bit_depth {
RENDER_BIT_DEPTH_DEFAULT, // the default is currently 8 for SDR, 10 for HDR
RENDER_BIT_DEPTH_6,
RENDER_BIT_DEPTH_8,
RENDER_BIT_DEPTH_10,
};
enum color_profile {
COLOR_PROFILE_DEFAULT, // default is Transform with NULL color_transform
COLOR_PROFILE_TRANSFORM, // use color_transform from output_config
COLOR_PROFILE_TRANSFORM_WITH_DEVICE_PRIMARIES, // create transform from wlr_output
};
/**
* Size and position configuration for a particular output.
*
* This is set via the `output` command.
*/
struct output_config {
char *name;
int enabled;
int power;
int width, height;
float refresh_rate;
int custom_mode;
drmModeModeInfo drm_mode;
int x, y;
float scale;
enum scale_filter_mode scale_filter;
int32_t transform;
enum wl_output_subpixel subpixel;
int max_render_time; // In milliseconds
int adaptive_sync;
enum render_bit_depth render_bit_depth;
enum color_profile color_profile;
struct wlr_color_transform *color_transform;
int allow_tearing;
int hdr;
char *background;
char *background_option;
char *background_fallback;
};
/**
* Stores size of gaps for each side
*/
struct side_gaps {
int top;
int right;
int bottom;
int left;
};
enum smart_gaps_mode {
SMART_GAPS_OFF,
SMART_GAPS_ON,
SMART_GAPS_INVERSE_OUTER,
};
/**
* Stores configuration for a workspace, regardless of whether the workspace
* exists.
*/
struct workspace_config {
char *workspace;
list_t *outputs;
int gaps_inner;
struct side_gaps gaps_outer;
};
enum pango_markup_config {
PANGO_MARKUP_DISABLED = false,
PANGO_MARKUP_ENABLED = true,
PANGO_MARKUP_DEFAULT // The default is font dependent ("pango:" prefix)
};
struct bar_config {
char *swaybar_command;
struct wl_client *client;
struct wl_listener client_destroy;
/**
* One of "dock", "hide", "invisible"
*
* Always visible in dock mode. Visible only when modifier key is held in hide mode.
* Never visible in invisible mode.
*/
char *mode;
/**
* One of "show" or "hide".
*
* In "show" mode, it will always be shown on top of the active workspace.
*/
char *hidden_state;
bool visible_by_modifier; // only relevant in "hide" mode
/**
* Id name used to identify the bar through IPC.
*
* Defaults to bar-x, where x corresponds to the position of the
* embedding bar block in the config file (bar-0, bar-1, ...).
*/
char *id;
uint32_t modifier;
list_t *outputs;
char *position;
list_t *bindings;
char *status_command;
enum pango_markup_config pango_markup;
char *font;
int height; // -1 not defined
bool workspace_buttons;
bool wrap_scroll;
char *separator_symbol;
bool strip_workspace_numbers;
bool strip_workspace_name;
bool binding_mode_indicator;
bool verbose;
struct side_gaps gaps;
int status_padding;
int status_edge_padding;
uint32_t workspace_min_width;
struct {
char *background;
char *statusline;
char *separator;
char *focused_background;
char *focused_statusline;
char *focused_separator;
char *focused_workspace_border;
char *focused_workspace_bg;
char *focused_workspace_text;
char *active_workspace_border;
char *active_workspace_bg;
char *active_workspace_text;
char *inactive_workspace_border;
char *inactive_workspace_bg;
char *inactive_workspace_text;
char *urgent_workspace_border;
char *urgent_workspace_bg;
char *urgent_workspace_text;
char *binding_mode_border;
char *binding_mode_bg;
char *binding_mode_text;
} colors;
#if HAVE_TRAY
char *icon_theme;
struct wl_list tray_bindings; // struct tray_binding::link
list_t *tray_outputs; // char *
int tray_padding;
#endif
};
struct bar_binding {
uint32_t button;
bool release;
char *command;
};
#if HAVE_TRAY
struct tray_binding {
uint32_t button;
const char *command;
struct wl_list link; // struct tray_binding::link
};
#endif
struct border_colors {
float border[4];
float background[4];
float text[4];
float indicator[4];
float child_border[4];
};
enum edge_border_types {
E_NONE, /**< Don't hide edge borders */
E_VERTICAL, /**< hide vertical edge borders */
E_HORIZONTAL, /**< hide horizontal edge borders */
E_BOTH, /**< hide vertical and horizontal edge borders */
};
enum edge_border_smart_types {
ESMART_OFF,
ESMART_ON, /**< hide edges if precisely one window is present in workspace */
ESMART_NO_GAPS, /**< hide edges if one window and gaps to edge is zero */
};
enum sway_popup_during_fullscreen {
POPUP_SMART,
POPUP_IGNORE,
POPUP_LEAVE,
};
enum focus_follows_mouse_mode {
FOLLOWS_NO,
FOLLOWS_YES,
FOLLOWS_ALWAYS,
};
enum focus_wrapping_mode {
WRAP_NO,
WRAP_YES,
WRAP_FORCE,
WRAP_WORKSPACE,
};
enum mouse_warping_mode {
WARP_NO,
WARP_OUTPUT,
WARP_CONTAINER,
};
enum alignment {
ALIGN_LEFT,
ALIGN_CENTER,
ALIGN_RIGHT,
};
enum xwayland_mode {
XWAYLAND_MODE_DISABLED,
XWAYLAND_MODE_LAZY,
XWAYLAND_MODE_IMMEDIATE,
};
/**
* The configuration struct. The result of loading a config file.
*/
struct sway_config {
float animation_duration_ms;
int corner_radius;
bool smart_corner_radius;
float default_dim_inactive;
struct {
float unfocused[4];
float urgent[4];
} dim_inactive_colors;
bool blur_enabled;
bool blur_xray;
struct blur_data blur_data;
bool shadow_enabled;
bool shadows_on_csd_enabled;
int shadow_blur_sigma;
float shadow_color[4];
float shadow_inactive_color[4];
float shadow_offset_x, shadow_offset_y;
bool titlebar_separator;
bool scratchpad_minimize;
list_t *layer_criteria;
char *swaynag_command;
struct swaynag_instance swaynag_config_errors;
list_t *symbols;
list_t *modes;
list_t *bars;
list_t *cmd_queue;
list_t *workspace_configs;
list_t *output_configs;
list_t *input_configs;
list_t *input_type_configs;
list_t *seat_configs;
list_t *criteria;
list_t *no_focus;
list_t *active_bar_modifiers;
struct sway_mode *current_mode;
struct bar_config *current_bar;
uint32_t floating_mod;
bool floating_mod_inverse;
uint32_t dragging_key;
uint32_t resizing_key;
char *floating_scroll_up_cmd;
char *floating_scroll_down_cmd;
char *floating_scroll_left_cmd;
char *floating_scroll_right_cmd;
enum sway_container_layout default_orientation;
enum sway_container_layout default_layout;
char *font; // Used for IPC.
PangoFontDescription *font_description; // Used internally for rendering and validating.
int font_height;
int font_baseline;
bool pango_markup;
int titlebar_border_thickness;
int titlebar_h_padding;
int titlebar_v_padding;
size_t urgent_timeout;
enum sway_fowa focus_on_window_activation;
enum sway_popup_during_fullscreen popup_during_fullscreen;
enum xwayland_mode xwayland;
// swaybg
char *swaybg_command;
struct wl_client *swaybg_client;
struct wl_listener swaybg_client_destroy;
// Flags
enum focus_follows_mouse_mode focus_follows_mouse;
enum mouse_warping_mode mouse_warping;
enum focus_wrapping_mode focus_wrapping;
bool active;
bool failed;
bool reloading;
bool reading;
bool validating;
bool auto_back_and_forth;
bool show_marks;
enum alignment title_align;
bool primary_selection;
bool tiling_drag;
int tiling_drag_threshold;
enum smart_gaps_mode smart_gaps;
int gaps_inner;
struct side_gaps gaps_outer;
list_t *config_chain;
bool user_config_path;
const char *current_config_path;
const char *current_config;
int current_config_line_number;
char *current_config_line;
enum sway_container_border border;
enum sway_container_border floating_border;
int border_thickness;
int floating_border_thickness;
enum edge_border_types hide_edge_borders;
enum edge_border_smart_types hide_edge_borders_smart;
bool hide_lone_tab;
// border colors
struct {
struct border_colors focused;
struct border_colors focused_inactive;
struct border_colors focused_tab_title;
struct border_colors unfocused;
struct border_colors urgent;
struct border_colors placeholder;
float background[4];
} border_colors;
bool has_focused_tab_title;
// floating view
int32_t floating_maximum_width;
int32_t floating_maximum_height;
int32_t floating_minimum_width;
int32_t floating_minimum_height;
// The keysym to keycode translation
struct xkb_state *keysym_translation_state;
// Context for command handlers
struct {
struct input_config *input_config;
struct output_config *output_config;
struct seat_config *seat_config;
struct sway_seat *seat;
struct sway_node *node;
struct sway_container *container;
struct sway_workspace *workspace;
bool node_overridden; // True if the node is selected by means other than focus
struct {
int argc;
char **argv;
} leftovers;
} handler_context;
};
/**
* Loads the main config from the given path. is_active should be true when
* reloading the config.
*/
bool load_main_config(const char *path, bool is_active, bool validating);
/**
* Loads an included config. Can only be used after load_main_config.
*/
void load_include_configs(const char *path, struct sway_config *config,
struct swaynag_instance *swaynag);
/**
* Reads the config from the given FILE.
*/
bool read_config(FILE *file, struct sway_config *config,
struct swaynag_instance *swaynag);
/**
* Run the commands that were deferred when reading the config file.
*/
void run_deferred_commands(void);
/**
* Run the binding commands that were deferred when initializing the inputs
*/
void run_deferred_bindings(void);
/**
* Adds a warning entry to the swaynag instance used for errors.
*/
void config_add_swaynag_warning(char *fmt, ...) _SWAY_ATTRIB_PRINTF(1, 2);
/**
* Free config struct
*/
void free_config(struct sway_config *config);
void free_sway_variable(struct sway_variable *var);
/**
* Does variable replacement for a string based on the config's currently loaded variables.
*/
char *do_var_replacement(char *str);
int input_identifier_cmp(const void *item, const void *data);
struct input_config *new_input_config(const char* identifier);
void merge_input_config(struct input_config *dst, struct input_config *src);
struct input_config *store_input_config(struct input_config *ic, char **error);
void input_config_fill_rule_names(struct input_config *ic,
struct xkb_rule_names *rules);
void free_input_config(struct input_config *ic);
int seat_name_cmp(const void *item, const void *data);
struct seat_config *new_seat_config(const char* name);
void merge_seat_config(struct seat_config *dst, struct seat_config *src);
struct seat_config *copy_seat_config(struct seat_config *seat);
void free_seat_config(struct seat_config *ic);
struct seat_attachment_config *seat_attachment_config_new(void);
struct seat_attachment_config *seat_config_get_attachment(
struct seat_config *seat_config, char *identifier);
struct seat_config *store_seat_config(struct seat_config *seat);
int output_name_cmp(const void *item, const void *data);
void output_get_identifier(char *identifier, size_t len,
struct sway_output *output);
const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter);
struct output_config *new_output_config(const char *name);
bool apply_output_configs(struct output_config **ocs, size_t ocs_len,
bool test_only, bool degrade_to_off);
void apply_stored_output_configs(void);
/**
* store_output_config stores a new output config. An output may be matched by
* three different config types, in order of precedence: Identifier, name and
* wildcard. When storing a config type of lower precedence, assume that the
* user wants the config to take immediate effect by superseding (clearing) the
* same values from higher presedence configuration.
*/
void store_output_config(struct output_config *oc);
struct output_config *find_output_config(struct sway_output *output);
void free_output_config(struct output_config *oc);
void request_modeset(void);
void force_modeset(void);
bool modeset_is_pending(void);
bool spawn_swaybg(void);
int workspace_output_cmp_workspace(const void *a, const void *b);
void free_sway_binding(struct sway_binding *sb);
void free_switch_binding(struct sway_switch_binding *binding);
void free_gesture_binding(struct sway_gesture_binding *binding);
void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding);
void load_swaybar(struct bar_config *bar);
void load_swaybars(void);
struct bar_config *default_bar_config(void);
void free_bar_config(struct bar_config *bar);
void free_bar_binding(struct bar_binding *binding);
void free_workspace_config(struct workspace_config *wsc);
/**
* Updates the value of config->font_height based on the metrics for title's
* font as reported by pango.
*
* If the height has changed, all containers will be rearranged to take on the
* new size.
*/
void config_update_font_height(void);
/**
* Convert bindsym into bindcode using the first configured layout.
* Return false in case the conversion is unsuccessful.
*/
bool translate_binding(struct sway_binding *binding);
void translate_keysyms(struct input_config *input_config);
void binding_add_translated(struct sway_binding *binding, list_t *bindings);
/* Global config singleton. */
extern struct sway_config *config;
#endif

91
include/sway/criteria.h Normal file
View file

@ -0,0 +1,91 @@
#ifndef _SWAY_CRITERIA_H
#define _SWAY_CRITERIA_H
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
#include "config.h"
#include "list.h"
#include "tree/view.h"
#if WLR_HAS_XWAYLAND
#include "sway/xwayland.h"
#endif
enum criteria_type {
CT_COMMAND = 1 << 0,
CT_ASSIGN_OUTPUT = 1 << 1,
CT_ASSIGN_WORKSPACE = 1 << 2,
CT_ASSIGN_WORKSPACE_NUMBER = 1 << 3,
CT_NO_FOCUS = 1 << 4,
};
enum pattern_type {
PATTERN_PCRE2,
PATTERN_FOCUSED,
};
struct pattern {
enum pattern_type match_type;
pcre2_code *regex;
};
struct criteria {
enum criteria_type type;
char *raw; // entire criteria string (for logging)
char *cmdlist;
char *target; // workspace or output name for `assign` criteria
struct pattern *title;
struct pattern *shell;
struct pattern *app_id;
struct pattern *con_mark;
uint32_t con_id; // internal ID
#if WLR_HAS_XWAYLAND
struct pattern *class;
uint32_t id; // X11 window ID
struct pattern *instance;
struct pattern *window_role;
enum atom_name window_type;
#endif
bool all;
bool floating;
bool tiling;
char urgent; // 'l' for latest or 'o' for oldest
struct pattern *workspace;
pid_t pid;
struct pattern *sandbox_engine;
struct pattern *sandbox_app_id;
struct pattern *sandbox_instance_id;
struct pattern *tag;
};
bool criteria_is_empty(struct criteria *criteria);
bool criteria_is_equal(struct criteria *left, struct criteria *right);
bool criteria_already_exists(struct criteria *criteria);
void criteria_destroy(struct criteria *criteria);
/**
* Generate a criteria struct from a raw criteria string such as
* [class="foo" instance="bar"] (brackets inclusive).
*
* The error argument is expected to be an address of a null pointer. If an
* error is encountered, the function will return NULL and the pointer will be
* changed to point to the error string. This string should be freed afterwards.
*/
struct criteria *criteria_parse(char *raw, char **error);
/**
* Compile a list of criterias matching the given view.
*
* Criteria types can be bitwise ORed.
*/
list_t *criteria_for_view(struct sway_view *view, enum criteria_type types);
/**
* Compile a list of containers matching the given criteria.
*/
list_t *criteria_get_containers(struct criteria *criteria);
#endif

17
include/sway/decoration.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef _SWAY_DECORATION_H
#define _SWAY_DECORATION_H
#include <wlr/types/wlr_server_decoration.h>
struct sway_server_decoration {
struct wlr_server_decoration *wlr_server_decoration;
struct wl_list link;
struct wl_listener destroy;
struct wl_listener mode;
};
struct sway_server_decoration *decoration_from_surface(
struct wlr_surface *surface);
#endif

View file

@ -0,0 +1,48 @@
#ifndef _SWAY_DESKTOP_IDLE_INHIBIT_V1_H
#define _SWAY_DESKTOP_IDLE_INHIBIT_V1_H
#include <wlr/types/wlr_idle_inhibit_v1.h>
enum sway_idle_inhibit_mode {
INHIBIT_IDLE_APPLICATION, // Application set inhibitor (when visible)
INHIBIT_IDLE_FOCUS, // User set inhibitor when focused
INHIBIT_IDLE_FULLSCREEN, // User set inhibitor when fullscreen + visible
INHIBIT_IDLE_OPEN, // User set inhibitor while open
INHIBIT_IDLE_VISIBLE // User set inhibitor when visible
};
struct sway_idle_inhibit_manager_v1 {
struct wlr_idle_inhibit_manager_v1 *wlr_manager;
struct wl_listener new_idle_inhibitor_v1;
struct wl_listener manager_destroy;
struct wl_list inhibitors;
};
struct sway_idle_inhibitor_v1 {
struct wlr_idle_inhibitor_v1 *wlr_inhibitor;
struct sway_view *view;
enum sway_idle_inhibit_mode mode;
struct wl_list link;
struct wl_listener destroy;
};
bool sway_idle_inhibit_v1_is_active(
struct sway_idle_inhibitor_v1 *inhibitor);
void sway_idle_inhibit_v1_check_active(void);
void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view,
enum sway_idle_inhibit_mode mode);
struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view(
struct sway_view *view);
struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_view(
struct sway_view *view);
void sway_idle_inhibit_v1_user_inhibitor_destroy(
struct sway_idle_inhibitor_v1 *inhibitor);
bool sway_idle_inhibit_manager_v1_init(void);
#endif

View file

@ -0,0 +1,40 @@
#ifndef _SWAY_LAUNCHER_H
#define _SWAY_LAUNCHER_H
#include <stdlib.h>
#include <wayland-server-core.h>
#include "sway/input/seat.h"
struct launcher_ctx {
pid_t pid;
char *fallback_name;
struct wlr_xdg_activation_token_v1 *token;
struct wl_listener token_destroy;
struct sway_seat *seat;
struct wl_listener seat_destroy;
bool activated;
bool had_focused_surface;
struct sway_node *node;
struct wl_listener node_destroy;
struct wl_list link; // sway_server::pending_launcher_ctxs
};
struct launcher_ctx *launcher_ctx_find_pid(pid_t pid);
struct sway_workspace *launcher_ctx_get_workspace(struct launcher_ctx *ctx);
void launcher_ctx_consume(struct launcher_ctx *ctx);
void launcher_ctx_destroy(struct launcher_ctx *ctx);
struct launcher_ctx *launcher_ctx_create_internal(void);
struct launcher_ctx *launcher_ctx_create(
struct wlr_xdg_activation_token_v1 *token, struct sway_node *node);
const char *launcher_ctx_get_token_name(struct launcher_ctx *ctx);
#endif

View file

@ -0,0 +1,65 @@
#ifndef _SWAY_TRANSACTION_H
#define _SWAY_TRANSACTION_H
#include <scenefx/types/wlr_scene.h>
#include <stdint.h>
#include <stdbool.h>
#include <wlr/types/wlr_scene.h>
/**
* Transactions enable us to perform atomic layout updates.
*
* A transaction contains a list of containers and their new state.
* A state might contain a new size, or new border settings, or new parent/child
* relationships.
*
* Committing a transaction makes sway notify of all the affected clients with
* their new sizes. We then wait for all the views to respond with their new
* surface sizes. When all are ready, or when a timeout has passed, we apply the
* updates all at the same time.
*
* When we want to make adjustments to the layout, we change the pending state
* in containers, mark them as dirty and call transaction_commit_dirty(). This
* create and commits a transaction from the dirty containers.
*/
struct sway_transaction_instruction;
struct sway_view;
/**
* Find all dirty containers, create and commit a transaction containing them,
* and unmark them as dirty.
*/
void transaction_commit_dirty(void);
/*
* Same as transaction_commit_dirty, but signalling that this is a
* client-initiated change has already taken effect.
*/
void transaction_commit_dirty_client(void);
/**
* Notify the transaction system that a view is ready for the new layout.
*
* When all views in the transaction are ready, the layout will be applied.
*
* A success boolean is returned denoting that this part of the transaction is
* ready.
*/
bool transaction_notify_view_ready_by_serial(struct sway_view *view,
uint32_t serial);
/**
* Notify the transaction system that a view is ready for the new layout, but
* identifying the instruction by geometry rather than by serial.
*
* This is used by xwayland views, as they don't have serials.
*
* A success boolean is returned denoting that this part of the transaction is
* ready.
*/
bool transaction_notify_view_ready_by_geometry(struct sway_view *view,
double x, double y, int width, int height);
void arrange_popups(struct wlr_scene_tree *popups);
#endif

150
include/sway/input/cursor.h Normal file
View file

@ -0,0 +1,150 @@
#ifndef _SWAY_INPUT_CURSOR_H
#define _SWAY_INPUT_CURSOR_H
#include <stdbool.h>
#include <stdint.h>
#include <wlr/types/wlr_pointer_constraints_v1.h>
#include <wlr/types/wlr_pointer_gestures_v1.h>
#include <wlr/types/wlr_compositor.h>
#include "sway/input/seat.h"
#include "config.h"
#define SWAY_CURSOR_PRESSED_BUTTONS_CAP 32
#define SWAY_SCROLL_UP KEY_MAX + 1
#define SWAY_SCROLL_DOWN KEY_MAX + 2
#define SWAY_SCROLL_LEFT KEY_MAX + 3
#define SWAY_SCROLL_RIGHT KEY_MAX + 4
struct sway_cursor {
struct sway_seat *seat;
struct wlr_cursor *cursor;
struct {
double x, y;
struct sway_node *node;
} previous;
struct wlr_xcursor_manager *xcursor_manager;
struct wl_list tablets;
struct wl_list tablet_pads;
const char *image;
struct wl_client *image_client;
struct wlr_surface *image_surface;
int hotspot_x, hotspot_y;
struct wlr_pointer_constraint_v1 *active_constraint;
pixman_region32_t confine; // invalid if active_constraint == NULL
bool active_confine_requires_warp;
struct wl_listener hold_begin;
struct wl_listener hold_end;
struct wl_listener pinch_begin;
struct wl_listener pinch_update;
struct wl_listener pinch_end;
struct wl_listener swipe_begin;
struct wl_listener swipe_update;
struct wl_listener swipe_end;
struct wl_listener motion;
struct wl_listener motion_absolute;
struct wl_listener button;
struct wl_listener axis;
struct wl_listener frame;
struct wl_listener touch_down;
struct wl_listener touch_up;
struct wl_listener touch_cancel;
struct wl_listener touch_motion;
struct wl_listener touch_frame;
bool simulating_pointer_from_touch;
bool pointer_touch_up;
int32_t pointer_touch_id;
struct wl_listener tool_axis;
struct wl_listener tool_tip;
struct wl_listener tool_proximity;
struct wl_listener tool_button;
bool simulating_pointer_from_tool_tip;
bool simulating_pointer_from_tool_button;
uint32_t tool_buttons;
struct wl_listener request_set_cursor;
struct wl_listener image_surface_destroy;
struct wl_listener constraint_commit;
struct wl_event_source *hide_source;
bool hidden;
// This field is just a cache of the field in seat_config in order to avoid
// costly seat_config lookups on every keypress. HIDE_WHEN_TYPING_DEFAULT
// indicates that there is no cached value.
enum seat_config_hide_cursor_when_typing hide_when_typing;
size_t pressed_button_count;
};
struct sway_node;
struct sway_node *node_at_coords(
struct sway_seat *seat, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy);
void sway_cursor_destroy(struct sway_cursor *cursor);
struct sway_cursor *sway_cursor_create(struct sway_seat *seat);
/**
* "Rebase" a cursor on top of whatever view is underneath it.
*
* This chooses a cursor icon and sends a motion event to the surface.
*/
void cursor_rebase(struct sway_cursor *cursor);
void cursor_rebase_all(void);
void cursor_update_image(struct sway_cursor *cursor, struct sway_node *node);
void cursor_handle_activity_from_idle_source(struct sway_cursor *cursor,
enum sway_input_idle_source idle_source);
void cursor_handle_activity_from_device(struct sway_cursor *cursor,
struct wlr_input_device *device);
void cursor_unhide(struct sway_cursor *cursor);
int cursor_get_timeout(struct sway_cursor *cursor);
void cursor_notify_key_press(struct sway_cursor *cursor);
void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
struct wlr_input_device *device, double dx, double dy,
double dx_unaccel, double dy_unaccel);
void dispatch_cursor_button(struct sway_cursor *cursor,
struct wlr_input_device *device, uint32_t time_msec, uint32_t button,
enum wl_pointer_button_state state);
void dispatch_cursor_axis(struct sway_cursor *cursor,
struct wlr_pointer_axis_event *event);
void cursor_set_image(struct sway_cursor *cursor, const char *image,
struct wl_client *client);
void cursor_set_image_surface(struct sway_cursor *cursor,
struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y,
struct wl_client *client);
void cursor_warp_to_container(struct sway_cursor *cursor,
struct sway_container *container, bool force);
void cursor_warp_to_workspace(struct sway_cursor *cursor,
struct sway_workspace *workspace);
void sway_cursor_constrain(struct sway_cursor *cursor,
struct wlr_pointer_constraint_v1 *constraint);
uint32_t get_mouse_bindsym(const char *name, char **error);
uint32_t get_mouse_bindcode(const char *name, char **error);
// Considers both bindsym and bindcode
uint32_t get_mouse_button(const char *name, char **error);
const char *get_mouse_button_name(uint32_t button);
void handle_request_set_cursor_shape(struct wl_listener *listener, void *data);
#endif

View file

@ -0,0 +1,81 @@
#ifndef _SWAY_INPUT_INPUT_MANAGER_H
#define _SWAY_INPUT_INPUT_MANAGER_H
#include <libinput.h>
#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
#include <wlr/types/wlr_transient_seat_v1.h>
#include "sway/config.h"
#include "list.h"
struct sway_server;
struct sway_input_device {
char *identifier;
struct wlr_input_device *wlr_device;
struct wl_list link;
struct wl_listener device_destroy;
bool is_virtual;
};
struct sway_input_manager {
struct wl_list devices;
struct wl_list seats;
struct wlr_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit;
struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard;
struct wlr_virtual_pointer_manager_v1 *virtual_pointer;
struct wlr_pointer_gestures_v1 *pointer_gestures;
struct wlr_transient_seat_manager_v1 *transient_seat_manager;
struct wl_listener new_input;
struct wl_listener inhibit_activate;
struct wl_listener inhibit_deactivate;
struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor;
struct wl_listener virtual_keyboard_new;
struct wl_listener virtual_pointer_new;
struct wl_listener transient_seat_create;
};
struct sway_input_manager *input_manager_create(struct sway_server *server);
void input_manager_finish(struct sway_input_manager *input);
bool input_manager_has_focus(struct sway_node *node);
void input_manager_set_focus(struct sway_node *node);
void input_manager_configure_xcursor(void);
void input_manager_apply_input_config(struct input_config *input_config);
void input_manager_configure_all_input_mappings(void);
void input_manager_reset_input(struct sway_input_device *input_device);
void input_manager_reset_all_inputs(void);
void input_manager_apply_seat_config(struct seat_config *seat_config);
struct sway_seat *input_manager_get_default_seat(void);
struct sway_seat *input_manager_get_seat(const char *seat_name, bool create);
/**
* If none of the seat configs have a fallback setting (either true or false),
* create the default seat (if needed) and set it as the fallback
*/
void input_manager_verify_fallback_seat(void);
/**
* Gets the last seat the user interacted with
*/
struct sway_seat *input_manager_current_seat(void);
struct input_config *input_device_get_config(struct sway_input_device *device);
char *input_device_get_identifier(struct wlr_input_device *device);
const char *input_device_get_type(struct sway_input_device *device);
#endif

View file

@ -0,0 +1,95 @@
#ifndef _SWAY_INPUT_KEYBOARD_H
#define _SWAY_INPUT_KEYBOARD_H
#include "sway/input/seat.h"
#define SWAY_KEYBOARD_PRESSED_KEYS_CAP 32
/**
* Get modifier mask from modifier name.
*
* Returns the modifier mask or 0 if the name isn't found.
*/
uint32_t get_modifier_mask_by_name(const char *name);
/**
* Get modifier name from modifier mask.
*
* Returns the modifier name or NULL if it isn't found.
*/
const char *get_modifier_name_by_mask(uint32_t modifier);
/**
* Get an array of modifier names from modifier_masks
*
* Populates the names array and return the number of names added.
*/
int get_modifier_names(const char **names, uint32_t modifier_masks);
struct sway_shortcut_state {
/**
* A list of pressed key ids (either keysyms or keycodes),
* including duplicates when different keycodes produce the same key id.
*
* Each key id is associated with the keycode (in `pressed_keycodes`)
* whose press generated it, so that the key id can be removed on
* keycode release without recalculating the transient link between
* keycode and key id at the time of the key press.
*/
uint32_t pressed_keys[SWAY_KEYBOARD_PRESSED_KEYS_CAP];
/**
* The list of keycodes associated to currently pressed key ids,
* including duplicates when a keycode generates multiple key ids.
*/
uint32_t pressed_keycodes[SWAY_KEYBOARD_PRESSED_KEYS_CAP];
uint32_t last_keycode;
uint32_t last_raw_modifiers;
size_t npressed;
uint32_t current_key;
};
struct sway_keyboard {
struct sway_seat_device *seat_device;
struct wlr_keyboard *wlr;
struct xkb_keymap *keymap;
xkb_layout_index_t effective_layout;
int32_t repeat_rate;
int32_t repeat_delay;
struct wl_listener keyboard_key;
struct wl_listener keyboard_modifiers;
struct sway_shortcut_state state_keysyms_translated;
struct sway_shortcut_state state_keysyms_raw;
struct sway_shortcut_state state_keycodes;
struct sway_shortcut_state state_pressed_sent;
struct sway_binding *held_binding;
struct wl_event_source *key_repeat_source;
struct sway_binding *repeat_binding;
};
struct sway_keyboard_group {
struct wlr_keyboard_group *wlr_group;
struct sway_seat_device *seat_device;
struct wl_listener keyboard_key;
struct wl_listener keyboard_modifiers;
struct wl_listener enter;
struct wl_listener leave;
struct wl_list link; // sway_seat::keyboard_groups
};
struct xkb_keymap *sway_keyboard_compile_keymap(struct input_config *ic,
char **error);
struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
struct sway_seat_device *device);
void sway_keyboard_configure(struct sway_keyboard *keyboard);
void sway_keyboard_destroy(struct sway_keyboard *keyboard);
void sway_keyboard_disarm_key_repeat(struct sway_keyboard *keyboard);
#endif

View file

@ -0,0 +1,14 @@
#ifndef _SWAY_INPUT_LIBINPUT_H
#define _SWAY_INPUT_LIBINPUT_H
#include "sway/input/input-manager.h"
bool sway_input_configure_libinput_device(struct sway_input_device *device);
void sway_input_configure_libinput_device_send_events(
struct sway_input_device *device);
void sway_input_reset_libinput_device(struct sway_input_device *device);
bool sway_libinput_device_is_builtin(struct sway_input_device *device);
#endif

373
include/sway/input/seat.h Normal file
View file

@ -0,0 +1,373 @@
#ifndef _SWAY_INPUT_SEAT_H
#define _SWAY_INPUT_SEAT_H
#include <scenefx/types/wlr_scene.h>
#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_touch.h>
#include <wlr/util/edges.h>
#include "sway/config.h"
#include "sway/input/input-manager.h"
#include "sway/input/tablet.h"
#include "sway/input/text_input.h"
struct sway_seat;
struct sway_seatop_impl {
void (*button)(struct sway_seat *seat, uint32_t time_msec,
struct wlr_input_device *device, uint32_t button,
enum wl_pointer_button_state state);
void (*pointer_motion)(struct sway_seat *seat, uint32_t time_msec);
void (*pointer_axis)(struct sway_seat *seat,
struct wlr_pointer_axis_event *event);
void (*hold_begin)(struct sway_seat *seat,
struct wlr_pointer_hold_begin_event *event);
void (*hold_end)(struct sway_seat *seat,
struct wlr_pointer_hold_end_event *event);
void (*pinch_begin)(struct sway_seat *seat,
struct wlr_pointer_pinch_begin_event *event);
void (*pinch_update)(struct sway_seat *seat,
struct wlr_pointer_pinch_update_event *event);
void (*pinch_end)(struct sway_seat *seat,
struct wlr_pointer_pinch_end_event *event);
void (*swipe_begin)(struct sway_seat *seat,
struct wlr_pointer_swipe_begin_event *event);
void (*swipe_update)(struct sway_seat *seat,
struct wlr_pointer_swipe_update_event *event);
void (*swipe_end)(struct sway_seat *seat,
struct wlr_pointer_swipe_end_event *event);
void (*rebase)(struct sway_seat *seat, uint32_t time_msec);
void (*touch_motion)(struct sway_seat *seat,
struct wlr_touch_motion_event *event, double lx, double ly);
void (*touch_up)(struct sway_seat *seat,
struct wlr_touch_up_event *event);
void (*touch_down)(struct sway_seat *seat,
struct wlr_touch_down_event *event, double lx, double ly);
void (*touch_cancel)(struct sway_seat *seat,
struct wlr_touch_cancel_event *event);
void (*tablet_tool_motion)(struct sway_seat *seat,
struct sway_tablet_tool *tool, uint32_t time_msec);
void (*tablet_tool_tip)(struct sway_seat *seat, struct sway_tablet_tool *tool,
uint32_t time_msec, enum wlr_tablet_tool_tip_state state);
void (*end)(struct sway_seat *seat);
void (*unref)(struct sway_seat *seat, struct sway_container *con);
bool allow_set_cursor;
};
struct sway_seat_device {
struct sway_seat *sway_seat;
struct sway_input_device *input_device;
struct sway_keyboard *keyboard;
struct sway_switch *switch_device;
struct sway_tablet *tablet;
struct sway_tablet_pad *tablet_pad;
struct wl_list link; // sway_seat::devices
};
struct sway_seat_node {
struct sway_seat *seat;
struct sway_node *node;
struct wl_list link; // sway_seat::focus_stack
struct wl_listener destroy;
};
struct sway_drag {
struct sway_seat *seat;
struct wlr_drag *wlr_drag;
struct wl_listener destroy;
};
struct sway_seat {
struct wlr_seat *wlr_seat;
struct sway_cursor *cursor;
// Seat scene tree structure
// - scene_tree
// - drag icons
// - drag icon 1
// - drag icon 2
// - seatop specific stuff
struct wlr_scene_tree *scene_tree;
struct wlr_scene_tree *drag_icons;
bool has_focus;
struct wl_list focus_stack; // list of containers in focus order
struct sway_workspace *workspace;
char *prev_workspace_name; // for workspace back_and_forth
struct wlr_layer_surface_v1 *focused_layer;
// If the exclusive layer is set, views cannot receive keyboard focus
bool has_exclusive_layer;
// Last touch point
int32_t touch_id;
double touch_x, touch_y;
// Seat operations (drag and resize)
const struct sway_seatop_impl *seatop_impl;
void *seatop_data;
uint32_t last_button_serial;
uint32_t idle_inhibit_sources, idle_wake_sources;
list_t *deferred_bindings; // struct sway_binding
struct sway_input_method_relay im_relay;
struct wl_listener focus_destroy;
struct wl_listener new_node;
struct wl_listener request_start_drag;
struct wl_listener start_drag;
struct wl_listener request_set_selection;
struct wl_listener request_set_primary_selection;
struct wl_listener destroy;
struct wl_list devices; // sway_seat_device::link
struct wl_list keyboard_groups; // sway_keyboard_group::link
struct wl_list keyboard_shortcuts_inhibitors;
// sway_keyboard_shortcuts_inhibitor::link
struct wl_list link; // input_manager::seats
};
struct sway_pointer_constraint {
struct sway_cursor *cursor;
struct wlr_pointer_constraint_v1 *constraint;
struct wl_listener set_region;
struct wl_listener destroy;
};
struct sway_keyboard_shortcuts_inhibitor {
struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor;
struct wl_listener destroy;
struct wl_list link; // sway_seat::keyboard_shortcuts_inhibitors
};
struct sway_seat *seat_create(const char *seat_name);
void seat_destroy(struct sway_seat *seat);
void seat_add_device(struct sway_seat *seat,
struct sway_input_device *device);
void seat_configure_device(struct sway_seat *seat,
struct sway_input_device *device);
void seat_configure_device_mapping(struct sway_seat *seat,
struct sway_input_device *input_device);
void seat_reset_device(struct sway_seat *seat,
struct sway_input_device *input_device);
void seat_remove_device(struct sway_seat *seat,
struct sway_input_device *device);
void seat_configure_xcursor(struct sway_seat *seat);
void seat_set_focus(struct sway_seat *seat, struct sway_node *node);
void seat_set_focus_container(struct sway_seat *seat,
struct sway_container *con);
void seat_set_focus_workspace(struct sway_seat *seat,
struct sway_workspace *ws);
/**
* Manipulate the focus stack without triggering any other behaviour.
*
* This can be used to set focus_inactive by calling the function a second time
* with the real focus.
*/
void seat_set_raw_focus(struct sway_seat *seat, struct sway_node *node);
void seat_set_focus_surface(struct sway_seat *seat,
struct wlr_surface *surface, bool unfocus);
void seat_set_focus_layer(struct sway_seat *seat,
struct wlr_layer_surface_v1 *layer);
void seat_unfocus_unless_client(struct sway_seat *seat, struct wl_client *client);
struct sway_node *seat_get_focus(struct sway_seat *seat);
struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat);
// If a scratchpad container is fullscreen global, this can be used to try to
// determine the last focused workspace. Otherwise, this should yield the same
// results as seat_get_focused_workspace.
struct sway_workspace *seat_get_last_known_workspace(struct sway_seat *seat);
struct sway_container *seat_get_focused_container(struct sway_seat *seat);
/**
* Return the last container to be focused for the seat (or the most recently
* opened if no container has received focused) that is a child of the given
* container. The focus-inactive container of the root window is the focused
* container for the seat (if the seat does have focus). This function can be
* used to determine what container gets focused next if the focused container
* is destroyed, or focus moves to a container with children and we need to
* descend into the next leaf in focus order.
*/
struct sway_node *seat_get_focus_inactive(struct sway_seat *seat,
struct sway_node *node);
struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat,
struct sway_workspace *workspace);
/**
* Descend into the focus stack to find the focus-inactive view. Useful for
* container placement when they change position in the tree.
*/
struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat,
struct sway_node *ancestor);
/**
* Return the immediate child of container which was most recently focused.
*/
struct sway_node *seat_get_active_tiling_child(struct sway_seat *seat,
struct sway_node *parent);
/**
* Iterate over the focus-inactive children of the container calling the
* function on each.
*/
void seat_for_each_node(struct sway_seat *seat,
void (*f)(struct sway_node *node, void *data), void *data);
void seat_apply_config(struct sway_seat *seat, struct seat_config *seat_config);
struct seat_config *seat_get_config(struct sway_seat *seat);
struct seat_config *seat_get_config_by_name(const char *name);
void seat_idle_notify_activity(struct sway_seat *seat,
enum sway_input_idle_source source);
bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface);
void drag_icons_update_position(struct sway_seat *seat);
enum wlr_edges find_resize_edge(struct sway_container *cont,
struct wlr_surface *surface, struct sway_cursor *cursor);
void seatop_begin_default(struct sway_seat *seat);
void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
double sx, double sy);
void seatop_begin_down_on_surface(struct sway_seat *seat,
struct wlr_surface *surface, double sx, double sy);
void seatop_begin_touch_down(struct sway_seat *seat, struct wlr_surface *surface,
struct wlr_touch_down_event *event, double sx, double sy, double lx, double ly);
void seatop_begin_move_floating(struct sway_seat *seat,
struct sway_container *con);
void seatop_begin_move_tiling_threshold(struct sway_seat *seat,
struct sway_container *con);
void seatop_begin_move_tiling(struct sway_seat *seat,
struct sway_container *con);
void seatop_begin_resize_floating(struct sway_seat *seat,
struct sway_container *con, enum wlr_edges edge);
void seatop_begin_resize_tiling(struct sway_seat *seat,
struct sway_container *con, enum wlr_edges edge);
struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat,
struct sway_workspace *workspace);
void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec,
uint32_t button, enum wl_pointer_button_state state);
void seat_consider_warp_to_focus(struct sway_seat *seat);
void seatop_button(struct sway_seat *seat, uint32_t time_msec,
struct wlr_input_device *device, uint32_t button,
enum wl_pointer_button_state state);
void seatop_pointer_motion(struct sway_seat *seat, uint32_t time_msec);
void seatop_pointer_axis(struct sway_seat *seat,
struct wlr_pointer_axis_event *event);
void seatop_tablet_tool_tip(struct sway_seat *seat,
struct sway_tablet_tool *tool, uint32_t time_msec,
enum wlr_tablet_tool_tip_state state);
void seatop_tablet_tool_motion(struct sway_seat *seat,
struct sway_tablet_tool *tool, uint32_t time_msec);
void seatop_hold_begin(struct sway_seat *seat,
struct wlr_pointer_hold_begin_event *event);
void seatop_hold_end(struct sway_seat *seat,
struct wlr_pointer_hold_end_event *event);
void seatop_pinch_begin(struct sway_seat *seat,
struct wlr_pointer_pinch_begin_event *event);
void seatop_pinch_update(struct sway_seat *seat,
struct wlr_pointer_pinch_update_event *event);
void seatop_pinch_end(struct sway_seat *seat,
struct wlr_pointer_pinch_end_event *event);
void seatop_swipe_begin(struct sway_seat *seat,
struct wlr_pointer_swipe_begin_event *event);
void seatop_swipe_update(struct sway_seat *seat,
struct wlr_pointer_swipe_update_event *event);
void seatop_swipe_end(struct sway_seat *seat,
struct wlr_pointer_swipe_end_event *event);
void seatop_touch_motion(struct sway_seat *seat,
struct wlr_touch_motion_event *event, double lx, double ly);
void seatop_touch_up(struct sway_seat *seat,
struct wlr_touch_up_event *event);
void seatop_touch_down(struct sway_seat *seat,
struct wlr_touch_down_event *event, double lx, double ly);
void seatop_touch_cancel(struct sway_seat *seat,
struct wlr_touch_cancel_event *event);
void seatop_rebase(struct sway_seat *seat, uint32_t time_msec);
/**
* End a seatop (ie. free any seatop specific resources).
*/
void seatop_end(struct sway_seat *seat);
/**
* Instructs the seatop implementation to drop any references to the given
* container (eg. because the container is destroying).
* The seatop may choose to abort itself in response to this.
*/
void seatop_unref(struct sway_seat *seat, struct sway_container *con);
bool seatop_allows_set_cursor(struct sway_seat *seat);
/**
* Returns the keyboard shortcuts inhibitor that applies to the given surface
* or NULL if none exists.
*/
struct sway_keyboard_shortcuts_inhibitor *
keyboard_shortcuts_inhibitor_get_for_surface(const struct sway_seat *seat,
const struct wlr_surface *surface);
/**
* Returns the keyboard shortcuts inhibitor that applies to the currently
* focused surface of a seat or NULL if none exists.
*/
struct sway_keyboard_shortcuts_inhibitor *
keyboard_shortcuts_inhibitor_get_for_focused_surface(const struct sway_seat *seat);
#endif

View file

@ -0,0 +1,24 @@
#ifndef _SWAY_INPUT_SWITCH_H
#define _SWAY_INPUT_SWITCH_H
#include "sway/input/seat.h"
struct sway_switch {
struct sway_seat_device *seat_device;
struct wlr_switch *wlr;
enum wlr_switch_state state;
enum wlr_switch_type type;
struct wl_listener switch_toggle;
};
struct sway_switch *sway_switch_create(struct sway_seat *seat,
struct sway_seat_device *device);
void sway_switch_configure(struct sway_switch *sway_switch);
void sway_switch_destroy(struct sway_switch *sway_switch);
void sway_switch_retrigger_bindings_for_all(void);
#endif

View file

@ -0,0 +1,69 @@
#ifndef _SWAY_INPUT_TABLET_H
#define _SWAY_INPUT_TABLET_H
#include <wlr/types/wlr_layer_shell_v1.h>
struct sway_seat;
struct wlr_tablet_tool;
struct sway_tablet {
struct wl_list link;
struct sway_seat_device *seat_device;
struct wlr_tablet_v2_tablet *tablet_v2;
};
enum sway_tablet_tool_mode {
SWAY_TABLET_TOOL_MODE_ABSOLUTE,
SWAY_TABLET_TOOL_MODE_RELATIVE,
};
struct sway_tablet_tool {
struct sway_seat *seat;
struct sway_tablet *tablet;
struct wlr_tablet_v2_tablet_tool *tablet_v2_tool;
enum sway_tablet_tool_mode mode;
double tilt_x, tilt_y;
struct wl_listener set_cursor;
struct wl_listener tool_destroy;
};
struct sway_tablet_pad {
struct wl_list link;
struct sway_seat_device *seat_device;
struct sway_tablet *tablet;
struct wlr_tablet_pad *wlr;
struct wlr_tablet_v2_tablet_pad *tablet_v2_pad;
struct wl_listener attach;
struct wl_listener button;
struct wl_listener ring;
struct wl_listener strip;
struct wlr_surface *current_surface;
struct wl_listener surface_destroy;
struct wl_listener tablet_destroy;
};
struct sway_tablet *sway_tablet_create(struct sway_seat *seat,
struct sway_seat_device *device);
void sway_configure_tablet(struct sway_tablet *tablet);
void sway_tablet_destroy(struct sway_tablet *tablet);
void sway_tablet_tool_configure(struct sway_tablet *tablet,
struct wlr_tablet_tool *wlr_tool);
struct sway_tablet_pad *sway_tablet_pad_create(struct sway_seat *seat,
struct sway_seat_device *device);
void sway_configure_tablet_pad(struct sway_tablet_pad *tablet_pad);
void sway_tablet_pad_destroy(struct sway_tablet_pad *tablet_pad);
void sway_tablet_pad_set_focus(struct sway_tablet_pad *tablet_pad,
struct wlr_surface *surface);
#endif

View file

@ -0,0 +1,73 @@
#ifndef _SWAY_INPUT_TEXT_INPUT_H
#define _SWAY_INPUT_TEXT_INPUT_H
#include <wlr/types/wlr_text_input_v3.h>
#include <wlr/types/wlr_input_method_v2.h>
#include <wlr/types/wlr_compositor.h>
/**
* The relay structure manages the relationship between text-input and
* input_method interfaces on a given seat. Multiple text-input interfaces may
* be bound to a relay, but at most one will be focused (receiving events) at
* a time. At most one input-method interface may be bound to the seat. The
* relay manages life cycle of both sides. When both sides are present and
* focused, the relay passes messages between them.
*
* Text input focus is a subset of keyboard focus - if the text-input is
* in the focused state, wl_keyboard sent an enter as well. However, having
* wl_keyboard focused doesn't mean that text-input will be focused.
*/
struct sway_input_method_relay {
struct sway_seat *seat;
struct wl_list text_inputs; // sway_text_input::link
struct wl_list input_popups; // sway_input_popup::link
struct wlr_input_method_v2 *input_method; // doesn't have to be present
struct wl_listener text_input_new;
struct wl_listener text_input_manager_destroy;
struct wl_listener input_method_new;
struct wl_listener input_method_manager_destroy;
struct wl_listener input_method_commit;
struct wl_listener input_method_new_popup_surface;
struct wl_listener input_method_grab_keyboard;
struct wl_listener input_method_destroy;
struct wl_listener input_method_keyboard_grab_destroy;
};
struct sway_text_input {
struct sway_input_method_relay *relay;
struct wlr_text_input_v3 *input;
// The surface getting seat's focus. Stored for when text-input cannot
// be sent an enter event immediately after getting focus, e.g. when
// there's no input method available. Cleared once text-input is entered.
struct wlr_surface *pending_focused_surface;
struct wl_list link;
struct wl_listener pending_focused_surface_destroy;
struct wl_listener text_input_enable;
struct wl_listener text_input_commit;
struct wl_listener text_input_disable;
struct wl_listener text_input_destroy;
};
void sway_input_method_relay_init(struct sway_seat *seat,
struct sway_input_method_relay *relay);
void sway_input_method_relay_finish(struct sway_input_method_relay *relay);
// Updates currently focused surface. Surface must belong to the same seat.
void sway_input_method_relay_set_focus(struct sway_input_method_relay *relay,
struct wlr_surface *surface);
struct sway_text_input *sway_text_input_create(
struct sway_input_method_relay *relay,
struct wlr_text_input_v3 *text_input);
#endif

View file

@ -0,0 +1,23 @@
#ifndef _SWAY_INPUT_TEXT_INPUT_POPUP_H
#define _SWAY_INPUT_TEXT_INPUT_POPUP_H
#include "sway/tree/view.h"
struct sway_input_popup {
struct sway_input_method_relay *relay;
struct wlr_scene_tree *scene_tree;
struct sway_popup_desc desc;
struct wlr_input_popup_surface_v2 *popup_surface;
struct wlr_output *fixed_output;
struct wl_list link;
struct wl_listener popup_destroy;
struct wl_listener popup_surface_commit;
struct wl_listener popup_surface_map;
struct wl_listener popup_surface_unmap;
struct wl_listener focused_surface_unmap;
};
#endif

20
include/sway/ipc-json.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef _SWAY_IPC_JSON_H
#define _SWAY_IPC_JSON_H
#include <json.h>
#include "sway/output.h"
#include "sway/tree/container.h"
#include "sway/input/input-manager.h"
json_object *ipc_json_get_version(void);
json_object *ipc_json_get_binding_mode(void);
json_object *ipc_json_describe_disabled_output(struct sway_output *o);
json_object *ipc_json_describe_non_desktop_output(struct sway_output_non_desktop *o);
json_object *ipc_json_describe_node(struct sway_node *node);
json_object *ipc_json_describe_node_recursive(struct sway_node *node);
json_object *ipc_json_describe_input(struct sway_input_device *device);
json_object *ipc_json_describe_seat(struct sway_seat *seat);
json_object *ipc_json_describe_bar_config(struct bar_config *bar);
#endif

26
include/sway/ipc-server.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef _SWAY_IPC_SERVER_H
#define _SWAY_IPC_SERVER_H
#include <sys/socket.h>
#include "sway/config.h"
#include "sway/input/input-manager.h"
#include "sway/tree/container.h"
#include "ipc.h"
struct sway_server;
void ipc_init(struct sway_server *server);
struct sockaddr_un *ipc_user_sockaddr(void);
void ipc_event_workspace(struct sway_workspace *old,
struct sway_workspace *new, const char *change);
void ipc_event_window(struct sway_container *window, const char *change);
void ipc_event_barconfig_update(struct bar_config *bar);
void ipc_event_bar_state_update(struct bar_config *bar);
void ipc_event_mode(const char *mode, bool pango);
void ipc_event_shutdown(const char *reason);
void ipc_event_binding(struct sway_binding *binding);
void ipc_event_input(const char *change, struct sway_input_device *device);
void ipc_event_output(void);
#endif

View file

@ -0,0 +1,19 @@
#include <stdbool.h>
struct layer_criteria {
char *namespace;
char *cmdlist;
bool shadow_enabled;
bool blur_enabled;
bool blur_xray;
bool blur_ignore_transparent;
int corner_radius;
};
void layer_criteria_destroy(struct layer_criteria *criteria);
struct layer_criteria *layer_criteria_add(char *namespace, char *cmdlist);
// Get the matching criteria for a specified `sway_layer_surface`
struct layer_criteria *layer_criteria_for_namespace(char *namespace);

61
include/sway/layers.h Normal file
View file

@ -0,0 +1,61 @@
#ifndef _SWAY_LAYERS_H
#define _SWAY_LAYERS_H
#include <stdbool.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include "sway/layer_criteria.h"
#include "sway/tree/view.h"
struct sway_layer_surface {
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener surface_commit;
struct wl_listener node_destroy;
struct wl_listener new_popup;
bool mapped;
struct wlr_scene_tree *popups;
struct sway_popup_desc desc;
struct sway_output *output;
struct wlr_scene_blur *blur_node;
struct wlr_scene_shadow *shadow_node;
bool shadow_enabled;
bool blur_enabled;
bool blur_xray;
bool blur_ignore_transparent;
int corner_radius;
struct wl_list link; // sway_output.layer_surfaces
struct wlr_scene_layer_surface_v1 *scene;
struct wlr_scene_tree *tree;
struct wlr_layer_surface_v1 *layer_surface;
};
struct sway_layer_popup {
struct wlr_xdg_popup *wlr_popup;
struct wlr_scene_tree *scene;
struct sway_layer_surface *toplevel;
struct wl_listener destroy;
struct wl_listener new_popup;
struct wl_listener commit;
struct wl_listener reposition;
};
struct sway_output;
struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
struct wlr_surface *surface);
void arrange_layers(struct sway_output *output);
void layer_apply_criteria(struct sway_layer_surface *surface, struct layer_criteria *criteria);
void destroy_layers(struct sway_output *output);
#endif

6
include/sway/lock.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef _SWAY_LOCK_H
#define _SWAY_LOCK_H
void arrange_locks(void);
#endif

159
include/sway/output.h Normal file
View file

@ -0,0 +1,159 @@
#ifndef _SWAY_OUTPUT_H
#define _SWAY_OUTPUT_H
#include <scenefx/types/wlr_scene.h>
#include <time.h>
#include <unistd.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_damage_ring.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_scene.h>
#include "config.h"
#include "sway/tree/node.h"
#include "sway/tree/view.h"
struct sway_server;
struct sway_container;
struct sway_output_state {
list_t *workspaces;
struct sway_workspace *active_workspace;
};
struct sway_output {
struct sway_node node;
struct {
struct wlr_scene_tree *shell_background;
struct wlr_scene_tree *shell_bottom;
// Used for optimized blur. Everything exclusively below gets blurred
struct wlr_scene_optimized_blur *blur_layer;
struct wlr_scene_tree *tiling;
struct wlr_scene_tree *fullscreen;
struct wlr_scene_tree *shell_top;
struct wlr_scene_tree *shell_overlay;
struct wlr_scene_tree *session_lock;
} layers;
// when a container is fullscreen, in case the fullscreen surface is
// translucent (can see behind) we must make sure that the background is a
// solid color in order to conform to the wayland protocol. This rect
// ensures that when looking through a surface, all that will be seen
// is black.
struct wlr_scene_rect *fullscreen_background;
struct wlr_output *wlr_output;
struct wlr_scene_output *scene_output;
struct sway_server *server;
struct wl_list link;
struct wlr_box usable_area;
int lx, ly; // layout coords
int width, height; // transformed buffer size
enum wl_output_subpixel detected_subpixel;
enum scale_filter_mode scale_filter;
bool enabled;
list_t *workspaces;
struct wl_list layer_surfaces; // sway_layer_surface.link
struct sway_output_state current;
struct sway_workspace *prev_active_workspace;
struct wl_listener layout_destroy;
struct wl_listener destroy;
struct wl_listener present;
struct wl_listener frame;
struct wl_listener request_state;
struct wlr_color_transform *color_transform;
struct wlr_ext_workspace_group_handle_v1 *ext_workspace_group;
struct timespec last_presentation;
uint32_t refresh_nsec;
int max_render_time; // In milliseconds
struct wl_event_source *repaint_timer;
bool allow_tearing;
bool hdr;
};
struct sway_output_non_desktop {
struct wlr_output *wlr_output;
struct wl_listener destroy;
};
struct sway_output *output_create(struct wlr_output *wlr_output);
void output_destroy(struct sway_output *output);
void output_begin_destroy(struct sway_output *output);
struct sway_output *output_from_wlr_output(struct wlr_output *output);
struct sway_output *output_get_in_direction(struct sway_output *reference,
enum wlr_direction direction);
void output_configure_scene(struct sway_output *output,
struct wlr_scene_node *node, bool has_titlebar,
struct sway_container *closest_con);
void output_add_workspace(struct sway_output *output,
struct sway_workspace *workspace);
typedef void (*sway_surface_iterator_func_t)(struct sway_output *output,
struct sway_view *view, struct wlr_surface *surface, struct wlr_box *box,
void *user_data);
bool output_match_name_or_id(struct sway_output *output,
const char *name_or_id);
// this ONLY includes the enabled outputs
struct sway_output *output_by_name_or_id(const char *name_or_id);
// this includes all the outputs, including disabled ones
struct sway_output *all_output_by_name_or_id(const char *name_or_id);
void output_sort_workspaces(struct sway_output *output);
void output_enable(struct sway_output *output);
void output_disable(struct sway_output *output);
struct sway_workspace *output_get_active_workspace(struct sway_output *output);
void output_for_each_workspace(struct sway_output *output,
void (*f)(struct sway_workspace *ws, void *data), void *data);
void output_for_each_container(struct sway_output *output,
void (*f)(struct sway_container *con, void *data), void *data);
struct sway_workspace *output_find_workspace(struct sway_output *output,
bool (*test)(struct sway_workspace *ws, void *data), void *data);
struct sway_container *output_find_container(struct sway_output *output,
bool (*test)(struct sway_container *con, void *data), void *data);
void output_get_box(struct sway_output *output, struct wlr_box *box);
bool output_supports_hdr(struct wlr_output *output, const char **unsupported_reason_ptr);
enum sway_container_layout output_get_default_layout(
struct sway_output *output);
enum wlr_direction opposite_direction(enum wlr_direction d);
void handle_output_manager_apply(struct wl_listener *listener, void *data);
void handle_output_manager_test(struct wl_listener *listener, void *data);
void handle_output_power_manager_set_mode(struct wl_listener *listener,
void *data);
struct sway_output_non_desktop *output_non_desktop_create(struct wlr_output *wlr_output);
void update_output_manager_config(struct sway_server *server);
#endif

View file

@ -0,0 +1,34 @@
/**
* Across a wayland compositor, there are multiple shells: It can be
* a toplevel, or a layer_shell, or even something more meta like a drag
* icon or highlight indicators when dragging windows around.
*
* This object lets us store values that represent these modes of operation
* and keep track of what object is being represented.
*/
#ifndef _SWAY_SCENE_DESCRIPTOR_H
#define _SWAY_SCENE_DESCRIPTOR_H
#include <scenefx/types/wlr_scene.h>
enum sway_scene_descriptor_type {
SWAY_SCENE_DESC_BUFFER_TIMER,
SWAY_SCENE_DESC_NON_INTERACTIVE,
SWAY_SCENE_DESC_CONTAINER,
SWAY_SCENE_DESC_VIEW,
SWAY_SCENE_DESC_LAYER_SHELL,
SWAY_SCENE_DESC_XWAYLAND_UNMANAGED,
SWAY_SCENE_DESC_POPUP,
SWAY_SCENE_DESC_DRAG_ICON,
SWAY_SCENE_DESC_SAVED_BUFFER,
};
bool scene_descriptor_assign(struct wlr_scene_node *node,
enum sway_scene_descriptor_type type, void *data);
void *scene_descriptor_try_get(struct wlr_scene_node *node,
enum sway_scene_descriptor_type type);
void scene_descriptor_destroy(struct wlr_scene_node *node,
enum sway_scene_descriptor_type type);
#endif

200
include/sway/server.h Normal file
View file

@ -0,0 +1,200 @@
#ifndef _SWAY_SERVER_H
#define _SWAY_SERVER_H
#include <stdbool.h>
#include <wayland-server-core.h>
#include "config.h"
#include "list.h"
#include "sway/desktop/idle_inhibit_v1.h"
#if WLR_HAS_XWAYLAND
#include "sway/xwayland.h"
#endif
struct sway_transaction;
struct sway_session_lock {
struct wlr_session_lock_v1 *lock;
struct wlr_surface *focused;
bool abandoned;
struct wl_list outputs; // struct sway_session_lock_output
// invalid if the session is abandoned
struct wl_listener new_surface;
struct wl_listener unlock;
struct wl_listener destroy;
};
struct sway_server {
struct wl_display *wl_display;
struct wl_event_loop *wl_event_loop;
char *socket;
struct wlr_backend *backend;
struct wlr_session *session;
// secondary headless backend used for creating virtual outputs on-the-fly
struct wlr_backend *headless_backend;
struct wlr_renderer *renderer;
struct wlr_allocator *allocator;
struct wlr_compositor *compositor;
struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1;
struct wlr_data_device_manager *data_device_manager;
struct sway_input_manager *input;
struct wl_listener new_output;
struct wl_listener renderer_lost;
struct wl_event_source *recreating_renderer;
struct wlr_idle_notifier_v1 *idle_notifier_v1;
struct sway_idle_inhibit_manager_v1 idle_inhibit_manager_v1;
struct wlr_layer_shell_v1 *layer_shell;
struct wl_listener layer_shell_surface;
struct wlr_xdg_shell *xdg_shell;
struct wl_listener xdg_shell_toplevel;
struct wlr_tablet_manager_v2 *tablet_v2;
#if WLR_HAS_XWAYLAND
struct sway_xwayland xwayland;
struct wl_listener xwayland_surface;
struct wl_listener xwayland_ready;
#endif
struct wlr_relative_pointer_manager_v1 *relative_pointer_manager;
struct wlr_server_decoration_manager *server_decoration_manager;
struct wl_listener server_decoration;
struct wl_list decorations; // sway_server_decoration::link
struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager;
struct wl_listener xdg_decoration;
struct wl_list xdg_decorations; // sway_xdg_decoration::link
struct wlr_drm_lease_v1_manager *drm_lease_manager;
struct wl_listener drm_lease_request;
struct wlr_pointer_constraints_v1 *pointer_constraints;
struct wl_listener pointer_constraint;
struct wlr_xdg_output_manager_v1 *xdg_output_manager_v1;
struct wlr_output_manager_v1 *output_manager_v1;
struct wl_listener output_manager_apply;
struct wl_listener output_manager_test;
struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1;
struct wl_listener gamma_control_set_gamma;
struct {
struct sway_session_lock *lock;
struct wlr_session_lock_manager_v1 *manager;
struct wl_listener new_lock;
struct wl_listener manager_destroy;
} session_lock;
struct wlr_output_power_manager_v1 *output_power_manager_v1;
struct wl_listener output_power_manager_set_mode;
struct wlr_input_method_manager_v2 *input_method;
struct wlr_text_input_manager_v3 *text_input;
struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list;
struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
struct wlr_content_type_manager_v1 *content_type_manager_v1;
struct wlr_data_control_manager_v1 *wlr_data_control_manager_v1;
struct wlr_ext_data_control_manager_v1 *ext_data_control_manager_v1;
struct wlr_screencopy_manager_v1 *screencopy_manager_v1;
struct wlr_ext_image_copy_capture_manager_v1 *ext_image_copy_capture_manager_v1;
struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager_v1;
struct wlr_security_context_manager_v1 *security_context_manager_v1;
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *ext_foreign_toplevel_image_capture_source_manager_v1;
struct wl_listener new_foreign_toplevel_capture_request;
struct wlr_xdg_activation_v1 *xdg_activation_v1;
struct wl_listener xdg_activation_v1_request_activate;
struct wl_listener xdg_activation_v1_new_token;
struct wl_listener xdg_toplevel_tag_manager_v1_set_tag;
struct wl_listener request_set_cursor_shape;
struct wlr_tearing_control_manager_v1 *tearing_control_v1;
struct wl_listener tearing_control_new_object;
struct wl_list tearing_controllers; // sway_tearing_controller::link
struct wlr_ext_workspace_manager_v1 *workspace_manager_v1;
struct wl_listener workspace_manager_v1_commit;
struct wl_list pending_launcher_ctxs; // launcher_ctx::link
// The timeout for transactions, after which a transaction is applied
// regardless of readiness.
size_t txn_timeout_ms;
// Stores a transaction after it has been committed, but is waiting for
// views to ack the new dimensions before being applied. A queued
// transaction is frozen and must not have new instructions added to it.
struct sway_transaction *queued_transaction;
// Stores a pending transaction that will be committed once the existing
// queued transaction is applied and freed. The pending transaction can be
// updated with new instructions as needed.
struct sway_transaction *pending_transaction;
// Stores the nodes that have been marked as "dirty" and will be put into
// the pending transaction.
list_t *dirty_nodes;
struct wl_event_source *delayed_modeset;
};
extern struct sway_server server;
struct sway_debug {
bool noatomic; // Ignore atomic layout updates
bool txn_timings; // Log verbose messages about transactions
bool txn_wait; // Always wait for the timeout before applying
};
extern struct sway_debug debug;
extern bool unsupported_gpu_detected;
void sway_terminate(int exit_code);
bool server_init(struct sway_server *server);
void server_fini(struct sway_server *server);
bool server_start(struct sway_server *server);
void server_run(struct sway_server *server);
void handle_new_output(struct wl_listener *listener, void *data);
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data);
void handle_layer_shell_surface(struct wl_listener *listener, void *data);
bool sway_session_lock_init(void);
void sway_session_lock_add_output(struct sway_session_lock *lock,
struct sway_output *output);
bool sway_session_lock_has_surface(struct sway_session_lock *lock,
struct wlr_surface *surface);
void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data);
#if WLR_HAS_XWAYLAND
void handle_xwayland_surface(struct wl_listener *listener, void *data);
#endif
void handle_server_decoration(struct wl_listener *listener, void *data);
void handle_xdg_decoration(struct wl_listener *listener, void *data);
void handle_pointer_constraint(struct wl_listener *listener, void *data);
void xdg_activation_v1_handle_request_activate(struct wl_listener *listener,
void *data);
void xdg_activation_v1_handle_new_token(struct wl_listener *listener,
void *data);
void set_rr_scheduling(void);
void handle_new_tearing_hint(struct wl_listener *listener, void *data);
#endif

View file

@ -0,0 +1,28 @@
#ifndef _SWAY_BUFFER_H
#define _SWAY_BUFFER_H
#include <scenefx/types/wlr_scene.h>
struct sway_text_node {
int width;
int max_width;
int height;
int baseline;
bool pango_markup;
float color[4];
float background[4];
struct wlr_scene_node *node;
};
struct sway_text_node *sway_text_node_create(struct wlr_scene_tree *parent,
char *text, float color[4], bool pango_markup);
void sway_text_node_set_color(struct sway_text_node *node, float color[4]);
void sway_text_node_set_text(struct sway_text_node *node, char *text);
void sway_text_node_set_max_width(struct sway_text_node *node, int max_width);
void sway_text_node_set_background(struct sway_text_node *node, float background[4]);
#endif

30
include/sway/swaynag.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef _SWAY_SWAYNAG_H
#define _SWAY_SWAYNAG_H
#include <wayland-server-core.h>
#include "stringop.h"
struct swaynag_instance {
struct wl_client *client;
struct wl_listener client_destroy;
const char *args;
int fd[2];
bool detailed;
};
// Spawn swaynag. If swaynag->detailed, then swaynag->fd[1] will left open
// so it can be written to. Call swaynag_show when done writing. This will
// be automatically called by swaynag_log if the instance is not spawned and
// swaynag->detailed is true.
bool swaynag_spawn(const char *swaynag_command,
struct swaynag_instance *swaynag);
// Write a log message to swaynag->fd[1]. This will fail when swaynag->detailed
// is false.
void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
const char *fmt, ...) _SWAY_ATTRIB_PRINTF(3, 4);
// If swaynag->detailed, close swaynag->fd[1] so swaynag displays
void swaynag_show(struct swaynag_instance *swaynag);
#endif

View file

@ -0,0 +1,19 @@
#ifndef _SWAY_ARRANGE_H
#define _SWAY_ARRANGE_H
struct sway_output;
struct sway_workspace;
struct sway_container;
struct sway_node;
void arrange_container(struct sway_container *container);
void arrange_workspace(struct sway_workspace *workspace);
void arrange_output(struct sway_output *output);
void arrange_root(void);
void arrange_node(struct sway_node *node);
#endif

View file

@ -0,0 +1,404 @@
#ifndef _SWAY_CONTAINER_H
#define _SWAY_CONTAINER_H
#include <scenefx/types/wlr_scene.h>
#include <stdint.h>
#include <sys/types.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_scene.h>
#include "list.h"
#include "sway/animation_manager.h"
#include "sway/tree/node.h"
struct sway_view;
struct sway_seat;
enum sway_container_layout {
L_NONE,
L_HORIZ,
L_VERT,
L_STACKED,
L_TABBED,
};
enum sway_container_border {
B_NONE,
B_PIXEL,
B_NORMAL,
B_CSD,
};
enum sway_fullscreen_mode {
FULLSCREEN_NONE,
FULLSCREEN_WORKSPACE,
FULLSCREEN_GLOBAL,
};
struct sway_root;
struct sway_output;
struct sway_workspace;
struct sway_view;
enum wlr_direction;
struct sway_container_state {
// Container properties
enum sway_container_layout layout;
double x, y;
double width, height;
enum sway_fullscreen_mode fullscreen_mode;
struct sway_workspace *workspace; // NULL when hidden in the scratchpad
struct sway_container *parent; // NULL if container in root of workspace
list_t *children; // struct sway_container
struct sway_container *focused_inactive_child;
bool focused;
enum sway_container_border border;
int border_thickness;
bool border_top;
bool border_bottom;
bool border_left;
bool border_right;
// These are in layout coordinates.
double content_x, content_y;
double content_width, content_height;
};
struct sway_container {
struct sway_node node;
struct sway_view *view;
struct wlr_scene_tree *scene_tree;
struct {
struct wlr_scene_tree *tree;
struct wlr_scene_rect *border;
struct wlr_scene_rect *background_left;
struct wlr_scene_rect *background_right;
struct sway_text_node *title_text;
struct sway_text_node *marks_text;
} title_bar;
struct {
struct wlr_scene_tree *tree;
struct wlr_scene_rect *top;
struct wlr_scene_rect *bottom;
struct wlr_scene_rect *left;
struct wlr_scene_rect *right;
} border;
struct wlr_scene_blur *blur;
struct wlr_scene_shadow *shadow;
struct wlr_scene_rect *dim_rect;
struct wlr_scene_tree *content_tree;
struct sway_container_state current;
struct sway_container_state pending;
char *title; // The view's title (unformatted)
char *formatted_title; // The title displayed in the title bar
int title_width;
char *title_format;
enum sway_container_layout prev_split_layout;
// Whether stickiness has been enabled on this container. Use
// `container_is_sticky_[or_child]` rather than accessing this field
// directly; it'll also check that the container is floating.
bool is_sticky;
// For C_ROOT, this has no meaning
// For other types, this is the position in layout coordinates
// Includes borders
double saved_x, saved_y;
double saved_width, saved_height;
// Used when the view changes to CSD unexpectedly. This will be a non-B_CSD
// border which we use to restore when the view returns to SSD.
enum sway_container_border saved_border;
// The share of the space of parent container this container occupies
double width_fraction;
double height_fraction;
// The share of space of the parent container that all children occupy
// Used for doing the resize calculations
double child_total_width;
double child_total_height;
// Indicates that the container is a scratchpad container.
// Both hidden and visible scratchpad containers have scratchpad=true.
// Hidden scratchpad containers have a NULL parent.
bool scratchpad;
// Stores last output size and position for adjusting coordinates of
// scratchpad windows.
// Unused for non-scratchpad windows.
struct wlr_box transform;
float alpha;
int corner_radius;
bool blur_enabled;
bool shadow_enabled;
float dim;
struct {
struct animation animation;
float from_alpha;
float to_alpha;
int from_x;
int from_y;
int to_x;
int to_y;
int from_width;
int to_width;
int from_height;
int to_height;
int current_global_x;
int current_global_y;
int current_width;
int current_height;
int current_content_width; // needed for output.c
int current_content_height; // needed for output.c
bool seat_is_resizing;
bool seat_is_moving_float;
} animation_state;
list_t *marks; // char *
struct {
struct wl_signal destroy;
} events;
};
struct sway_container *container_create(struct sway_view *view);
void container_destroy(struct sway_container *con);
void container_begin_destroy(struct sway_container *con);
/**
* Search a container's descendants a container based on test criteria. Returns
* the first container that passes the test.
*/
struct sway_container *container_find_child(struct sway_container *container,
bool (*test)(struct sway_container *view, void *data), void *data);
void container_for_each_child(struct sway_container *container,
void (*f)(struct sway_container *container, void *data), void *data);
/**
* Returns the fullscreen container obstructing this container if it exists.
*/
struct sway_container *container_obstructing_fullscreen_container(struct sway_container *container);
/**
* Returns true if the given container is an ancestor of this container.
*/
bool container_has_ancestor(struct sway_container *container,
struct sway_container *ancestor);
void container_reap_empty(struct sway_container *con);
struct sway_container *container_flatten(struct sway_container *container);
void container_update_title_bar(struct sway_container *container);
void container_update_marks(struct sway_container *container);
size_t parse_title_format(struct sway_container *container, char *buffer);
size_t container_build_representation(enum sway_container_layout layout,
list_t *children, char *buffer);
void container_update_representation(struct sway_container *container);
/**
* Return the height of a regular title bar.
*/
size_t container_titlebar_height(void);
void floating_calculate_constraints(int *min_width, int *max_width,
int *min_height, int *max_height);
void floating_fix_coordinates(struct sway_container *con,
struct wlr_box *old, struct wlr_box *new);
void container_floating_resize_and_center(struct sway_container *con);
void container_floating_set_default_size(struct sway_container *con);
void container_set_resizing(struct sway_container *con, bool resizing);
void container_set_floating(struct sway_container *container, bool enable);
void container_set_geometry_from_content(struct sway_container *con);
/**
* Determine if the given container is itself floating.
* This will return false for any descendants of a floating container.
*
* Uses pending container state.
*/
bool container_is_floating(struct sway_container *container);
/**
* Get a container's box in layout coordinates.
*/
void container_get_box(struct sway_container *container, struct wlr_box *box);
/**
* Move a floating container by the specified amount.
*/
void container_floating_translate(struct sway_container *con,
double x_amount, double y_amount);
/**
* Choose an output for the floating container's new position.
*/
struct sway_output *container_floating_find_output(struct sway_container *con);
/**
* Move a floating container to a new layout-local position.
*/
void container_floating_move_to(struct sway_container *con,
double lx, double ly);
/**
* Move a floating container to the center of the workspace.
*/
void container_floating_move_to_center(struct sway_container *con);
bool container_has_urgent_child(struct sway_container *container);
/**
* If the container is involved in a drag or resize operation via a mouse, this
* ends the operation.
*/
void container_end_mouse_operation(struct sway_container *container);
void container_set_fullscreen(struct sway_container *con,
enum sway_fullscreen_mode mode);
/**
* Convenience function.
*/
void container_fullscreen_disable(struct sway_container *con);
/**
* Walk up the container tree branch starting at the given container, and return
* its earliest ancestor.
*/
struct sway_container *container_toplevel_ancestor(
struct sway_container *container);
/**
* Return true if the container is floating, or a child of a floating split
* container.
*/
bool container_is_floating_or_child(struct sway_container *container);
/**
* Return true if the container is fullscreen, or a child of a fullscreen split
* container.
*/
bool container_is_fullscreen_or_child(struct sway_container *container);
enum sway_container_layout container_parent_layout(struct sway_container *con);
list_t *container_get_siblings(struct sway_container *container);
int container_sibling_index(struct sway_container *child);
void container_handle_fullscreen_reparent(struct sway_container *con);
void container_add_child(struct sway_container *parent,
struct sway_container *child);
void container_insert_child(struct sway_container *parent,
struct sway_container *child, int i);
/**
* Side should be 0 to add before, or 1 to add after.
*/
void container_add_sibling(struct sway_container *parent,
struct sway_container *child, bool after);
void container_detach(struct sway_container *child);
void container_replace(struct sway_container *container,
struct sway_container *replacement);
void container_swap(struct sway_container *con1, struct sway_container *con2);
struct sway_container *container_split(struct sway_container *child,
enum sway_container_layout layout);
bool container_is_transient_for(struct sway_container *child,
struct sway_container *ancestor);
/**
* Find any container that has the given mark and return it.
*/
struct sway_container *container_find_mark(char *mark);
/**
* Find any container that has the given mark and remove the mark from the
* container. Returns true if it matched a container.
*/
bool container_find_and_unmark(char *mark);
/**
* Remove all marks from the container.
*/
void container_clear_marks(struct sway_container *container);
bool container_has_mark(struct sway_container *container, char *mark);
void container_add_mark(struct sway_container *container, char *mark);
void container_raise_floating(struct sway_container *con);
bool container_is_scratchpad_hidden(struct sway_container *con);
bool container_is_scratchpad_hidden_or_child(struct sway_container *con);
bool container_is_sticky(struct sway_container *con);
bool container_is_sticky_or_child(struct sway_container *con);
/**
* This will destroy pairs of redundant H/V splits
* e.g. H[V[H[app app]] app] -> H[app app app]
* The middle "V[H[" are eliminated by a call to container_squash
* on the V[ con. It's grandchildren are added to its parent.
*
* This function is roughly equivalent to i3's tree_flatten here:
* https://github.com/i3/i3/blob/1f0c628cde40cf87371481041b7197344e0417c6/src/tree.c#L651
*
* Returns the number of new containers added to the parent
*/
int container_squash(struct sway_container *con);
void container_arrange_title_bar(struct sway_container *con);
void container_update(struct sway_container *con);
void container_update_itself_and_parents(struct sway_container *con);
bool container_has_shadow(struct sway_container *con);
bool container_has_corner_radius(struct sway_container *con);
#endif

97
include/sway/tree/node.h Normal file
View file

@ -0,0 +1,97 @@
#ifndef _SWAY_NODE_H
#define _SWAY_NODE_H
#include <scenefx/types/wlr_scene.h>
#include <wayland-server-core.h>
#include <stdbool.h>
#include "list.h"
#define MIN_SANE_W 100
#define MIN_SANE_H 60
struct sway_root;
struct sway_output;
struct sway_workspace;
struct sway_container;
struct sway_transaction_instruction;
struct wlr_box;
enum sway_node_type {
N_ROOT,
N_OUTPUT,
N_WORKSPACE,
N_CONTAINER,
};
struct sway_node {
enum sway_node_type type;
union {
struct sway_root *sway_root;
struct sway_output *sway_output;
struct sway_workspace *sway_workspace;
struct sway_container *sway_container;
};
/**
* A unique ID to identify this node.
* Primarily used in the get_tree JSON output.
*/
size_t id;
struct sway_transaction_instruction *instruction;
size_t ntxnrefs;
bool destroying;
// If true, indicates that the container has pending state that differs from
// the current.
bool dirty;
struct {
struct wl_signal destroy;
} events;
};
void node_init(struct sway_node *node, enum sway_node_type type, void *thing);
const char *node_type_to_str(enum sway_node_type type);
/**
* Mark a node as dirty if it isn't already. Dirty nodes will be included in the
* next transaction then unmarked as dirty.
*/
void node_set_dirty(struct sway_node *node);
bool node_is_view(struct sway_node *node);
char *node_get_name(struct sway_node *node);
void node_get_box(struct sway_node *node, struct wlr_box *box);
struct sway_output *node_get_output(struct sway_node *node);
enum sway_container_layout node_get_layout(struct sway_node *node);
struct sway_node *node_get_parent(struct sway_node *node);
list_t *node_get_children(struct sway_node *node);
bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor);
// when destroying a sway tree, it's not known which order the tree will be
// destroyed. To prevent freeing of scene_nodes recursing up the tree,
// let's use this helper function to disown them to the staging node.
void scene_node_disown_children(struct wlr_scene_tree *tree);
// a helper function used to allocate tree nodes. If an allocation failure
// occurs a flag is flipped that can be checked later to destroy a parent
// of this scene node preventing memory leaks.
struct wlr_scene_tree *alloc_scene_tree(struct wlr_scene_tree *parent,
bool *failed);
struct wlr_scene_shadow *alloc_scene_shadow(struct wlr_scene_tree *parent,
int width, int height, int corner_radius, float blur_sigma,
const float color [static 4], bool *failed);
struct wlr_scene_blur *alloc_scene_blur(struct wlr_scene_tree *parent,
int width, int height, bool *failed);
#endif

124
include/sway/tree/root.h Normal file
View file

@ -0,0 +1,124 @@
#ifndef _SWAY_ROOT_H
#define _SWAY_ROOT_H
#include <scenefx/types/wlr_scene.h>
#include <wayland-server-core.h>
#include <wayland-util.h>
#include <wlr/config.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/render/wlr_texture.h>
#include "sway/tree/container.h"
#include "sway/tree/node.h"
#include "list.h"
extern struct sway_root *root;
struct sway_root {
struct sway_node node;
struct wlr_output_layout *output_layout;
// scene node layout:
// - root
// - staging
// - layer shell stuff
// - tiling
// - floating
// - fullscreen stuff
// - seat stuff
// - ext_session_lock
struct wlr_scene *root_scene;
// since wlr_scene nodes can't be orphaned and must always
// have a parent, use this staging scene_tree so that a
// node always have a valid parent. Nothing in this
// staging node will be visible.
struct wlr_scene_tree *staging;
// tree containing all layers the compositor will render. Cursor handling
// will end up iterating this tree.
struct wlr_scene_tree *layer_tree;
struct {
struct wlr_scene_tree *shell_background;
struct wlr_scene_tree *shell_bottom;
struct wlr_scene_tree *blur_tree;
struct wlr_scene_tree *tiling;
struct wlr_scene_tree *floating;
struct wlr_scene_tree *shell_top;
struct wlr_scene_tree *fullscreen;
struct wlr_scene_tree *fullscreen_global;
#if WLR_HAS_XWAYLAND
struct wlr_scene_tree *unmanaged;
#endif
struct wlr_scene_tree *shell_overlay;
struct wlr_scene_tree *popup;
struct wlr_scene_tree *seat;
struct wlr_scene_tree *session_lock;
} layers;
// Includes disabled outputs
struct wl_list all_outputs; // sway_output::link
double x, y;
double width, height;
list_t *outputs; // struct sway_output
list_t *non_desktop_outputs; // struct sway_output_non_desktop
list_t *scratchpad; // struct sway_container
// For when there's no connected outputs
struct sway_output *fallback_output;
struct sway_container *fullscreen_global;
struct {
struct wl_signal new_node;
} events;
};
struct sway_root *root_create(struct wl_display *display);
void root_destroy(struct sway_root *root);
/**
* Move a container to the scratchpad.
* If a workspace is passed, the container is assumed to have been in
* the scratchpad before and is shown on the workspace.
* The ws parameter can safely be NULL.
*/
void root_scratchpad_add_container(struct sway_container *con,
struct sway_workspace *ws);
/**
* Remove a container from the scratchpad.
*/
void root_scratchpad_remove_container(struct sway_container *con);
/**
* Show a single scratchpad container.
*/
void root_scratchpad_show(struct sway_container *con);
/**
* Hide a single scratchpad container.
*/
void root_scratchpad_hide(struct sway_container *con);
void root_for_each_workspace(void (*f)(struct sway_workspace *ws, void *data),
void *data);
void root_for_each_container(void (*f)(struct sway_container *con, void *data),
void *data);
struct sway_output *root_find_output(
bool (*test)(struct sway_output *output, void *data), void *data);
struct sway_workspace *root_find_workspace(
bool (*test)(struct sway_workspace *ws, void *data), void *data);
struct sway_container *root_find_container(
bool (*test)(struct sway_container *con, void *data), void *data);
void root_get_box(struct sway_root *root, struct wlr_box *box);
#endif

374
include/sway/tree/view.h Normal file
View file

@ -0,0 +1,374 @@
#ifndef _SWAY_VIEW_H
#define _SWAY_VIEW_H
#include <scenefx/types/wlr_scene.h>
#include <wayland-server-core.h>
#include <wlr/config.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_tearing_control_v1.h>
#include "sway/config.h"
#if WLR_HAS_XWAYLAND
#include <wlr/xwayland.h>
#endif
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
struct sway_container;
struct sway_xdg_decoration;
enum sway_view_type {
SWAY_VIEW_XDG_SHELL,
#if WLR_HAS_XWAYLAND
SWAY_VIEW_XWAYLAND,
#endif
};
enum sway_view_prop {
VIEW_PROP_TITLE,
VIEW_PROP_APP_ID,
VIEW_PROP_TAG,
VIEW_PROP_CLASS,
VIEW_PROP_INSTANCE,
VIEW_PROP_WINDOW_TYPE,
VIEW_PROP_WINDOW_ROLE,
#if WLR_HAS_XWAYLAND
VIEW_PROP_X11_WINDOW_ID,
VIEW_PROP_X11_PARENT_ID,
#endif
};
enum sway_view_tearing_mode {
TEARING_OVERRIDE_FALSE,
TEARING_OVERRIDE_TRUE,
TEARING_WINDOW_HINT,
};
struct sway_view_impl {
void (*get_constraints)(struct sway_view *view, double *min_width,
double *max_width, double *min_height, double *max_height);
const char *(*get_string_prop)(struct sway_view *view,
enum sway_view_prop prop);
uint32_t (*get_int_prop)(struct sway_view *view, enum sway_view_prop prop);
uint32_t (*configure)(struct sway_view *view, double lx, double ly,
int width, int height);
void (*set_activated)(struct sway_view *view, bool activated);
void (*set_tiled)(struct sway_view *view, bool tiled);
void (*set_fullscreen)(struct sway_view *view, bool fullscreen);
void (*set_resizing)(struct sway_view *view, bool resizing);
bool (*wants_floating)(struct sway_view *view);
bool (*is_transient_for)(struct sway_view *child,
struct sway_view *ancestor);
void (*close)(struct sway_view *view);
void (*close_popups)(struct sway_view *view);
void (*destroy)(struct sway_view *view);
};
struct sway_view {
enum sway_view_type type;
const struct sway_view_impl *impl;
struct wlr_scene_tree *scene_tree;
struct wlr_scene_tree *content_tree;
struct wlr_scene_tree *saved_surface_tree;
struct wlr_scene_buffer *output_handler;
struct wl_listener outputs_update;
struct wlr_scene *image_capture_scene;
struct wlr_ext_image_capture_source_v1 *image_capture_source;
struct sway_container *container; // NULL if unmapped and transactions finished
struct wlr_surface *surface; // NULL for unmapped views
struct sway_xdg_decoration *xdg_decoration;
pid_t pid;
struct launcher_ctx *ctx;
// The size the view would want to be if it weren't tiled.
// Used when changing a view from tiled to floating.
int natural_width, natural_height;
bool using_csd;
struct timespec urgent;
bool allow_request_urgent;
struct wl_event_source *urgent_timer;
// The geometry for whatever the client is committing, regardless of
// transaction state. Updated on every commit.
struct wlr_box geometry;
struct wlr_ext_foreign_toplevel_handle_v1 *ext_foreign_toplevel;
struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel;
struct wl_listener foreign_activate_request;
struct wl_listener foreign_fullscreen_request;
struct wl_listener foreign_close_request;
struct wl_listener foreign_minimize;
struct wl_listener foreign_destroy;
bool destroying;
list_t *executed_criteria; // struct criteria *
union {
struct wlr_xdg_toplevel *wlr_xdg_toplevel;
#if WLR_HAS_XWAYLAND
struct wlr_xwayland_surface *wlr_xwayland_surface;
#endif
};
struct {
struct wl_signal unmap;
} events;
int max_render_time; // In milliseconds
enum seat_config_shortcuts_inhibit shortcuts_inhibit;
enum sway_view_tearing_mode tearing_mode;
enum wp_tearing_control_v1_presentation_hint tearing_hint;
};
struct sway_xdg_shell_view {
struct sway_view view;
struct wlr_scene_tree *image_capture_tree;
char *tag;
struct wl_listener commit;
struct wl_listener request_move;
struct wl_listener request_resize;
struct wl_listener request_maximize;
struct wl_listener request_minimize;
struct wl_listener request_fullscreen;
struct wl_listener set_title;
struct wl_listener set_app_id;
struct wl_listener new_popup;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
};
#if WLR_HAS_XWAYLAND
struct sway_xwayland_view {
struct sway_view view;
struct wlr_scene_tree *surface_tree;
struct wlr_scene_surface *image_capture_scene_surface;
struct wl_listener commit;
struct wl_listener request_move;
struct wl_listener request_resize;
struct wl_listener request_maximize;
struct wl_listener request_minimize;
struct wl_listener request_configure;
struct wl_listener request_fullscreen;
struct wl_listener request_activate;
struct wl_listener set_title;
struct wl_listener set_class;
struct wl_listener set_role;
struct wl_listener set_startup_id;
struct wl_listener set_window_type;
struct wl_listener set_hints;
struct wl_listener set_decorations;
struct wl_listener associate;
struct wl_listener dissociate;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
struct wl_listener override_redirect;
struct wl_listener surface_tree_destroy;
};
struct sway_xwayland_unmanaged {
struct wlr_xwayland_surface *wlr_xwayland_surface;
struct wlr_scene_surface *surface_scene;
struct wl_listener request_activate;
struct wl_listener request_configure;
struct wl_listener request_fullscreen;
struct wl_listener set_geometry;
struct wl_listener associate;
struct wl_listener dissociate;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
struct wl_listener override_redirect;
};
#endif
struct sway_popup_desc {
struct wlr_scene_node *relative;
struct sway_view *view;
};
struct sway_xdg_popup {
struct sway_view *view;
struct wlr_xdg_popup *wlr_xdg_popup;
struct wlr_scene_tree *scene_tree;
struct wlr_scene_tree *xdg_surface_tree;
struct wlr_scene_tree *image_capture_tree;
struct sway_popup_desc desc;
struct wl_listener surface_commit;
struct wl_listener new_popup;
struct wl_listener reposition;
struct wl_listener destroy;
};
const char *view_get_title(struct sway_view *view);
const char *view_get_app_id(struct sway_view *view);
const char *view_get_class(struct sway_view *view);
const char *view_get_instance(struct sway_view *view);
uint32_t view_get_x11_window_id(struct sway_view *view);
uint32_t view_get_x11_parent_id(struct sway_view *view);
const char *view_get_window_role(struct sway_view *view);
uint32_t view_get_window_type(struct sway_view *view);
const char *view_get_sandbox_engine(struct sway_view *view);
const char *view_get_sandbox_app_id(struct sway_view *view);
const char *view_get_sandbox_instance_id(struct sway_view *view);
const char *view_get_tag(struct sway_view *view);
const char *view_get_shell(struct sway_view *view);
void view_get_constraints(struct sway_view *view, double *min_width,
double *max_width, double *min_height, double *max_height);
uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
int height);
bool view_inhibit_idle(struct sway_view *view);
/**
* Whether or not this view's most distant ancestor (possibly itself) is the
* only visible node in its tree. If the view is tiling, there may be floating
* views. If the view is floating, there may be tiling views or views in a
* different floating container.
*/
bool view_ancestor_is_only_visible(struct sway_view *view);
/**
* Configure the view's position and size based on the container's position and
* size, taking borders into consideration.
*/
void view_autoconfigure(struct sway_view *view);
void view_set_activated(struct sway_view *view, bool activated);
/**
* Called when the view requests to be focused.
*/
void view_request_activate(struct sway_view *view, struct sway_seat *seat);
/*
* Called when the view requests urgent state
*/
void view_request_urgent(struct sway_view *view);
/**
* If possible, instructs the client to change their decoration mode.
*/
void view_set_csd_from_server(struct sway_view *view, bool enabled);
/**
* Updates the view's border setting when the client unexpectedly changes their
* decoration mode.
*/
void view_update_csd_from_client(struct sway_view *view, bool enabled);
void view_set_tiled(struct sway_view *view, bool tiled);
void view_close(struct sway_view *view);
void view_close_popups(struct sway_view *view);
// view implementation
bool view_init(struct sway_view *view, enum sway_view_type type,
const struct sway_view_impl *impl);
void view_destroy(struct sway_view *view);
void view_begin_destroy(struct sway_view *view);
/**
* Map a view, ie. make it visible in the tree.
*
* `fullscreen` should be set to true (and optionally `fullscreen_output`
* should be populated) if the view should be made fullscreen immediately.
*
* `decoration` should be set to true if the client prefers CSD. The client's
* preference may be ignored.
*/
void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
bool fullscreen, struct wlr_output *fullscreen_output, bool decoration);
void view_unmap(struct sway_view *view);
void view_update_size(struct sway_view *view);
void view_center_and_clip_surface(struct sway_view *view);
struct sway_view *view_from_wlr_xdg_surface(
struct wlr_xdg_surface *xdg_surface);
#if WLR_HAS_XWAYLAND
struct sway_view *view_from_wlr_xwayland_surface(
struct wlr_xwayland_surface *xsurface);
#endif
struct sway_view *view_from_wlr_surface(struct wlr_surface *surface);
void view_update_app_id(struct sway_view *view);
/**
* Re-read the view's title property and update any relevant title bars.
* The force argument makes it recreate the title bars even if the title hasn't
* changed.
*/
void view_update_title(struct sway_view *view, bool force);
/**
* Run any criteria that match the view and haven't been run on this view
* before.
*/
void view_execute_criteria(struct sway_view *view);
/**
* Returns true if there's a possibility the view may be rendered on screen.
* Intended for damage tracking.
*/
bool view_is_visible(struct sway_view *view);
void view_set_urgent(struct sway_view *view, bool enable);
bool view_is_urgent(struct sway_view *view);
void view_remove_saved_buffer(struct sway_view *view);
void view_save_buffer(struct sway_view *view);
bool view_is_transient_for(struct sway_view *child, struct sway_view *ancestor);
void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx);
void view_send_frame_done(struct sway_view *view);
bool view_can_tear(struct sway_view *view);
void xdg_toplevel_tag_manager_v1_handle_set_tag(struct wl_listener *listener, void *data);
#endif

View file

@ -0,0 +1,176 @@
#ifndef _SWAY_WORKSPACE_H
#define _SWAY_WORKSPACE_H
#include <scenefx/types/wlr_scene.h>
#include <stdbool.h>
#include <wlr/types/wlr_ext_workspace_v1.h>
#include "sway/animation_manager.h"
#include "sway/config.h"
#include "sway/tree/container.h"
#include "sway/tree/node.h"
struct sway_view;
struct sway_workspace_state {
struct sway_container *fullscreen;
double x, y;
int width, height;
enum sway_container_layout layout;
struct sway_output *output;
list_t *floating;
list_t *tiling;
struct sway_container *focused_inactive_child;
bool focused;
};
struct sway_workspace {
struct sway_node node;
struct {
struct wlr_scene_tree *tiling;
struct wlr_scene_tree *fullscreen;
} layers;
struct sway_container *fullscreen;
char *name;
char *representation;
double x, y;
int width, height;
enum sway_container_layout layout;
enum sway_container_layout prev_split_layout;
struct side_gaps current_gaps;
int gaps_inner;
struct side_gaps gaps_outer;
struct sway_output *output; // NULL if no outputs are connected
list_t *floating; // struct sway_container
list_t *tiling; // struct sway_container
list_t *output_priority;
bool urgent;
struct sway_workspace_state current;
struct wlr_ext_workspace_handle_v1 *ext_workspace; // Always set.
struct {
struct animation animation;
float from_alpha;
float to_alpha;
} animation_state;
};
struct workspace_config *workspace_find_config(const char *ws_name);
struct sway_output *workspace_get_initial_output(const char *name);
struct sway_workspace *workspace_create(struct sway_output *output,
const char *name);
void workspace_destroy(struct sway_workspace *workspace);
void workspace_begin_destroy(struct sway_workspace *workspace);
void workspace_consider_destroy(struct sway_workspace *ws);
char *workspace_next_name(const char *output_name);
struct sway_workspace *workspace_auto_back_and_forth(
struct sway_workspace *workspace);
bool workspace_switch(struct sway_workspace *workspace);
struct sway_workspace *workspace_by_number(const char* name);
struct sway_workspace *workspace_by_name(const char*);
struct sway_workspace *workspace_output_next(struct sway_workspace *current);
struct sway_workspace *workspace_next(struct sway_workspace *current);
struct sway_workspace *workspace_output_prev(struct sway_workspace *current);
struct sway_workspace *workspace_prev(struct sway_workspace *current);
bool workspace_is_visible(struct sway_workspace *ws);
bool workspace_is_empty(struct sway_workspace *ws);
void workspace_output_raise_priority(struct sway_workspace *workspace,
struct sway_output *old_output, struct sway_output *new_output);
void workspace_output_add_priority(struct sway_workspace *workspace,
struct sway_output *output);
struct sway_output *workspace_output_get_highest_available(
struct sway_workspace *ws);
void workspace_detect_urgent(struct sway_workspace *workspace);
void workspace_for_each_container(struct sway_workspace *ws,
void (*f)(struct sway_container *con, void *data), void *data);
struct sway_container *workspace_find_container(struct sway_workspace *ws,
bool (*test)(struct sway_container *con, void *data), void *data);
/**
* Wrap the workspace's tiling children in a new container.
* The new container will be the only direct tiling child of the workspace.
* The new container is returned.
*/
struct sway_container *workspace_wrap_children(struct sway_workspace *ws);
void workspace_unwrap_children(struct sway_workspace *ws,
struct sway_container *wrap);
void workspace_detach(struct sway_workspace *workspace);
struct sway_container *workspace_add_tiling(struct sway_workspace *workspace,
struct sway_container *con);
void workspace_add_floating(struct sway_workspace *workspace,
struct sway_container *con);
/**
* Adds a tiling container to the workspace without considering
* the workspace_layout, so the con will not be split.
*/
void workspace_insert_tiling_direct(struct sway_workspace *workspace,
struct sway_container *con, int index);
struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace,
struct sway_container *con, int index);
void workspace_remove_gaps(struct sway_workspace *ws);
void workspace_add_gaps(struct sway_workspace *ws);
struct sway_container *workspace_split(struct sway_workspace *workspace,
enum sway_container_layout layout);
void workspace_update_representation(struct sway_workspace *ws);
void workspace_get_box(struct sway_workspace *workspace, struct wlr_box *box);
size_t workspace_num_tiling_views(struct sway_workspace *ws);
size_t workspace_num_sticky_containers(struct sway_workspace *ws);
/**
* workspace_squash is container_flatten in the reverse
* direction. Instead of eliminating redundant splits that are
* parents of the target container, it eliminates pairs of
* redundant H/V splits that are children of the workspace.
*/
void workspace_squash(struct sway_workspace *workspace);
void workspace_move_to_output(struct sway_workspace *workspace,
struct sway_output *output);
bool sway_ext_workspace_init(void);
void sway_ext_workspace_output_enable(struct sway_output *output);
void sway_ext_workspace_output_disable(struct sway_output *output);
#endif

View file

@ -0,0 +1,21 @@
#ifndef _SWAY_XDG_DECORATION_H
#define _SWAY_XDG_DECORATION_H
#include <wlr/types/wlr_xdg_decoration_v1.h>
struct sway_xdg_decoration {
struct wlr_xdg_toplevel_decoration_v1 *wlr_xdg_decoration;
struct wl_list link;
struct sway_view *view;
struct wl_listener destroy;
struct wl_listener request_mode;
};
struct sway_xdg_decoration *xdg_decoration_from_surface(
struct wlr_surface *surface);
void set_xdg_decoration_mode(struct sway_xdg_decoration *deco);
#endif

31
include/sway/xwayland.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef SWAY_XWAYLAND_H
#define SWAY_XWAYLAND_H
#include <wlr/xwayland.h>
#include <xcb/xproto.h>
enum atom_name {
NET_WM_WINDOW_TYPE_NORMAL,
NET_WM_WINDOW_TYPE_DIALOG,
NET_WM_WINDOW_TYPE_UTILITY,
NET_WM_WINDOW_TYPE_TOOLBAR,
NET_WM_WINDOW_TYPE_SPLASH,
NET_WM_WINDOW_TYPE_MENU,
NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
NET_WM_WINDOW_TYPE_POPUP_MENU,
NET_WM_WINDOW_TYPE_TOOLTIP,
NET_WM_WINDOW_TYPE_NOTIFICATION,
NET_WM_STATE_MODAL,
ATOM_LAST,
};
struct sway_xwayland {
struct wlr_xwayland *wlr_xwayland;
struct wlr_xcursor_manager *xcursor_manager;
xcb_atom_t atoms[ATOM_LAST];
};
void handle_xwayland_ready(struct wl_listener *listener, void *data);
#endif

Some files were not shown because too many files have changed in this diff Show more