diff --git a/.builds/alpine.yml b/.builds/alpine.yml
index dc5e7c11a..abf636ab6 100644
--- a/.builds/alpine.yml
+++ b/.builds/alpine.yml
@@ -6,6 +6,7 @@ packages:
- json-c-dev
- libevdev-dev
- libinput-dev
+ - libseat-dev
- libxcb-dev
- libxkbcommon-dev
- mesa-dev
@@ -16,10 +17,11 @@ packages:
- wayland-dev
- wayland-protocols
- xcb-util-image-dev
- - xorg-server-xwayland
+ - xcb-util-wm-dev
+ - xwayland
sources:
- https://github.com/swaywm/sway
- - https://github.com/swaywm/wlroots
+ - https://gitlab.freedesktop.org/wlroots/wlroots.git
tasks:
- wlroots: |
cd wlroots
@@ -28,7 +30,7 @@ tasks:
sudo ninja -C build install
- setup: |
cd sway
- meson build -Dauto_features=enabled -Dtray=disabled
+ meson build --fatal-meson-warnings -Dauto_features=enabled -Dtray=disabled
- build: |
cd sway
ninja -C build
@@ -36,3 +38,10 @@ tasks:
cd sway
meson configure build -Dxwayland=disabled
ninja -C build
+ - build-static: |
+ cd sway
+ mkdir subprojects
+ ln -s ../../wlroots subprojects/wlroots
+ rm -rf build
+ meson build --fatal-meson-warnings --default-library=static --force-fallback-for=wlroots
+ ninja -C build
diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml
index dfe1900ee..ac4cdb4d6 100644
--- a/.builds/archlinux.yml
+++ b/.builds/archlinux.yml
@@ -3,6 +3,7 @@ packages:
- cairo
- gdk-pixbuf2
- json-c
+ - libegl
- libinput
- libxcb
- libxkbcommon
@@ -12,10 +13,12 @@ packages:
- wayland
- wayland-protocols
- xcb-util-image
- - xorg-server-xwayland
+ - xcb-util-wm
+ - xorg-xwayland
+ - seatd
sources:
- https://github.com/swaywm/sway
- - https://github.com/swaywm/wlroots
+ - https://gitlab.freedesktop.org/wlroots/wlroots.git
tasks:
- wlroots: |
cd wlroots
@@ -24,7 +27,7 @@ tasks:
sudo ninja -C build install
- setup: |
cd sway
- meson build -Dauto_features=enabled
+ meson build --fatal-meson-warnings -Dauto_features=enabled -Dsd-bus-provider=libsystemd
- build: |
cd sway
ninja -C build
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
index 0a1760894..97e7eccc2 100644
--- a/.builds/freebsd.yml
+++ b/.builds/freebsd.yml
@@ -1,5 +1,6 @@
image: freebsd/latest
packages:
+- devel/basu
- devel/json-c
- devel/libevdev
- devel/meson
@@ -18,13 +19,14 @@ packages:
- devel/libudev-devd
- graphics/libdrm
- graphics/mesa-libs
+- sysutils/seatd
- x11/libinput
- x11/libX11
- x11/pixman
- x11/xcb-util-wm
sources:
- https://github.com/swaywm/sway
-- https://github.com/swaywm/wlroots
+- https://gitlab.freedesktop.org/wlroots/wlroots.git
tasks:
- setup: |
cd sway
@@ -32,7 +34,7 @@ tasks:
cd subprojects
ln -s ../../wlroots wlroots
cd ..
- meson build
+ meson build --fatal-meson-warnings -Dtray=enabled -Dsd-bus-provider=basu
- build: |
cd sway
ninja -C build
diff --git a/.clang-format b/.clang-format
index 5818da3ca..24ea869df 100644
--- a/.clang-format
+++ b/.clang-format
@@ -8,9 +8,11 @@ IndentCaseLabels: false
SortIncludes: false
ColumnLimit: 80
AlignAfterOpenBracket: DontAlign
-BinPackParameters: false
-BinPackArguments: false
+BinPackParameters: true
+BinPackArguments: true
ContinuationIndentWidth: 8
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortLoopsOnASingleLine: true
ReflowComments: false
+AllowAllArgumentsOnNextLine: false
+AlignOperands: DontAlign
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index de7a8ac4e..000000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-# These are supported funding model platforms
-
-github: ddevault
-patreon: sircmpwn
-custom: https://drewdevault.com/donate
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 4e4f6a778..eba606e65 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -6,9 +6,10 @@ labels: 'bug'
---
### Please read the following before submitting:
-- Please do NOT submit bug reports for questions. Ask questions on IRC at #sway on irc.freenode.net.
+- Please do NOT submit bug reports for questions. Ask questions on IRC at #sway on Libera Chat.
- Proprietary graphics drivers, including nvidia, are not supported. Please use the open source equivalents, such as nouveau, if you would like to use Sway.
-- Problems with the Wayland version of Firefox are likely to be Firefox bugs. Start by submitting your issue to the Firefox Bugzilla and come back here only after they confirm otherwise.
+- 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:
- **Sway Version:**
@@ -17,6 +18,7 @@ labels: 'bug'
- **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.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index f09cdf5bb..0092609b5 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,5 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Questions
- url: "http://webchat.freenode.net/?channels=sway&uio=d4"
- about: "Please ask questions on IRC in #sway on irc.freenode.net"
+ url: "https://libera.chat"
+ about: "Please ask questions on IRC in #sway on Libera Chat"
diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md
index 3ed45b01d..9be069a7a 100644
--- a/.github/ISSUE_TEMPLATE/enhancement.md
+++ b/.github/ISSUE_TEMPLATE/enhancement.md
@@ -6,7 +6,7 @@ labels: 'enhancement'
---
### Please read the following before submitting:
-- We are not accepting any new window management features unless they get implemented by i3. Please consider searching for or opening an i3 feature request.
+- We are not accepting any new window management features unless they get implemented by i3.
### Please fill out the following:
- **Description:**
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 031f51f53..4f043f7a7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,13 +1,21 @@
# Contributing to sway
Contributing just involves sending a pull request. You will probably be more
-successful with your contribution if you visit
-[#sway-devel](https://webchat.freenode.net/?channels=sway-devel) on
-irc.freenode.net upfront and discuss your plans.
+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
diff --git a/README.de.md b/README.de.md
index 1abf2f4a6..01b5e9ad2 100644
--- a/README.de.md
+++ b/README.de.md
@@ -1,14 +1,12 @@
# Sway
-Sway ist ein [i3](https://i3wm.org/)-kompatibler [Wayland](http://wayland.freedesktop.org/)-Compositor. Lies die [FAQ](https://github.com/swaywm/sway/wiki). Tritt dem [IRC Channel](http://webchat.freenode.net/?channels=sway&uio=d4) bei (#sway on irc.freenode.net; Englisch).
-
-Falls du die Entwicklung von Sway unterstützen möchtest, kannst du das auf [SirCmpwn's Patreon Seite](https://patreon.com/sircmpwn) machen.
+Sway ist ein [i3](https://i3wm.org/)-kompatibler [Wayland](http://wayland.freedesktop.org/)-Compositor. Lies die [FAQ](https://github.com/swaywm/sway/wiki). Tritt dem [IRC Channel](https://web.libera.chat/gamja/?channels=#sway) bei (#sway on irc.libera.chat; Englisch).
## Signaturen
-Jedes Release wird mit dem PGP-Schlüssel [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) signiert und auf GitHub veröffentlicht.
+Jedes Release wird mit dem PGP-Schlüssel [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) signiert und auf GitHub veröffentlicht.
## Installation
### Mit der Paketverwaltung
-Sway kann in vielen Distributionen direkt durch die Paketverwaltung installiert werden. Das Paket sollte "sway" heißen. Falls es kein solches Paket gibt, kannst du im [Wiki](https://github.com/swaywm/sway/wiki/Unsupported-packages) (Englisch) nach mehr Informationen bezüglich deiner Distribution suchen.
+Sway kann in vielen Distributionen direkt durch die Paketverwaltung installiert werden. Das Paket sollte "sway" heißen. Falls es kein solches Paket gibt, kannst du im [Wiki](https://github.com/swaywm/sway/wiki/Unsupported-packages) (englisch) nach mehr Informationen bezüglich deiner Distribution suchen.
Falls du sway für deine eigene Distribution als Paket bereitstellen möchtest, solltest du die Entwickler per IRC oder E-Mail (sir@cmpwn.com) kontaktieren.
@@ -17,7 +15,7 @@ Falls du sway für deine eigene Distribution als Paket bereitstellen möchtest,
sway benötigt die folgenden Pakete:
* meson\*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols\*
* pcre
@@ -30,7 +28,7 @@ sway benötigt die folgenden Pakete:
_\*Werden nur während des Kompilierens benötigt_
-Führe die folgenden Befehle aus
+Führe die folgenden Befehle aus:
meson build
ninja -C build
@@ -44,8 +42,8 @@ Sway läuft nur in der Startphase mit Root-Rechten.
## Konfiguration
-Falls du von i3 migrierst, kannst du deine Konfigurationsdatei nach `~/.config/sway/config` kopieren, und die Einstellungen sollten ohne Weiteres funktionieren. Ansonsten kannst du die Beispielkonfiguration, die normalerweise in `/etc/sway/config` liegt, nach `~/.config/sway/config` kopieren. Die Dokumentation zur Konfigurationsdatei findest du in `man 5 sway`.
+Falls du von i3 migrierst, kannst du deine Konfigurationsdatei nach `~/.config/sway/config` kopieren und die Einstellungen sollten ohne Weiteres funktionieren. Ansonsten kannst du die Beispielkonfiguration, die normalerweise in `/etc/sway/config` liegt, nach `~/.config/sway/config` kopieren. Die Dokumentation zur Konfigurationsdatei findest du in `man 5 sway`.
-## Sway Starten
+## Sway starten
Sway kann einfach mit dem Befehl `sway` vom TTY gestartet werden.
-Display-Manager werden nicht offiziell unterstützt. Es gibt aber durchaus einige, die mit Sway funktionieren. (z.B. gdm)
+Display-Manager werden nicht offiziell unterstützt. Es gibt aber durchaus einige, die mit Sway funktionieren (z.B. gdm).
diff --git a/README.dk.md b/README.dk.md
index c588c9da2..f712e96b9 100644
--- a/README.dk.md
+++ b/README.dk.md
@@ -1,43 +1,43 @@
# Sway
-Sway er en [i3](https://i3wm.org/)-kompatibel [Wayland](http://wayland.freedesktop.org/) compositor.
-Læs [Ofte stillede spørgsmål](https://github.com/swaywm/sway/wiki).
-Deltag på [IRC kanalen](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway på irc.freenode.net).
-
-Hvis du har lyst til at støtte sway udviklingen, venligst send bidrag på [Sir Cmpwn's Patreon side](https://patreon.com/sircmpwn).
+Sway er en [i3]-kompatibel [Wayland] compositor. Læs [Ofte stillede spørgsmål].
+Deltag på [IRC kanalen][IRC kanal] \(#sway på irc.libera.chat).
## Udgivelses Signaturer
-Udgivelser er signeret med [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
-og publiseret på [GitHub](https://github.com/swaywm/sway/releases).
+Udgivelser er signeret med [E88F5E48] og publiceret [på GitHub][GitHub
+releases].
## Installation
-### Fra Pakker
+### Fra pakker
-Sway er tilgængelig i mange distributioner. Prøv at installere pakken "svay". Hvis den ikke er tilgængelig, så tjek [denne wiki-side](https://github.com/swaywm/sway/wiki/Unsupported-packages)
-for information om installation til din(e) distribution(er).
+Sway er tilgængelig i mange distributioner. Prøv at installere "sway" pakken
+fra din.
-Hvis du er interesseret i at lave en Sway pakke til din distribution, burde du besøge IRC
-kanalen eller sende en e-mail til sir@cmpwn.com for rådgivning.
+Hvis du er interesseret i at pakke Sway til din distribution, kan du tage forbi
+IRC kanalen eller sende en email til sir@cmpwn.com for rådgivning.
### Kompilering fra kildekode
-Installation afhænger af følgende programmer:
+Se [denne wiki-side][Opsætning til udvikling] hvis du vil bygge HEAD af sway og
+wlroots til test eller udvikling.
+
+Installationsafhængigheder:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots]
* wayland
* wayland-protocols \*
* pcre
* json-c
* pango
* cairo
-* gdk-pixbuf2 (valgfrit tillæg: system tray)
-* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (valgfrit tillæg: man pages) \*
+* gdk-pixbuf2 (valgfrit: system tray)
+* [scdoc] (valgfrit: man pages) \*
* git \*
-_\*Kompiler krav_
+_\*Kompileringsafhængighed_
Kør følgende kommandoer:
@@ -45,21 +45,30 @@ Kør følgende kommandoer:
ninja -C build
sudo ninja -C build install
-På systemer uden 'logind', behøver du at sætte ejerens bruger-id for Sways eksekverbare filer - såkaldt SUID (Set owner User ID):
+På systemer uden logind eller seatd skal du sætte SUID bit på sway filen:
sudo chmod a+s /usr/local/bin/sway
-Sway vil frasige sig 'root' tilladelser kort efter opstart
+Sway dropper 'root' tilladelser kort efter opstart.
## Konfiguration
-Hvis du allerede bruger i3, bør du kopiere din i3-konfiguration til `~/.config/sway/config` og
-det vil bare fungerer. Ellers skal du kopiere eksempel konfigurations filen til
-`~/.config/sway/config`. Den er normalt placeret i `/etc/sway/config`.
-Kør `man 5 sway` for at få oplysninger om konfigurationen.
+Hvis du allerede bruger i3 kan du bare kopiere din i3 konfiguration til
+`~/.config/sway/config`. Ellers skal du kopiere eksempelkonfigurationsfilen til
+`~/.config/sway/config`. Den er normalt placeret i `/etc/sway/config`. Kør
+`man 5 sway` for at få oplysninger om konfigurationen.
-## Kører
+## Eksekvering
-Kør `sway` fra en TTY. Nogle display managers fungerer muligvis, men understøttes ikke af
-Sway (gdm er kendt for at fungere temmelig godt).
+Kør `sway` fra en TTY. Nogle display managers kan fungere, men Sway yder ikke
+support til dem (gdm er kendt for at fungere temmelig godt).
+[i3]: https://i3wm.org/
+[Wayland]: http://wayland.freedesktop.org/
+[Ofte stillede spørgsmål]: https://github.com/swaywm/sway/wiki
+[IRC kanal]: https://web.libera.chat/gamja/?channels=#sway
+[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
+[GitHub releases]: https://github.com/swaywm/sway/releases
+[Opsætning til udvikling]: https://github.com/swaywm/sway/wiki/Development-Setup
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
+[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
diff --git a/README.es.md b/README.es.md
index 2f2a1b069..7af7d90b8 100644
--- a/README.es.md
+++ b/README.es.md
@@ -1,14 +1,12 @@
# sway
sway es un compositor de [Wayland](http://wayland.freedesktop.org/) compatible con [i3](https://i3wm.org/).
-Lea el [FAQ](https://github.com/swaywm/sway/wiki). Únase al [canal de IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on
-irc.freenode.net).
-
-Si quiere apoyar el desarrollo de sway, por favor, contribuya en [la página de Patreon de SirCmpwn](https://patreon.com/sircmpwn).
+Lea el [FAQ](https://github.com/swaywm/sway/wiki). Únase al [canal de IRC](https://web.libera.chat/gamja/?channels=#sway) (#sway on
+irc.libera.chat).
## Firmas de las versiones
-Las distintas versiones están firmadas con [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
+Las distintas versiones están firmadas con [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48)
y publicadas [en GitHub](https://github.com/swaywm/sway/releases).
## Instalación
@@ -27,7 +25,7 @@ escriba un email a sir@cmpwn.com
Instale las dependencias:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.fr.md b/README.fr.md
index 7068b3be0..359a30f95 100644
--- a/README.fr.md
+++ b/README.fr.md
@@ -1,51 +1,49 @@
# sway
-Sway est un compositeur [Wayland](http://wayland.freedesktop.org/) compatible
-avec [i3](https://i3wm.org/), **en cours de développement**. Lisez la
-[FAQ](https://github.com/swaywm/sway/wiki). Rejoignez le [canal
-IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway sur
-irc.freenode.net).
-
-Si vous souhaitez soutenir le développement de Sway, vous pouvez contribuer à [la page
-Patreon de SirCmpwn](https://patreon.com/sircmpwn).
+Sway est un compositeur [Wayland] compatible avec [i3]. Lisez la
+[FAQ]. Rejoignez le [canal IRC] (#sway sur irc.libera.chat).
## Aide en français
-[abdelq](//github.com/abdelq) fournit du support en français sur IRC et Github, dans le fuseau horaire UTC-4 (EST).
+[abdelq] fournit du support en français sur IRC et Github, dans le fuseau
+horaire UTC-4 (EST).
## Signatures de nouvelles versions
-Les nouvelles versions sont signées avec [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
-et publiées [sur GitHub](https://github.com/swaywm/sway/releases).
+Les nouvelles versions sont signées avec [E88F5E48] et publiées
+[sur GitHub][versions GitHub].
## Installation
### À partir de paquets
-Sway est disponible sur plusieurs distributions. Essayez d'installer le paquet "sway" pour
-la vôtre. Si ce n'est pas disponible, consultez [cette page wiki](https://github.com/swaywm/sway/wiki/Unsupported-packages)
-pour de l'information sur l'installation pour vos distributions.
+Sway est disponible sur beaucoup de distributions. Essayez d'installer le
+paquet "sway" pour la vôtre.
-Si vous êtes intéressé à maintenir Sway pour votre distribution, passez par le canal
-IRC ou envoyez un e-mail à sir@cmpwn.com (en anglais seulement) pour des conseils.
+Si vous êtes intéressé à maintenir Sway pour votre distribution, passez sur le
+canal IRC ou envoyez un e-mail à sir@cmpwn.com (en anglais seulement) pour des
+conseils.
-### Compilation depuis la source
+### Compilation depuis les sources
+
+Consultez [cette page wiki][Configuration de développement] si vous souhaitez
+compiler la révision HEAD de sway et wlroots pour tester ou développer.
Installez les dépendances :
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots]
* wayland
* wayland-protocols \*
* pcre
* json-c
* pango
* cairo
-* gdk-pixbuf2 (optionnel: system tray)
-* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (optionnel: requis pour les pages man) \*
-* git \*
+* gdk-pixbuf2 (optionnel : system tray)
+* [scdoc] (optionnel : requis pour les pages man) \*
+* git (optionnel : information de version) \*
-_\*Requis uniquement pour la compilation_
+_\* Requis uniquement pour la compilation_
Exécutez ces commandes :
@@ -61,12 +59,25 @@ Sway se débarassera des permissions *root* peu de temps après le démarrage.
## Configuration
-Si vous utilisez déjà i3, copiez votre configuration i3 à `~/.config/sway/config` et
-cela va fonctionner. Sinon, copiez l'exemple de fichier de configuration à
-`~/.config/sway/config`. Il se trouve généralement dans `/etc/sway/config`.
-Exécutez `man 5 sway` pour l'information sur la configuration.
+Si vous utilisez déjà i3, copiez votre configuration i3 vers
+`~/.config/sway/config` et sway fonctionnera directement. Sinon, copiez
+l'exemple de fichier de configuration vers `~/.config/sway/config`. Il se
+trouve généralement dans `/etc/sway/config`. Exécutez `man 5 sway` pour lire la
+documentation pour la configuration de sway.
## Exécution
-Exécutez `sway` à partir d'un TTY. Certains gestionnaires d'affichage peuvent fonctionner,
-mais ne sont pas supportés par Sway (gdm est réputé pour assez bien fonctionner).
+Exécutez `sway` à partir d'un TTY. Certains gestionnaires d'affichage peuvent
+fonctionner, mais ne sont pas supportés par Sway (gdm est réputé pour assez
+bien fonctionner).
+
+[Wayland]: http://wayland.freedesktop.org/
+[i3]: https://i3wm.org/
+[FAQ]: https://github.com/swaywm/sway/wiki
+[canal IRC]: https://web.libera.chat/gamja/?channels=#sway
+[abdelq]: https://github.com/abdelq
+[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
+[versions GitHub]: https://github.com/swaywm/sway/releases
+[Configuration de développement]: https://github.com/swaywm/sway/wiki/Development-Setup
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
+[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
diff --git a/README.gr.md b/README.gr.md
new file mode 100644
index 000000000..4c30e29de
--- /dev/null
+++ b/README.gr.md
@@ -0,0 +1,73 @@
+# Sway
+
+Το sway ένα [i3]-συμβατό [Wayland] compositor. Διαβάστε το [FAQ]. Μπείτε στο
+[IRC channel] \(#sway on irc.libera.chat).
+
+## Υπογραφές δημοσιεύσεων
+
+Οι εκδόσεις είναι υπογεραμμένες με [E88F5E48] και δημοσιευμένες [στο GitHub][GitHub releases].
+
+## Εγκατάσταση
+
+### Από πακέτα
+
+Το Sway είναι διαθέσιμο σε πολλά distributions. Δοκιμάστε εγκαταστώντας το "sway" package για
+το δικό σας.
+
+Εάν ενδιαφέρεστε για packaging του sway για το distribution σας, να πάτε στο IRC
+channel ή στείλτε ένα email στο sir@cmpwn.com για συμβουλές.
+
+### Compiling από πηγή
+
+Τσεκάρετε [αυτό το wiki page][Development setup] εάμα θέλετε να κάνετε build το HEAD του
+sway και wlroots γιά τεστάρισμα ή development.
+
+Εγκατάσταση των dependencies:
+
+* meson \*
+* [wlroots]
+* wayland
+* wayland-protocols \*
+* pcre
+* json-c
+* pango
+* cairo
+* gdk-pixbuf2 (προαιρετικό: system tray)
+* [scdoc] (προαιρετικό: man pages) \*
+* git (προαιρετικό: πληροφορίες εκδώσεων) \*
+
+_\*Compile-time dep_
+
+Τρέξτε αυτά τα commands:
+
+ meson build/
+ ninja -C build/
+ sudo ninja -C build/ install
+
+Σε συστήματα χωρίς logind ή seatd, πρέπει να κάνετε suid το sway binary:
+
+ sudo chmod a+s /usr/local/bin/sway
+
+Το Sway θα κάνει drop root δικαιώματα λίγο μετά την εκκίνηση.
+
+## Configuration
+
+Εάν ήδη χρησιμοποιήτε το i3, αντιγράψτε το i3 config σας στο `~/.config/sway/config` και
+θα δουλέψει out of the box. Αλλιώς, αντιγράψτε το sample configuration αρχείο στο
+`~/.config/sway/config`. Το οποίο συνήθως βρίσκεται στο `/etc/sway/config`.
+Κάντε run `man 5 sway` για πληροφορίες τού configuration.
+
+## Τρέχοντας
+
+Τρέξτε `sway` από ένα TTY. Μερίκα display managers μπορεί να δουλέψουν αλλά δέν είναι συμβατά με
+το sway (το gdm γνωρίζεται να δουλέβει σχετικά καλά).
+
+[i3]: https://i3wm.org/
+[Wayland]: http://wayland.freedesktop.org/
+[FAQ]: https://github.com/swaywm/sway/wiki
+[IRC channel]: https://web.libera.chat/gamja/?channels=#sway
+[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
+[GitHub releases]: https://github.com/swaywm/sway/releases
+[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
+[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
\ No newline at end of file
diff --git a/README.hu.md b/README.hu.md
new file mode 100644
index 000000000..4e006f252
--- /dev/null
+++ b/README.hu.md
@@ -0,0 +1,77 @@
+# sway
+
+A Sway egy [i3]-kompatibilis [Wayland] kompozitor. Olvasd el a [Gyarkan Ismételt Kérdéseket][FAQ]. Csatlakozz az [IRC csatornához][IRC channel] \(`#sway` az `irc.libera.chat`-en).
+
+## Csomag aláírások
+
+A kiadott csomagok az [E88F5E48] kulccsal vannak aláírva és [GitHub-on][GitHub releases] publikálva.
+
+## Telepítés
+
+### Csomagból
+
+A Sway sok disztribúció csomagkezelőjéből elérhető, próbáld meg a "sway"
+csomagot telepíteni az általad használt eszközzel.
+
+Ha szeretnél csomagot készíteni a saját disztribúciódhoz, ugorj be az IRC
+csatornára, vagy küldj levelet a sir@cmpwn.com címre tanácsokért.
+
+### Fordítás forráskódból
+
+Olvasd el [ezt a wiki oldalt][Development setup], ha szeretnéd tesztelési vagy
+fejlesztési célokból lefordítani az aktuális (HEAD) állapotát a `sway`-nek és a
+`wlroots`-nak.
+
+Telepítsd a függőségeket:
+
+* meson \*
+* [wlroots]
+* wayland
+* wayland-protocols \*
+* pcre
+* json-c
+* pango
+* cairo
+* gdk-pixbuf2 (opcionális: system tray)
+* [scdoc] (opcionális: man pages) \*
+* git (opcionális: version info) \*
+
+_\*Fordításidejű függőség_
+
+Futtasd ezeket a parancsokat:
+
+ meson build
+ ninja -C build
+ sudo ninja -C build install
+
+Ha `logind` nélküli rendszert használsz, akkor be kell állítanod a `suid` bitet
+a futtaható állományon:
+
+ sudo chmod a+s /usr/local/bin/sway
+
+A Sway indulás után nem sokkal el fogja engedni a root jogosultságait.
+
+## Konfiguráció
+
+Ha előzőleg i3-mat használtál, akkor átmásolhatod az i3 beállításaidat a
+`~/.config/sway/config` file-ba és ugyanúgy működni fognak. Egyéb esetben másold
+le kiindulási alapnak a mintát, ami általában az `etc/sway/config` elérési
+útvonalon található.
+Futtasd a `man 5 sway` parancsot további információért a konfigurációval
+kapcsolatban.
+
+## Futtatás
+
+Futtasd a `sway` parancsot egy TTY felületről. Néhány bejelentkezéskezelő
+(display manager) működhet, de alapvetően nem támogatottak a sway által. (A
+gdm-ről ismeretes, hogy egész jól működik.)
+
+[i3]: https://i3wm.org/
+[Wayland]: http://wayland.freedesktop.org/
+[FAQ]: https://github.com/swaywm/sway/wiki
+[IRC channel]: https://web.libera.chat/gamja/?channels=#sway
+[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
+[GitHub releases]: https://github.com/swaywm/sway/releases
+[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
+[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
diff --git a/README.ir.md b/README.ir.md
new file mode 100644
index 000000000..bd0849b68
--- /dev/null
+++ b/README.ir.md
@@ -0,0 +1,70 @@
+
+
+# sway
+
+sway یک کامپوزیتور الهام گرفته از [i3](https://i3wm.org/) بر روی [Wayland](http://wayland.freedesktop.org/) است. [سوالهای متداول](https://github.com/swaywm/sway/wiki) را بخوانید. در [کانال
+IRC](http://web.libera.chat/gamja/?channels=sway&uio=d4) عضو شوید (#sway sur
+irc.libera.chat).
+
+برای حمایت از تیم توسعه sway به [صفحه
+Patreon با نام کاربری SirCmpwn](https://patreon.com/sircmpwn) مراجعه کنید.
+
+## امضای نسخهها
+
+امضای نسخهها با [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) در [GitHub](https://github.com/swaywm/sway/releases) منتشر میشود.
+
+## شیوه نصب
+
+### از بستههای رسمی
+
+sway در بستههای رسمی توزیعهای مختلف وجود دارد. بسته «sway» را نصب کنید. در صورتی که بسته رسمی وجود نداشت، برای آگاهی بیشتر درباره نصب روی توزیعتان به این [صفحه راهنما](https://github.com/swaywm/sway/wiki/Unsupported-packages) مراجعه کنید.
+
+اگر به ایجاد بسته sway برای توزیعتان علاقهمند هستید، از کانال IRC استفاده کنید یا به sir@cmpwn.com ایمیل بزنید.
+
+### کامپایل کردن کد
+
+چنانچه میخواهید آخرین نسخه کد sway و wlroots را برای آزمایش یا توسعه بسازید به این [صفحه راهنما](https://github.com/swaywm/sway/wiki/Development-Setup) مراجعه کنید.
+
+بستههای مورد نیاز:
+
+* meson \*
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
+* wayland
+* wayland-protocols \*
+* pcre
+* json-c
+* pango
+* cairo
+* gdk-pixbuf2 (انتخابی: برای system tray)
+* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (انتخابی: برای صفحههای راهنما) \*
+* git (انتخابی: برای اطلاع در خصوص نسخهها) \*
+
+_\*نیازمندیهای زمان کامپایل برنامه_
+
+این فرمانها را اجرا کنید:
+
+
+ meson build
+ ninja -C build
+ sudo ninja -C build install
+
+
+
+روی سیستمهای بدون logind، باید فرمان زیر را برای suid کردن باینری sway اجرا کنید:
+
+
+ sudo chmod a+s /usr/local/bin/sway
+
+
+sway پس از startup مجوزهای دسترسی root را رها میکند.
+
+### شخصی سازی و تنظیمات
+
+اگر در حال حاضر از i3 استفاده میکنید، تنظیمات i3 خودتان را در فایل `~/.config/sway/config` کپی کنید و بدون نیاز به تغییر کار خواهد کرد. در غیر اینصورت، فایل نمونه تنظیمات را استفاده کنید. این فایل عموما در `/etc/sway/config` قرار دارد. برای آگاهی بیشتر `man 5 sway` را اجرا کنید.
+
+## اجرا
+
+در محیط TTY کافیست `sway` را اجرا کنید. ممکن است ابزارهای مدیریت نمایشگری نیز برای این کار وجود داشته باشند اما از طرف sway پشتیبانی نمیشوند (gdm عملکرد خوبی در این زمینه دارد).
+
+
+
diff --git a/README.ja.md b/README.ja.md
index 21528a9fd..786e169c3 100644
--- a/README.ja.md
+++ b/README.ja.md
@@ -2,19 +2,17 @@
Swayは[i3](https://i3wm.org/)互換な[Wayland](http://wayland.freedesktop.org/)コンポジタです。
[FAQ](https://github.com/swaywm/sway/wiki)も合わせてご覧ください。
-[IRC チャンネル](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on irc.freenode.net)もあります。
+[IRC チャンネル](https://web.libera.chat/gamja/?channels=#sway) (irc.libera.chatの#sway)もあります。
[](https://sr.ht/ICd5.png)
-Swayの開発を支援したい場合は、[SirCmpwnのPatreon](https://patreon.com/sircmpwn)や、特定の機能に対する[報奨金のページ](https://github.com/swaywm/sway/issues/986)から寄付ができます。誰でも報奨金を請求できますし、自分の欲しい機能に報奨金を懸ける事も出来ます。またSwayのメンテナンスを支援するには、Patreonがより有用です。
-
## 日本語サポート
SirCmpwnは、日本語でのサポートをIRCとGitHubで行います。タイムゾーンはUTC-4です。
## リリースの署名
-Swayのリリースは[B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)で署名され、[GitHub](https://github.com/swaywm/sway/releases)で公開されています。
+Swayのリリースは[E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48)で署名され、[GitHub](https://github.com/swaywm/sway/releases)で公開されています。
## インストール
@@ -29,7 +27,7 @@ Swayは沢山のディストリビューションで提供されています。"
次の依存パッケージをインストールしてください:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.ko.md b/README.ko.md
index 0d28079f0..1086da0c0 100644
--- a/README.ko.md
+++ b/README.ko.md
@@ -1,13 +1,11 @@
# sway
sway는 [i3](https://i3wm.org/)-호환 [Wayland](http://wayland.freedesktop.org/) 컴포지터입니다.
-[FAQ](https://github.com/swaywm/sway/wiki)를 읽어보세요. [IRC 채널](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on irc.freenode.net)도 있습니다.
-
-sway 개발을 도우고 싶으시다면, [SirCmpwn의 Patreon 페이지](https://patreon.com/sircmpwn)에 기여해 주세요.
+[FAQ](https://github.com/swaywm/sway/wiki)를 읽어보세요. [IRC 채널](https://web.libera.chat/gamja/?channels=#sway) (#sway on irc.libera.chat)도 있습니다.
## 릴리즈 서명
-릴리즈는 [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)에서 서명되고,
+릴리즈는 [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48)에서 서명되고,
[GitHub에서](https://github.com/swaywm/sway/releases) 공개되고 있습니다.
## 설치
@@ -26,7 +24,7 @@ IRC 채널을 방문하거나 sir@cmpwn.com으로 이메일을 보내 상담 받
다음 의존 패키지들을 설치해 주세요:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.md b/README.md
index 336403a63..8c252e9ef 100644
--- a/README.md
+++ b/README.md
@@ -1,39 +1,30 @@
# sway
-[**English**](https://github.com/swaywm/sway/blob/master/README.md#sway--) - [日本語](https://github.com/swaywm/sway/blob/master/README.ja.md#sway--) - [Français](https://github.com/swaywm/sway/blob/master/README.fr.md#sway--) - [Українська](https://github.com/swaywm/sway/blob/master/README.uk.md#sway--) - [Español](https://github.com/swaywm/sway/blob/master/README.es.md#sway--) - [Polski](https://github.com/swaywm/sway/blob/master/README.pl.md#sway--) - [中文-简体](https://github.com/swaywm/sway/blob/master/README.zh-CN.md#sway--) - [Deutsch](https://github.com/swaywm/sway/blob/master/README.de.md#sway--) - [Nederlands](https://github.com/swaywm/sway/blob/master/README.nl.md#sway--) - [Русский](https://github.com/swaywm/sway/blob/master/README.ru.md#sway--)- [中文-繁體](https://github.com/swaywm/sway/blob/master/README.zh-TW.md#sway--) - [Português](https://github.com/swaywm/sway/blob/master/README.pt.md#sway--) - [Danish](https://github.com/swaywm/sway/blob/master/README.dk.md#sway--) - [한국어](https://github.com/swaywm/sway/blob/master/README.ko.md#sway--) - [Română](https://github.com/swaywm/sway/blob/master/README.ro.md#sway--)
+**[English][en]** - [日本語][ja] - [Français][fr] - [Українська][uk] - [Español][es] - [Polski][pl] - [中文-简体][zh-CN] - [Deutsch][de] - [Nederlands][nl] - [Русский][ru] - [中文-繁體][zh-TW] - [Português][pt] - [Dansk][dk] - [한국어][ko] - [Română][ro] - [Magyar][hu] - [Türkçe][tr] - [فارسی][ir] - [Ελληνικά][gr]
-sway is an [i3](https://i3wm.org/)-compatible [Wayland](http://wayland.freedesktop.org/) compositor.
-Read the [FAQ](https://github.com/swaywm/sway/wiki). Join the [IRC
-channel](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on
-irc.freenode.net).
-
-If you'd like to support sway development, please contribute to [SirCmpwn's
-Patreon page](https://patreon.com/sircmpwn).
+sway is an [i3]-compatible [Wayland] compositor. Read the [FAQ]. Join the
+[IRC channel] \(#sway on irc.libera.chat).
## Release Signatures
-Releases are signed with [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
-and published [on GitHub](https://github.com/swaywm/sway/releases).
+Releases are signed with [E88F5E48] and published [on GitHub][GitHub releases].
## Installation
### From Packages
Sway is available in many distributions. Try installing the "sway" package for
-yours. If it's not available, check out [this wiki page](https://github.com/swaywm/sway/wiki/Unsupported-packages)
-for information on installation for your distributions.
-
-If you're interested in packaging sway for your distribution, stop by the IRC
-channel or shoot an email to sir@cmpwn.com for advice.
+yours.
### Compiling from Source
-Check out [this wiki page](https://github.com/swaywm/sway/wiki/Development-Setup) if you want to build the HEAD of sway and wlroots for testing or development.
+Check out [this wiki page][Development setup] if you want to build the HEAD of
+sway and wlroots for testing or development.
Install dependencies:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots]
* wayland
* wayland-protocols \*
* pcre
@@ -41,18 +32,18 @@ Install dependencies:
* pango
* cairo
* gdk-pixbuf2 (optional: system tray)
-* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (optional: man pages) \*
+* [scdoc] (optional: man pages) \*
* git (optional: version info) \*
-_\*Compile-time dep_
+_\* Compile-time dep_
Run these commands:
- meson build
- ninja -C build
- sudo ninja -C build install
+ meson build/
+ ninja -C build/
+ sudo ninja -C build/ install
-On systems without logind, you need to suid the sway binary:
+On systems without logind nor seatd, you need to suid the sway binary:
sudo chmod a+s /usr/local/bin/sway
@@ -69,3 +60,32 @@ Run `man 5 sway` for information on the configuration.
Run `sway` from a TTY. Some display managers may work but are not supported by
sway (gdm is known to work fairly well).
+
+[en]: https://github.com/swaywm/sway#readme
+[ja]: https://github.com/swaywm/sway/blob/master/README.ja.md
+[fr]: https://github.com/swaywm/sway/blob/master/README.fr.md
+[uk]: https://github.com/swaywm/sway/blob/master/README.uk.md
+[es]: https://github.com/swaywm/sway/blob/master/README.es.md
+[pl]: https://github.com/swaywm/sway/blob/master/README.pl.md
+[zh-CN]: https://github.com/swaywm/sway/blob/master/README.zh-CN.md
+[de]: https://github.com/swaywm/sway/blob/master/README.de.md
+[nl]: https://github.com/swaywm/sway/blob/master/README.nl.md
+[ru]: https://github.com/swaywm/sway/blob/master/README.ru.md
+[zh-TW]: https://github.com/swaywm/sway/blob/master/README.zh-TW.md
+[pt]: https://github.com/swaywm/sway/blob/master/README.pt.md
+[dk]: https://github.com/swaywm/sway/blob/master/README.dk.md
+[ko]: https://github.com/swaywm/sway/blob/master/README.ko.md
+[ro]: https://github.com/swaywm/sway/blob/master/README.ro.md
+[hu]: https://github.com/swaywm/sway/blob/master/README.hu.md
+[tr]: https://github.com/swaywm/sway/blob/master/README.tr.md
+[ir]: https://github.com/swaywm/sway/blob/master/README.ir.md
+[gr]: https://github.com/swaywm/sway/blob/master/README.gr.md
+[i3]: https://i3wm.org/
+[Wayland]: http://wayland.freedesktop.org/
+[FAQ]: https://github.com/swaywm/sway/wiki
+[IRC channel]: https://web.libera.chat/gamja/?channels=#sway
+[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
+[GitHub releases]: https://github.com/swaywm/sway/releases
+[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
+[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
diff --git a/README.nl.md b/README.nl.md
index 4b66cb27f..c0a930631 100644
--- a/README.nl.md
+++ b/README.nl.md
@@ -2,15 +2,12 @@
Sway is een [i3](https://i3wm.org/)-compatibele [Wayland](http://wayland.freedesktop.org/) compositor.
Lees de [FAQ](https://github.com/swaywm/sway/wiki). Word lid van het [IRC
-kanaal](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway op
-irc.freenode.net).
-
-Als je de ontwikkeling van sway wilt ondersteunen, draag dan bij aan [SirCmpwn's
-Patreon-pagina](https://patreon.com/sircmpwn).
+kanaal](https://web.libera.chat/gamja/?channels=#sway) (#sway op
+irc.libera.chat).
## Releasehandtekeningen
-Releases worden ondertekend met [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
+Releases worden ondertekend met [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48)
en gepubliceerd [op GitHub](https://github.com/swaywm/sway/releases).
## Installatie
@@ -28,7 +25,7 @@ kanaal of stuur een e-mail naar sir@cmpwn.com voor advies.
Afhankelijkheden installeren:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.pl.md b/README.pl.md
index ddfd16766..6d376b68c 100644
--- a/README.pl.md
+++ b/README.pl.md
@@ -1,14 +1,12 @@
# sway
sway jest kompozytorem [Wayland](http://wayland.freedesktop.org/) kompatybilnym z [i3](https://i3wm.org/).
-Przeczytaj [FAQ](https://github.com/swaywm/sway/wiki). Dołącz do [kanału IRC](http://webchat.freenode.net/?channels=sway&uio=d4)
-(#sway na irc.freenode.net).
-
-Jeśli chcesz wesprzeć rozwój sway, rozważ wsparcie SirCmpwn na jego [stronie Patreon](https://patreon.com/sircmpwn).
+Przeczytaj [FAQ](https://github.com/swaywm/sway/wiki). Dołącz do [kanału IRC](https://web.libera.chat/gamja/?channels=#sway)
+(#sway na irc.libera.chat).
## Podpisy cyfrowe wydań
-Wydania są podpisywane przy pomocy klucza [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
+Wydania są podpisywane przy pomocy klucza [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48)
i publikowane [na GitHubie](https://github.com/swaywm/sway/releases).
## Instalacja
@@ -27,7 +25,7 @@ adres sir@cmpwn.com w celu uzyskania wskazówek.
Zainstaluj zależności:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.pt.md b/README.pt.md
index 72a95066a..92a4b54d5 100644
--- a/README.pt.md
+++ b/README.pt.md
@@ -2,15 +2,12 @@
O sway é um compositor do [Wayland](http://wayland.freedesktop.org/) compatível com o [i3](https://i3wm.org/).
Leia o [FAQ](https://github.com/swaywm/sway/wiki). Junte-se ao [canal do
-IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway em
-irc.freenode.net).
-
-Se você gostaria de apoiar o desenvolvimento do sway, por favor, contribua na [página do patreon de
-SirCmpwn](https://patreon.com/sircmpwn).
+IRC](https://web.libera.chat/gamja/?channels=#sway) (#sway em
+irc.libera.chat).
## Assinatura das versões
-As versões são assinadas com [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
+As versões são assinadas com [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48)
e publicadas [no GitHub](https://github.com/swaywm/sway/releases).
## Instalação
@@ -25,19 +22,21 @@ ou mande um email para sir@cmpwn.com para obter informações.
### Compilando a partir do código-fonte
+Verifique [essa página da wiki](https://github.com/swaywm/sway/wiki/Development-Setup) se você quer compilar o HEAD do sway e o wlroots para testes ou desenvolvimento.
+
Instale as dependências:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
* json-c
* pango
* cairo
-* gdk-pixbuf2 (optional: system tray)
-* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (Opcional: man pages) \*
-* git \*
+* gdk-pixbuf2 (opcional: system tray)
+* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (opcional: man pages) \*
+* git (opcional: informações de versão) \*
_\*Dependência de tempo de compilação_
@@ -62,5 +61,5 @@ Execute `man 5 sway` para se informar sobre a configuração.
## Execução
-Execute o comando `sway` de um TTY. Alguns gerenciadores de display (ou gerenciadores de login) podem funcionar mas alguns não são suportaods
+Execute o comando `sway` de um TTY. Alguns gerenciadores de display (ou gerenciadores de login) podem funcionar mas alguns não são suportados
pelo sway (o gdm é conhecido por funcionar bem).
diff --git a/README.ro.md b/README.ro.md
index b046bc2e8..f7785b8f2 100644
--- a/README.ro.md
+++ b/README.ro.md
@@ -1,13 +1,11 @@
# sway
sway este un compositor pentru [Wayland](http://wayland.freedesktop.org/) compatibil cu [i3](https://i3wm.org/).
-Citiți [FAQ](https://github.com/swaywm/sway/wiki)-ul. Connectați-vă la canalul nostru [IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway pe irc.freenode.net).
-
-Dacă doriți să contribuiți la dezvoltarea sway, vă rugăm contribuiți în [pagina de Patreon lui SirCmpwn](https://patreon.com/sircmpwn).
+Citiți [FAQ](https://github.com/swaywm/sway/wiki)-ul. Connectați-vă la canalul nostru [IRC](https://web.libera.chat/gamja/?channels=#sway) (#sway pe irc.libera.chat).
## Semnarea digitală
-Noile versiuni sunt semnate cu [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
+Noile versiuni sunt semnate cu [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48)
și postate [pe GitHub](https://github.com/swaywm/sway/releases).
## Instalare
@@ -24,7 +22,7 @@ Dacă sunteți interesați in a crea pachete pentru distribuția voastră, infor
Dependențe pentru instalare:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.ru.md b/README.ru.md
index 2debc551a..d563859c1 100644
--- a/README.ru.md
+++ b/README.ru.md
@@ -1,45 +1,41 @@
# sway
-sway - это [i3](https://i3wm.org/)-совместимый композитор [Wayland](http://wayland.freedesktop.org/).
-Больше информации в [FAQ](https://github.com/swaywm/sway/wiki). Присоединяйтесь к
-[IRC-каналу](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway на
-irc.freenode.net).
-
-Если вы хотите поддержать разработку sway, сделайте пожертвование SirCmpwn на
-[странице Patreon](https://patreon.com/sircmpwn).
+sway - это [i3]-совместимый композитор [Wayland].
+Больше информации в [FAQ]. Присоединяйтесь к
+[IRC-каналу][IRC channel] (#sway на
+irc.libera.chat).
## Подписи релизов
-Релизы подписываются ключом [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
-и публикуются [на GitHub](https://github.com/swaywm/sway/releases).
+Релизы подписываются ключом [E88F5E48] и публикуются [на GitHub][GitHub releases].
## Установка
### Из репозиториев
-sway доступен во многих дистрибутивах. Попробуйте установить пакет "sway".
-Если он вдруг недоступен, проверьте [эту страницу на wiki](https://github.com/swaywm/sway/wiki/Unsupported-packages)
-для получения информации о подробностях установки для вашего
-дистрибутива.
+Sway доступен во многих дистрибутивах. Попробуйте установить пакет "sway".
-Если вы заинтересованы поддерживать sway в вашем дистрибутиве, загляните в наш IRC-канал
-или обратитесь на sir@cmpwn.com за советом.
+Если вас интересует создание пакета sway для вашего дистрибутива, зайдите на [IRC-канал][IRC channel]
+или отправьте письмо на sir@cmpwn.com за советом.
### Сборка из исходников
+Посетите [эту страницу на вики][Development setup], если вы хотите построить последнюю версию
+sway и wlroots для тестирования или разработки.
+
Установите зависимости:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots]
* wayland
* wayland-protocols \*
* pcre
* json-c
* pango
* cairo
-* gdk-pixbuf2 (необязательно: для работы трея)
-* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (необязательно: для сборки man-страниц) \*
-* git \*
+* gdk-pixbuf2 (опционально: для работы трея)
+* [scdoc] (опционально: для man-страниц) \*
+* git (опционально: для информации о версии) \*
_\*Зависимости для сборки_
@@ -66,3 +62,13 @@ sway сбросит root-права при запуске.
Выполните команду `sway` прямо из TTY. Некоторые дисплейные менеджеры могут работать, но они не поддерживаются со стороны
sway (gdm работает довольно неплохо).
+
+[i3]: https://i3wm.org/
+[Wayland]: http://wayland.freedesktop.org/
+[FAQ]: https://github.com/swaywm/sway/wiki
+[IRC channel]: https://web.libera.chat/gamja/?channels=#sway
+[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
+[GitHub releases]: https://github.com/swaywm/sway/releases
+[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
+[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
diff --git a/README.tr.md b/README.tr.md
new file mode 100644
index 000000000..5c98a5386
--- /dev/null
+++ b/README.tr.md
@@ -0,0 +1,68 @@
+# sway
+
+
+Sway, [i3]-uyumlu bir [Wayland] dizgicisidir. [SSS][FAQ]'yi okuyun.
+[IRC kanalı][IRC channel]na katılın \(irc.libera.chat'te #sway (İngilizce)).
+
+## Sürüm imzaları
+
+Sürümler [E88F5E48] ile imzalandı ve [GitHub][GitHub releases]'da yayınlandı.
+
+## Kurulum
+
+### Paketler ile
+
+Sway birçok dağıtımda mevcuttur. Sizinki için "sway" paketini yüklemeyi deneyin.
+
+Dağıtımınız için sway'i paketlemekle ilgileniyorsanız, IRC kanalına uğrayın veya tavsiye için sir@cmpwn.com adresine bir e-posta gönderin.
+
+### Kaynak koddan derleme
+
+Test veya geliştirme için sway ve wlroots'un HEAD'ini oluşturmak istiyorsanız [bu wiki sayfası][Development setup]na göz atın.
+
+Aşağıdaki bağımlılıkları yükleyin:
+
+* meson \*
+* [wlroots]
+* wayland
+* wayland-protocols \*
+* pcre
+* json-c
+* pango
+* cairo
+* gdk-pixbuf2 (isteğe bağlı: system tray)
+* [scdoc] (isteğe bağlı: man pages) \*
+* git (isteğe bağlı: version info) \*
+
+_\*Derleme-anı bağımlılıkları_
+
+Şu komutları çalıştırın:
+
+ meson build
+ ninja -C build
+ sudo ninja -C build install
+
+logind olmayan sistemlerde, sway ikilisine (binary) izin vermeniz (suid) gerekir:
+
+ sudo chmod a+s /usr/local/bin/sway
+
+Sway, başlangıçtan kısa bir süre sonra kök(root) izinlerini bırakacaktır.
+
+## Yapılandırma
+
+Zaten i3 kullanıyorsanız, i3 yapılandırmanızı `~/.config/sway/config` konumuna kopyalayın ve kutudan çıktığı gibi çalışacaktır. Aksi takdirde, örnek yapılandırma dosyasını `~/.config/sway/config` konumuna kopyalayın. Genellikle `/etc/sway/config` konumunda bulunur.
+Yapılandırma hakkında bilgi almak için `man 5 sway` komutunu çalıştırın.
+
+## Çalıştırma
+
+TTY'den `sway` çalıştırın. Bazı görüntü yöneticileriyle(display manager) çalışabilir ama Sway tarafından desteklenmez. (gdm'nin oldukça iyi çalıştığı bilinmektedir.)
+
+[i3]: https://i3wm.org/
+[Wayland]: http://wayland.freedesktop.org/
+[FAQ]: https://github.com/swaywm/sway/wiki
+[IRC channel]: https://web.libera.chat/gamja/?channels=#sway
+[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
+[GitHub releases]: https://github.com/swaywm/sway/releases
+[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
+[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
diff --git a/README.uk.md b/README.uk.md
index 1c0065667..ff9ebec31 100644
--- a/README.uk.md
+++ b/README.uk.md
@@ -2,11 +2,8 @@
Sway це сумісний з [i3](https://i3wm.org/) композитор [Wayland](http://wayland.freedesktop.org/).
Ознайомтесь з [ЧаПами](https://github.com/swaywm/sway/wiki). Приєднуйтесь до [спільноти в
-IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway на
-irc.freenode.net).
-
-Якщо ви маєте бажання підтримати розробку sway, ви можете зробити свій внесок на сторінці
-[SirCmpwn у Patreon](https://patreon.com/sircmpwn).
+IRC](https://web.libera.chat/gamja/?channels=#sway) (#sway на
+irc.libera.chat).
## Підтримка українською мовою
@@ -18,7 +15,7 @@ Hummer12007 у IRC-спільноті. Будьте терплячі, вам о
## Підписи випусків
-Випуски підписані ключем [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
+Випуски підписані ключем [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48)
та публікуються на сторінці [GitHub](https://github.com/swaywm/sway/releases).
## Встановлення
@@ -39,7 +36,7 @@ Sway доступний у багатьох дистрибутивах Linux (а
Встановіть залежності:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 99dc7d835..561d6c14c 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -2,15 +2,12 @@
sway 是和 [i3](https://i3wm.org/) 兼容的 [Wayland](http://wayland.freedesktop.org/) compositor.
阅读 [FAQ](https://github.com/swaywm/sway/wiki). 加入 [IRC
-频道](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on
-irc.freenode.net).
-
-如果你想要支持 sway 的发展, 请到 [SirCmpwn's
-Patreon page](https://patreon.com/sircmpwn)贡献.
+频道](https://web.libera.chat/gamja/?channels=#sway) (#sway on
+irc.libera.chat).
## 发布签名
-发布是以 [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) 签名
+发布是以 [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) 签名
并发布在 [GitHub](https://github.com/swaywm/sway/releases).
## 安装
@@ -28,7 +25,7 @@ Sway 在很多发行版中可用. 尝试在你的发行版中安装 "sway" 包.
安装依赖:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.zh-TW.md b/README.zh-TW.md
index a27ac6408..bc30b9035 100644
--- a/README.zh-TW.md
+++ b/README.zh-TW.md
@@ -2,15 +2,12 @@
sway 是一個與 [i3](https://i3wm.org/) 相容的 [Wayland](http://wayland.freedesktop.org/) compositor。
閱讀 [FAQ](https://github.com/swaywm/sway/wiki)。 加入 [IRC
-頻道](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on
-irc.freenode.net)
-
-如果你想支持 sway 的開發,請到 [SirCmpwn's
-Patreon page](https://patreon.com/sircmpwn) 貢獻。
+頻道](https://web.libera.chat/gamja/?channels=#sway) (#sway on
+irc.libera.chat)
## 發行簽章
-所有發行的版本都會以 [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) 簽署
+所有發行的版本都會以 [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) 簽署
並發佈於 [GitHub](https://github.com/swaywm/sway/releases)
## 安裝
@@ -28,7 +25,7 @@ Sway 在許多發行版都有提供。請自己嘗試於你的發行版安裝
相依套件:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/client/pool-buffer.c b/client/pool-buffer.c
index fd500c492..ea31edd35 100644
--- a/client/pool-buffer.c
+++ b/client/pool-buffer.c
@@ -1,6 +1,6 @@
#define _POSIX_C_SOURCE 200809
#include
-#include
+#include
#include
#include
#include
diff --git a/common/background-image.c b/common/background-image.c
index de42e8e94..994a08052 100644
--- a/common/background-image.c
+++ b/common/background-image.c
@@ -1,6 +1,6 @@
#include
#include "background-image.h"
-#include "cairo.h"
+#include "cairo_util.h"
#include "log.h"
#if HAVE_GDK_PIXBUF
#include
diff --git a/common/cairo.c b/common/cairo.c
index 403dcf490..7c59d48c4 100644
--- a/common/cairo.c
+++ b/common/cairo.c
@@ -1,6 +1,6 @@
#include
-#include
-#include "cairo.h"
+#include
+#include "cairo_util.h"
void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
cairo_set_source_rgba(cairo,
diff --git a/common/log.c b/common/log.c
index 2acf2e576..483420e7f 100644
--- a/common/log.c
+++ b/common/log.c
@@ -45,6 +45,13 @@ static const char *verbosity_colors[] = {
[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;
@@ -84,6 +91,8 @@ static void sway_log_stderr(sway_log_importance_t verbosity, const char *fmt,
if (colored && isatty(STDERR_FILENO)) {
fprintf(stderr, "%s", verbosity_colors[c]);
+ } else {
+ fprintf(stderr, "%s ", verbosity_headers[c]);
}
vfprintf(stderr, fmt, args);
diff --git a/common/pango.c b/common/pango.c
index fc3d06886..abc18281f 100644
--- a/common/pango.c
+++ b/common/pango.c
@@ -1,4 +1,4 @@
-#include
+#include
#include
#include
#include
@@ -6,7 +6,7 @@
#include
#include
#include
-#include "cairo.h"
+#include "cairo_util.h"
#include "log.h"
#include "stringop.h"
@@ -109,7 +109,23 @@ void get_text_size(cairo_t *cairo, const char *font, int *width, int *height,
free(buf);
}
-void pango_printf(cairo_t *cairo, const char *font,
+void get_text_metrics(const char *font, int *height, int *baseline) {
+ cairo_t *cairo = cairo_create(NULL);
+ PangoContext *pango = pango_cairo_create_context(cairo);
+ PangoFontDescription *description = pango_font_description_from_string(font);
+ // 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);
+ pango_font_description_free(description);
+ g_object_unref(pango);
+ cairo_destroy(cairo);
+}
+
+void render_text(cairo_t *cairo, const char *font,
double scale, bool markup, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
diff --git a/common/stringop.c b/common/stringop.c
index 8c8e9aa21..7fb3fe12a 100644
--- a/common/stringop.c
+++ b/common/stringop.c
@@ -64,7 +64,7 @@ char *lenient_strncat(char *dest, const char *src, size_t len) {
}
// strcmp that also handles null pointers.
-int lenient_strcmp(char *a, char *b) {
+int lenient_strcmp(const char *a, const char *b) {
if (a == b) {
return 0;
} else if (!a) {
diff --git a/common/util.c b/common/util.c
index 5ea94f481..199f3ee1c 100644
--- a/common/util.c
+++ b/common/util.c
@@ -10,12 +10,6 @@
#include "log.h"
#include "util.h"
-uint32_t get_current_time_msec(void) {
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
- return now.tv_sec * 1000 + now.tv_nsec / 1000000;
-}
-
int wrap(int i, int max) {
return ((i % max) + max) % max;
}
diff --git a/config.in b/config.in
index 08703bef2..94050ba6c 100644
--- a/config.in
+++ b/config.in
@@ -14,7 +14,7 @@ set $down j
set $up k
set $right l
# Your preferred terminal emulator
-set $term alacritty
+set $term foot
# Your preferred application launcher
# Note: pass the final command to swaymsg so that the resulting window can be opened
# on the original workspace that the command was run on.
@@ -82,7 +82,7 @@ output * bg @datadir@/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill
bindsym $mod+Shift+c reload
# Exit sway (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 sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'
+ bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -B 'Yes, exit sway' 'swaymsg exit'
#
# Moving around:
#
@@ -205,7 +205,7 @@ bar {
# 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 %l:%M:%S %p'; do sleep 1; done
+ status_command while date +'%Y-%m-%d %I:%M:%S %p'; do sleep 1; done
colors {
statusline #ffffff
diff --git a/contrib/_incr_version b/contrib/_incr_version
deleted file mode 100755
index a4fa26547..000000000
--- a/contrib/_incr_version
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/sh -eu
-old_version="$1"
-new_version="$2"
-
-if [ "$new_version" != "${new_version#v}" ]
-then
- echo "Error: The new version shouldn't be prefixed with a \"v\"." >&2
- exit 1
-fi
-
-sed -i meson.build -e "s/^ version: .*#release_version/ version: '$new_version', #release_version/g"
-
-printf "Minimum wlroots version? "
-read wlr_version_min
-printf "Maximum wlroots version? "
-read wlr_version_max
-
-sed -i meson.build -e "s/wlroots_version =.*/wlroots_version = ['>=$wlr_version_min', '<$wlr_version_max']/"
-
-git add meson.build
-git commit -m "Update version to $new_version"
diff --git a/contrib/autoname-workspaces.py b/contrib/autoname-workspaces.py
index 297d91b2a..3ec399280 100755
--- a/contrib/autoname-workspaces.py
+++ b/contrib/autoname-workspaces.py
@@ -22,24 +22,17 @@ DEFAULT_ICON = ""
def icon_for_window(window):
- app_id = window.app_id
- if app_id is not None and len(app_id) > 0:
- app_id = app_id.lower()
- if app_id in WINDOW_ICONS:
- return WINDOW_ICONS[app_id]
- logging.info("No icon available for window with app_id: %s" % str(app_id))
- else:
- # xwayland support
- class_name = window.window_class
- if len(class_name) > 0:
- class_name = class_name.lower()
- if class_name in WINDOW_ICONS:
- return WINDOW_ICONS[class_name]
- logging.info(
- "No icon available for window with class_name: %s" % str(class_name)
- )
- return DEFAULT_ICON
+ name = None
+ if window.app_id is not None and len(window.app_id) > 0:
+ name = window.app_id.lower()
+ elif window.window_class is not None and len(window.window_class) > 0:
+ name = window.window_class.lower()
+ if name in WINDOW_ICONS:
+ return WINDOW_ICONS[name]
+
+ logging.info("No icon available for window with name: %s" % str(name))
+ return DEFAULT_ICON
def rename_workspaces(ipc):
for workspace in ipc.get_tree().workspaces():
@@ -128,3 +121,4 @@ if __name__ == "__main__":
rename_workspaces(ipc)
ipc.main()
+
diff --git a/contrib/grimshot b/contrib/grimshot
index 461a5eeff..4ce31f29f 100755
--- a/contrib/grimshot
+++ b/contrib/grimshot
@@ -32,13 +32,13 @@ FILE=${3:-$(getTargetDirectory)/$(date -Ins).png}
if [ "$ACTION" != "save" ] && [ "$ACTION" != "copy" ] && [ "$ACTION" != "check" ]; then
echo "Usage:"
- echo " grimshot [--notify] (copy|save) [active|screen|output|area|window] [FILE]"
+ echo " grimshot [--notify] (copy|save) [active|screen|output|area|window] [FILE|-]"
echo " grimshot check"
echo " grimshot usage"
echo ""
echo "Commands:"
echo " copy: Copy the screenshot data into the clipboard."
- echo " save: Save the screenshot to a regular file."
+ echo " save: Save the screenshot to a regular file or '-' to pipe to STDOUT."
echo " check: Verify if required tools are installed and exit."
echo " usage: Show this message and exit."
echo ""
@@ -113,7 +113,7 @@ elif [ "$SUBJECT" = "area" ] ; then
GEOM=$(slurp -d)
# Check if user exited slurp without selecting the area
if [ -z "$GEOM" ]; then
- exit
+ exit 1
fi
WHAT="Area"
elif [ "$SUBJECT" = "active" ] ; then
@@ -132,7 +132,7 @@ elif [ "$SUBJECT" = "window" ] ; then
GEOM=$(swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp)
# Check if user exited slurp without selecting the area
if [ -z "$GEOM" ]; then
- exit
+ exit 1
fi
WHAT="Window"
else
diff --git a/contrib/grimshot.1 b/contrib/grimshot.1
index a51f3d4d0..e4baccfdd 100644
--- a/contrib/grimshot.1
+++ b/contrib/grimshot.1
@@ -1,53 +1,61 @@
-.\" Generated by scdoc 1.10.1
+.\" Generated by scdoc 1.11.1
.\" Complete documentation for this program is not available as a GNU info page
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.nh
.ad l
.\" Begin generated content:
-.TH "grimshot" "1" "2020-05-08"
+.TH "grimshot" "1" "2021-02-23"
.P
.SH NAME
.P
grimshot - a helper for screenshots within sway
.P
-.SH DESCRIPTION
+.SH SYNOPSIS
.P
-grimshot [--notify] (copy|save) [TARGET] [FILE]
-grimshot check
-grimshot usage
+\fBgrimshot\fR [--notify] (copy|save) [TARGET] [FILE]
+.br
+\fBgrimshot\fR check
+.br
+\fBgrimshot\fR usage
+.P
+.SH OPTIONS
.P
\fB--notify\fR
.RS 4
-Show notifications to the user that a screenshot has been taken.
+Show notifications to the user that a screenshot has been taken.\&
.P
.RE
\fBsave\fR
.RS 4
-Save the screenshot into a regular file. Grimshot will write images
-files to \fB$XDG_SCREENSHOTS_DIR\fR if this is set (or defined
-in `user-dirs.dir`), or otherwise fall back to `$XDG_PICTURES_DIR`
+Save the screenshot into a regular file.\& Grimshot will write images
+files to \fBXDG_SCREENSHOTS_DIR\fR if this is set (or defined
+in \fBuser-dirs.\&dir\fR), or otherwise fall back to \fBXDG_PICTURES_DIR\fR.\&
+Set FILE to '-' to pipe the output to STDOUT.\&
.P
.RE
\fBcopy\fR
.RS 4
-Copy the screenshot data (as image/png) into the clipboard.
+Copy the screenshot data (as image/png) into the clipboard.\&
.P
.RE
-.SH SYNOPSIS
+.SH DESCRIPTION
.P
-Grimshot is an easy to use screenshot tool for sway. It relies on grim, slurp
-and jq to do the heavy lifting, and mostly provides an easy to use interface.
+Grimshot is an easy-to-use screenshot utility for sway.\& It provides a
+convenient interface over grim, slurp and jq, and supports storing the
+screenshot either directly to the clipboard using wl-copy or to a file.\&
.P
-A recommended usage pattern is to just bind this to Super+P via sway:
+.SH EXAMPLES
+.P
+An example usage pattern is to add these bindings to your sway config:
.P
.nf
.RS 4
# Screenshots:
-# Cmd+P: Current window
-# Cmd+Shift+p: Select area
-# Cmd+Alt+p Current output
-# Cmd+Ctrl+p Select a window
+# Super+P: Current window
+# Super+Shift+p: Select area
+# Super+Alt+p Current output
+# Super+Ctrl+p Select a window
bindsym Mod4+p exec grimshot save active
bindsym Mod4+Shift+p exec grimshot save area
@@ -62,34 +70,34 @@ grimshot can capture the following named targets:
.P
\fIactive\fR
.RS 4
-Captures the currently active window.
+Captures the currently active window.\&
.P
.RE
\fIscreen\fR
.RS 4
-Captures the entire screen. This includes all visible outputs.
+Captures the entire screen.\& This includes all visible outputs.\&
.P
.RE
\fIarea\fR
.RS 4
-Allows manually selecting a rectangular region, and captures that.
+Allows manually selecting a rectangular region, and captures that.\&
.P
.RE
\fIwindow\fR
.RS 4
Allows manually selecting a single window (by clicking on it), and
-captures it.
+captures it.\&
.P
.RE
\fIoutput\fR
.RS 4
-Captures the currently active output.
+Captures the currently active output.\&
.P
.RE
.SH OUTPUT
.P
-Grimshot will always print the filename of the captured screenshot to
-stdout.
+Grimshot will print the filename of the captured screenshot to stdout if called
+with the \fIsave\fR subcommand.\&
.P
.SH SEE ALSO
.P
diff --git a/contrib/grimshot.1.scd b/contrib/grimshot.1.scd
index b28779765..d2a577599 100644
--- a/contrib/grimshot.1.scd
+++ b/contrib/grimshot.1.scd
@@ -4,36 +4,42 @@ grimshot(1)
grimshot - a helper for screenshots within sway
-# DESCRIPTION
+# SYNOPSIS
-grimshot [--notify] (copy|save) [TARGET] [FILE]
-grimshot check
-grimshot usage
+*grimshot* [--notify] (copy|save) [TARGET] [FILE]++
+*grimshot* check++
+*grimshot* usage
+
+# OPTIONS
*--notify*
Show notifications to the user that a screenshot has been taken.
*save*
Save the screenshot into a regular file. Grimshot will write images
- files to *$XDG_SCREENSHOTS_DIR* if this is set (or defined
- in `user-dirs.dir`), or otherwise fall back to `$XDG_PICTURES_DIR`
+ files to *XDG_SCREENSHOTS_DIR* if this is set (or defined
+ in *user-dirs.dir*), or otherwise fall back to *XDG_PICTURES_DIR*.
+ Set FILE to '-' to pipe the output to STDOUT.
*copy*
Copy the screenshot data (as image/png) into the clipboard.
-# SYNOPSIS
+# DESCRIPTION
-Grimshot is an easy to use screenshot tool for sway. It relies on grim, slurp
-and jq to do the heavy lifting, and mostly provides an easy to use interface.
+Grimshot is an easy-to-use screenshot utility for sway. It provides a
+convenient interface over grim, slurp and jq, and supports storing the
+screenshot either directly to the clipboard using wl-copy or to a file.
-A recommended usage pattern is to just bind this to Super+P via sway:
+# EXAMPLES
+
+An example usage pattern is to add these bindings to your sway config:
```
# Screenshots:
-# Cmd+P: Current window
-# Cmd+Shift+p: Select area
-# Cmd+Alt+p Current output
-# Cmd+Ctrl+p Select a window
+# Super+P: Current window
+# Super+Shift+p: Select area
+# Super+Alt+p Current output
+# Super+Ctrl+p Select a window
bindsym Mod4+p exec grimshot save active
bindsym Mod4+Shift+p exec grimshot save area
@@ -63,8 +69,8 @@ _output_
# OUTPUT
-Grimshot will always print the filename of the captured screenshot to
-stdout.
+Grimshot will print the filename of the captured screenshot to stdout if called
+with the _save_ subcommand.
# SEE ALSO
diff --git a/contrib/inactive-windows-transparency.py b/contrib/inactive-windows-transparency.py
index 77b1f221c..b81134dd4 100755
--- a/contrib/inactive-windows-transparency.py
+++ b/contrib/inactive-windows-transparency.py
@@ -15,8 +15,13 @@ def on_window_focus(inactive_opacity, ipc, event):
global prev_focused
global prev_workspace
+ focused_workspace = ipc.get_tree().find_focused()
+
+ if focused_workspace == None:
+ return
+
focused = event.container
- workspace = ipc.get_tree().find_focused().workspace().num
+ workspace = focused_workspace.workspace().num
if focused.id != prev_focused.id: # https://github.com/swaywm/sway/issues/2859
focused.command("opacity 1")
diff --git a/include/background-image.h b/include/background-image.h
index 15935ffd3..a97ef3752 100644
--- a/include/background-image.h
+++ b/include/background-image.h
@@ -1,6 +1,6 @@
#ifndef _SWAY_BACKGROUND_IMAGE_H
#define _SWAY_BACKGROUND_IMAGE_H
-#include "cairo.h"
+#include "cairo_util.h"
enum background_mode {
BACKGROUND_MODE_STRETCH,
diff --git a/include/cairo.h b/include/cairo_util.h
similarity index 81%
rename from include/cairo.h
rename to include/cairo_util.h
index c1275db20..dc049c6dc 100644
--- a/include/cairo.h
+++ b/include/cairo_util.h
@@ -1,8 +1,8 @@
-#ifndef _SWAY_CAIRO_H
-#define _SWAY_CAIRO_H
+#ifndef _SWAY_CAIRO_UTIL_H
+#define _SWAY_CAIRO_UTIL_H
#include "config.h"
#include
-#include
+#include
#include
void cairo_set_source_u32(cairo_t *cairo, uint32_t color);
diff --git a/include/ipc-client.h b/include/ipc-client.h
index d3895023f..9c5712d73 100644
--- a/include/ipc-client.h
+++ b/include/ipc-client.h
@@ -1,6 +1,9 @@
#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
#include
#include
diff --git a/include/pango.h b/include/pango.h
index 6ab83c167..93affc236 100644
--- a/include/pango.h
+++ b/include/pango.h
@@ -3,7 +3,7 @@
#include
#include
#include
-#include
+#include
#include
/**
@@ -17,7 +17,8 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
const char *text, double scale, bool markup);
void get_text_size(cairo_t *cairo, const char *font, int *width, int *height,
int *baseline, double scale, bool markup, const char *fmt, ...);
-void pango_printf(cairo_t *cairo, const char *font,
+void get_text_metrics(const char *font, int *height, int *baseline);
+void render_text(cairo_t *cairo, const char *font,
double scale, bool markup, const char *fmt, ...);
#endif
diff --git a/include/pool-buffer.h b/include/pool-buffer.h
index 54f5be069..b7a95afe9 100644
--- a/include/pool-buffer.h
+++ b/include/pool-buffer.h
@@ -1,6 +1,6 @@
#ifndef _SWAY_BUFFERS_H
#define _SWAY_BUFFERS_H
-#include
+#include
#include
#include
#include
diff --git a/include/stringop.h b/include/stringop.h
index e3f4f0f7c..8d7089e91 100644
--- a/include/stringop.h
+++ b/include/stringop.h
@@ -12,7 +12,7 @@ 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(char *a, char *b);
+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);
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 4a2f8c20d..4be408705 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -46,8 +46,8 @@ enum expected_args {
struct cmd_results *checkarg(int argc, const char *name,
enum expected_args type, int val);
-struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers,
- size_t handlers_size);
+const struct cmd_handler *find_handler(char *line,
+ const struct cmd_handler *cmd_handlers, size_t handlers_size);
/**
* Parse and executes a command.
@@ -68,7 +68,7 @@ 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,
- struct cmd_handler *handlers, size_t handlers_size);
+ const struct cmd_handler *handlers, size_t handlers_size);
/*
* Parses a command policy rule.
*/
@@ -97,6 +97,12 @@ void container_resize_tiled(struct sway_container *parent, uint32_t axis,
struct sway_container *container_find_resize_parent(struct sway_container *con,
uint32_t edge);
+/**
+ * Handlers shared by exec and exec_always.
+ */
+sway_cmd cmd_exec_validate;
+sway_cmd cmd_exec_process;
+
sway_cmd cmd_assign;
sway_cmd cmd_bar;
sway_cmd cmd_bindcode;
@@ -222,6 +228,7 @@ 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;
@@ -257,6 +264,7 @@ sway_cmd input_cmd_scroll_button;
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;
@@ -274,6 +282,7 @@ sway_cmd output_cmd_dpms;
sway_cmd output_cmd_enable;
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_scale;
sway_cmd output_cmd_scale_filter;
diff --git a/include/sway/config.h b/include/sway/config.h
index 5ad240d34..660245c1e 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -5,12 +5,15 @@
#include
#include
#include
-#include
+#include
+#include
#include
+#include
#include "../include/config.h"
#include "list.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"
@@ -116,6 +119,11 @@ enum input_config_mapped_to {
MAPPED_TO_REGION,
};
+struct input_config_tool {
+ enum wlr_tablet_tool_type type;
+ enum sway_tablet_tool_mode mode;
+};
+
/**
* options for input devices
*/
@@ -160,6 +168,8 @@ struct input_config {
char *mapped_to_output;
struct wlr_box *mapped_to_region;
+ list_t *tools;
+
bool capturable;
struct wlr_box region;
};
@@ -172,6 +182,12 @@ struct seat_attachment_config {
// 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,
@@ -207,6 +223,7 @@ struct seat_config {
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;
@@ -241,6 +258,7 @@ struct output_config {
int width, height;
float refresh_rate;
int custom_mode;
+ drmModeModeInfo drm_mode;
int x, y;
float scale;
enum scale_filter_mode scale_filter;
@@ -265,6 +283,12 @@ struct side_gaps {
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.
@@ -276,6 +300,12 @@ struct workspace_config {
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;
@@ -307,7 +337,7 @@ struct bar_config {
char *position;
list_t *bindings;
char *status_command;
- bool pango_markup;
+ enum pango_markup_config pango_markup;
char *font;
int height; // -1 not defined
bool workspace_buttons;
@@ -320,6 +350,7 @@ struct bar_config {
struct side_gaps gaps;
int status_padding;
int status_edge_padding;
+ uint32_t workspace_min_width;
struct {
char *background;
char *statusline;
@@ -393,14 +424,6 @@ enum sway_popup_during_fullscreen {
POPUP_LEAVE,
};
-enum command_context {
- CONTEXT_CONFIG = 1 << 0,
- CONTEXT_BINDING = 1 << 1,
- CONTEXT_IPC = 1 << 2,
- CONTEXT_CRITERIA = 1 << 3,
- CONTEXT_ALL = 0xFFFFFFFF,
-};
-
enum focus_follows_mouse_mode {
FOLLOWS_NO,
FOLLOWS_YES,
@@ -463,8 +486,8 @@ struct sway_config {
enum sway_container_layout default_orientation;
enum sway_container_layout default_layout;
char *font;
- size_t font_height;
- size_t font_baseline;
+ int font_height;
+ int font_baseline;
bool pango_markup;
int titlebar_border_thickness;
int titlebar_h_padding;
@@ -495,7 +518,7 @@ struct sway_config {
bool tiling_drag;
int tiling_drag_threshold;
- bool smart_gaps;
+ enum smart_gaps_mode smart_gaps;
int gaps_inner;
struct side_gaps gaps_outer;
@@ -542,7 +565,7 @@ struct sway_config {
struct sway_node *node;
struct sway_container *container;
struct sway_workspace *workspace;
- bool using_criteria;
+ bool node_overridden; // True if the node is selected by means other than focus
struct {
int argc;
char **argv;
@@ -673,14 +696,13 @@ 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 max title height
- * reported by each container. If recalculate is true, the containers will
- * recalculate their heights before reporting.
- *
+ * 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(bool recalculate);
+void config_update_font_height(void);
/**
* Convert bindsym into bindcode using the first configured layout.
diff --git a/include/sway/desktop/idle_inhibit_v1.h b/include/sway/desktop/idle_inhibit_v1.h
index 0adafdb91..58d54c686 100644
--- a/include/sway/desktop/idle_inhibit_v1.h
+++ b/include/sway/desktop/idle_inhibit_v1.h
@@ -22,6 +22,7 @@ struct sway_idle_inhibit_manager_v1 {
struct sway_idle_inhibitor_v1 {
struct sway_idle_inhibit_manager_v1 *manager;
+ struct wlr_idle_inhibitor_v1 *wlr_inhibitor;
struct sway_view *view;
enum sway_idle_inhibit_mode mode;
diff --git a/include/sway/desktop/transaction.h b/include/sway/desktop/transaction.h
index 66e8c9a25..7dd58ba8c 100644
--- a/include/sway/desktop/transaction.h
+++ b/include/sway/desktop/transaction.h
@@ -28,6 +28,12 @@ struct sway_view;
*/
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.
*
@@ -38,11 +44,11 @@ void transaction_notify_view_ready_by_serial(struct sway_view *view,
/**
* Notify the transaction system that a view is ready for the new layout, but
- * identifying the instruction by width and height rather than by serial.
+ * identifying the instruction by geometry rather than by serial.
*
* This is used by xwayland views, as they don't have serials.
*/
-void transaction_notify_view_ready_by_size(struct sway_view *view,
- int width, int height);
+void transaction_notify_view_ready_by_geometry(struct sway_view *view,
+ double x, double y, int width, int height);
#endif
diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h
index 4c130fafc..7d66e6997 100644
--- a/include/sway/input/cursor.h
+++ b/include/sway/input/cursor.h
@@ -6,6 +6,7 @@
#include
#include
#include "sway/input/seat.h"
+#include "config.h"
#define SWAY_CURSOR_PRESSED_BUTTONS_CAP 32
@@ -51,7 +52,9 @@ struct sway_cursor {
struct wl_listener touch_down;
struct wl_listener touch_up;
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;
@@ -68,6 +71,10 @@ struct sway_cursor {
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;
};
@@ -90,10 +97,13 @@ 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(struct sway_cursor *cursor,
+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 dispatch_cursor_button(struct sway_cursor *cursor,
struct wlr_input_device *device, uint32_t time_msec, uint32_t button,
@@ -110,7 +120,7 @@ void cursor_set_image_surface(struct sway_cursor *cursor,
struct wl_client *client);
void cursor_warp_to_container(struct sway_cursor *cursor,
- struct sway_container *container);
+ struct sway_container *container, bool force);
void cursor_warp_to_workspace(struct sway_cursor *cursor,
struct sway_workspace *workspace);
diff --git a/include/sway/input/libinput.h b/include/sway/input/libinput.h
index de0199765..890d632ee 100644
--- a/include/sway/input/libinput.h
+++ b/include/sway/input/libinput.h
@@ -6,4 +6,6 @@ void sway_input_configure_libinput_device(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
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index 2256fff18..77c2278d7 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -16,13 +16,12 @@ struct sway_seatop_impl {
void (*button)(struct sway_seat *seat, uint32_t time_msec,
struct wlr_input_device *device, uint32_t button,
enum wlr_button_state state);
- void (*pointer_motion)(struct sway_seat *seat, uint32_t time_msec,
- double dx, double dy);
+ void (*pointer_motion)(struct sway_seat *seat, uint32_t time_msec);
void (*pointer_axis)(struct sway_seat *seat,
struct wlr_event_pointer_axis *event);
void (*rebase)(struct sway_seat *seat, uint32_t time_msec);
void (*tablet_tool_motion)(struct sway_seat *seat,
- struct sway_tablet_tool *tool, uint32_t time_msec, double dx, double dy);
+ 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);
@@ -240,7 +239,10 @@ enum wlr_edges find_resize_edge(struct sway_container *cont,
void seatop_begin_default(struct sway_seat *seat);
void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
- uint32_t time_msec, int sx, int sy);
+ uint32_t time_msec, double sx, double sy);
+
+void seatop_begin_down_on_surface(struct sway_seat *seat,
+ struct wlr_surface *surface, uint32_t time_msec, double sx, double sy);
void seatop_begin_move_floating(struct sway_seat *seat,
struct sway_container *con);
@@ -269,11 +271,7 @@ void seatop_button(struct sway_seat *seat, uint32_t time_msec,
struct wlr_input_device *device, uint32_t button,
enum wlr_button_state state);
-/**
- * dx and dy are distances relative to previous position.
- */
-void seatop_pointer_motion(struct sway_seat *seat, uint32_t time_msec,
- double dx, double dy);
+void seatop_pointer_motion(struct sway_seat *seat, uint32_t time_msec);
void seatop_pointer_axis(struct sway_seat *seat,
struct wlr_event_pointer_axis *event);
@@ -283,7 +281,7 @@ void seatop_tablet_tool_tip(struct sway_seat *seat,
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, double dx, double dy);
+ struct sway_tablet_tool *tool, uint32_t time_msec);
void seatop_rebase(struct sway_seat *seat, uint32_t time_msec);
diff --git a/include/sway/input/tablet.h b/include/sway/input/tablet.h
index f30e232a8..d7e4c2425 100644
--- a/include/sway/input/tablet.h
+++ b/include/sway/input/tablet.h
@@ -11,11 +11,17 @@ struct sway_tablet {
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;
diff --git a/include/sway/input/text_input.h b/include/sway/input/text_input.h
index 81915795d..37744266d 100644
--- a/include/sway/input/text_input.h
+++ b/include/sway/input/text_input.h
@@ -28,7 +28,10 @@ struct sway_input_method_relay {
struct wl_listener input_method_new;
struct wl_listener input_method_commit;
+ 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 {
@@ -53,6 +56,8 @@ struct sway_text_input {
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);
diff --git a/include/sway/layers.h b/include/sway/layers.h
index 025776f8e..224dc5e68 100644
--- a/include/sway/layers.h
+++ b/include/sway/layers.h
@@ -1,7 +1,6 @@
#ifndef _SWAY_LAYERS_H
#define _SWAY_LAYERS_H
#include
-#include
#include
#include
@@ -20,8 +19,11 @@ struct sway_layer_surface {
struct wl_listener surface_commit;
struct wl_listener output_destroy;
struct wl_listener new_popup;
+ struct wl_listener new_subsurface;
struct wlr_box geo;
+ bool mapped;
+ struct wlr_box extent;
enum zwlr_layer_shell_v1_layer layer;
};
@@ -39,6 +41,16 @@ struct sway_layer_popup {
struct wl_listener new_popup;
};
+struct sway_layer_subsurface {
+ struct wlr_subsurface *wlr_subsurface;
+ struct sway_layer_surface *layer_surface;
+
+ struct wl_listener map;
+ struct wl_listener unmap;
+ struct wl_listener destroy;
+ struct wl_listener commit;
+};
+
struct sway_output;
void arrange_layers(struct sway_output *output);
diff --git a/include/sway/output.h b/include/sway/output.h
index 4e4588a6f..dae6edc82 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -3,7 +3,6 @@
#include
#include
#include
-#include
#include
#include
#include "config.h"
@@ -44,9 +43,8 @@ struct sway_output {
struct sway_output_state current;
struct wl_listener destroy;
+ struct wl_listener commit;
struct wl_listener mode;
- struct wl_listener transform;
- struct wl_listener scale;
struct wl_listener present;
struct wl_listener damage_destroy;
struct wl_listener damage_frame;
@@ -77,8 +75,8 @@ struct sway_output *output_get_in_direction(struct sway_output *reference,
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, float rotation,
+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);
void output_damage_whole(struct sway_output *output);
@@ -121,7 +119,7 @@ void output_view_for_each_surface(struct sway_output *output,
struct sway_view *view, sway_surface_iterator_func_t iterator,
void *user_data);
-void output_view_for_each_popup(struct sway_output *output,
+void output_view_for_each_popup_surface(struct sway_output *output,
struct sway_view *view, sway_surface_iterator_func_t iterator,
void *user_data);
@@ -129,11 +127,11 @@ void output_layer_for_each_surface(struct sway_output *output,
struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
void *user_data);
-void output_layer_for_each_surface_toplevel(struct sway_output *output,
+void output_layer_for_each_toplevel_surface(struct sway_output *output,
struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
void *user_data);
-void output_layer_for_each_surface_popup(struct sway_output *output,
+void output_layer_for_each_popup_surface(struct sway_output *output,
struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
void *user_data);
diff --git a/include/sway/server.h b/include/sway/server.h
index c1229b0b1..e1fcb133f 100644
--- a/include/sway/server.h
+++ b/include/sway/server.h
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -24,6 +25,8 @@
#include "sway/xwayland.h"
#endif
+struct sway_transaction;
+
struct sway_server {
struct wl_display *wl_display;
struct wl_event_loop *wl_event_loop;
@@ -71,6 +74,9 @@ struct sway_server {
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_presentation *presentation;
struct wlr_pointer_constraints_v1 *pointer_constraints;
@@ -88,8 +94,25 @@ struct sway_server {
struct wlr_workspace_manager_v1 *workspace_manager;
struct wl_listener workspace_manager_commit_request;
+ struct wlr_xdg_activation_v1 *xdg_activation_v1;
+ struct wl_listener xdg_activation_v1_request_activate;
+
+ // The timeout for transactions, after which a transaction is applied
+ // regardless of readiness.
size_t txn_timeout_ms;
- list_t *transactions;
+
+ // 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;
};
@@ -99,6 +122,7 @@ 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
+ bool noscanout; // Disable direct scan-out
enum {
DAMAGE_DEFAULT, // Default behaviour
@@ -116,6 +140,8 @@ void server_fini(struct sway_server *server);
bool server_start(struct sway_server *server);
void server_run(struct sway_server *server);
+void restore_nofile_limit(void);
+
void handle_compositor_new_surface(struct wl_listener *listener, void *data);
void handle_new_output(struct wl_listener *listener, void *data);
@@ -128,5 +154,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data);
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);
#endif
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 136d618b2..97fa98c1c 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -2,7 +2,6 @@
#define _SWAY_CONTAINER_H
#include
#include
-#include
#include
#include "list.h"
#include "sway/tree/node.h"
@@ -46,9 +45,9 @@ struct sway_container_state {
enum sway_fullscreen_mode fullscreen_mode;
- struct sway_workspace *workspace;
- struct sway_container *parent;
- list_t *children;
+ 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;
@@ -60,6 +59,7 @@ struct sway_container_state {
bool border_left;
bool border_right;
+ // These are in layout coordinates.
double content_x, content_y;
double content_width, content_height;
};
@@ -68,26 +68,29 @@ struct sway_container {
struct sway_node node;
struct sway_view *view;
- // The pending state is the main container properties, and the current state is in the below struct.
- // This means most places of the code can refer to the main variables (pending state) and it'll just work.
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
- enum sway_container_layout layout;
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 x, y;
- double width, height;
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;
@@ -97,33 +100,11 @@ struct sway_container {
double child_total_width;
double child_total_height;
- // These are in layout coordinates.
- double content_x, content_y;
- int content_width, content_height;
-
// In most cases this is the same as the content x and y, but if the view
// refuses to resize to the content dimensions then it can be smaller.
// These are in layout coordinates.
double surface_x, surface_y;
- enum sway_fullscreen_mode fullscreen_mode;
-
- enum sway_container_border border;
-
- // 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;
-
- int border_thickness;
- bool border_top;
- bool border_bottom;
- bool border_left;
- bool border_right;
-
- 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
-
// Outputs currently being intersected
list_t *outputs; // struct sway_output
@@ -138,8 +119,6 @@ struct sway_container {
struct wlr_texture *title_focused_inactive;
struct wlr_texture *title_unfocused;
struct wlr_texture *title_urgent;
- size_t title_height;
- size_t title_baseline;
list_t *marks; // char *
struct wlr_texture *marks_focused;
@@ -181,6 +160,11 @@ struct sway_container *tiling_container_at(
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.
*/
@@ -197,11 +181,6 @@ struct sway_container *container_flatten(struct sway_container *container);
void container_update_title_textures(struct sway_container *container);
-/**
- * Calculate the container's title_height property.
- */
-void container_calculate_title_height(struct sway_container *container);
-
size_t container_build_representation(enum sway_container_layout layout,
list_t *children, char *buffer);
@@ -228,9 +207,16 @@ 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);
+/**
+ * Same as above, but for current container state.
+ */
+bool container_is_current_floating(struct sway_container *container);
+
/**
* Get a container's box in layout coordinates.
*/
@@ -296,6 +282,7 @@ bool container_is_fullscreen_or_child(struct sway_container *container);
/**
* Return the output which will be used for scale purposes.
* This is the most recently entered output.
+ * If the container is not on any output, return NULL.
*/
struct sway_output *container_get_effective_output(struct sway_container *con);
@@ -367,4 +354,21 @@ 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 it's 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);
+
#endif
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index a32f5907c..008361f7b 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -47,7 +47,7 @@ struct sway_view_impl {
bool (*wants_floating)(struct sway_view *view);
void (*for_each_surface)(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data);
- void (*for_each_popup)(struct sway_view *view,
+ void (*for_each_popup_surface)(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data);
bool (*is_transient_for)(struct sway_view *child,
struct sway_view *ancestor);
@@ -99,7 +99,9 @@ struct sway_view {
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_destroy;
bool destroying;
@@ -110,7 +112,6 @@ struct sway_view {
#if HAVE_XWAYLAND
struct wlr_xwayland_surface *wlr_xwayland_surface;
#endif
- struct wlr_wl_shell_surface *wlr_wl_shell_surface;
};
struct {
@@ -130,7 +131,6 @@ struct sway_xdg_shell_view {
struct wl_listener commit;
struct wl_listener request_move;
struct wl_listener request_resize;
- struct wl_listener request_maximize;
struct wl_listener request_fullscreen;
struct wl_listener set_title;
struct wl_listener set_app_id;
@@ -160,6 +160,7 @@ struct sway_xwayland_view {
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
+ struct wl_listener override_redirect;
};
struct sway_xwayland_unmanaged {
@@ -171,15 +172,17 @@ struct sway_xwayland_unmanaged {
struct wl_listener request_configure;
struct wl_listener request_fullscreen;
struct wl_listener commit;
+ struct wl_listener set_geometry;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
+ struct wl_listener override_redirect;
};
#endif
struct sway_view_child;
struct sway_view_child_impl {
- void (*get_root_coords)(struct sway_view_child *child, int *sx, int *sy);
+ void (*get_view_coords)(struct sway_view_child *child, int *sx, int *sy);
void (*destroy)(struct sway_view_child *child);
};
@@ -292,9 +295,9 @@ void view_for_each_surface(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data);
/**
- * Iterate all popups recursively.
+ * Iterate all popup surfaces of a view.
*/
-void view_for_each_popup(struct sway_view *view,
+void view_for_each_popup_surface(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data);
// view implementation
@@ -306,12 +309,22 @@ 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, int width, int height);
+void view_update_size(struct sway_view *view);
+void view_center_surface(struct sway_view *view);
void view_child_init(struct sway_view_child *child,
const struct sway_view_child_impl *impl, struct sway_view *view,
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index b57dceaa7..baf506452 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -63,20 +63,20 @@ void workspace_consider_destroy(struct sway_workspace *ws);
char *workspace_next_name(const char *output_name);
-bool workspace_switch(struct sway_workspace *workspace,
- bool no_auto_back_and_forth);
+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, bool create);
+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, bool create);
+struct sway_workspace *workspace_output_prev(struct sway_workspace *current);
struct sway_workspace *workspace_prev(struct sway_workspace *current);
@@ -113,13 +113,20 @@ void workspace_unwrap_children(struct sway_workspace *ws,
void workspace_detach(struct sway_workspace *workspace);
-void workspace_add_tiling(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);
-void workspace_insert_tiling(struct sway_workspace *workspace,
+/**
+ * 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);
@@ -135,4 +142,14 @@ 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);
+
#endif
diff --git a/include/swaybar/config.h b/include/swaybar/config.h
index 688fa2d71..4cacd21a4 100644
--- a/include/swaybar/config.h
+++ b/include/swaybar/config.h
@@ -38,6 +38,7 @@ struct swaybar_config {
bool binding_mode_indicator;
bool wrap_scroll;
bool workspace_buttons;
+ uint32_t workspace_min_width;
list_t *bindings;
struct wl_list outputs; // config_output::link
int height;
diff --git a/include/swaybar/i3bar.h b/include/swaybar/i3bar.h
index df8cdd097..1aec6d6c7 100644
--- a/include/swaybar/i3bar.h
+++ b/include/swaybar/i3bar.h
@@ -19,6 +19,7 @@ struct i3bar_block {
// Airblader features
uint32_t background;
uint32_t border;
+ bool border_set;
int border_top;
int border_bottom;
int border_left;
diff --git a/include/swaybar/tray/tray.h b/include/swaybar/tray/tray.h
index 8958b69aa..d2e80a6d4 100644
--- a/include/swaybar/tray/tray.h
+++ b/include/swaybar/tray/tray.h
@@ -2,10 +2,12 @@
#define _SWAYBAR_TRAY_TRAY_H
#include "config.h"
-#ifdef HAVE_SYSTEMD
+#if HAVE_LIBSYSTEMD
#include
-#elif HAVE_ELOGIND
+#elif HAVE_LIBELOGIND
#include
+#elif HAVE_BASU
+#include
#endif
#include
#include
diff --git a/include/swaynag/types.h b/include/swaynag/types.h
index 7f8f62212..3c3b2754a 100644
--- a/include/swaynag/types.h
+++ b/include/swaynag/types.h
@@ -7,9 +7,12 @@ struct swaynag_type {
char *font;
char *output;
uint32_t anchors;
+ int32_t layer; // enum zwlr_layer_shell_v1_layer or -1 if unset
// Colors
+ uint32_t button_text;
uint32_t button_background;
+ uint32_t details_background;
uint32_t background;
uint32_t text;
uint32_t border;
diff --git a/include/util.h b/include/util.h
index c80da1cbc..f887d4895 100644
--- a/include/util.h
+++ b/include/util.h
@@ -29,12 +29,6 @@ enum movement_unit parse_movement_unit(const char *unit);
int parse_movement_amount(int argc, char **argv,
struct movement_amount *amount);
-/**
- * Get the current time, in milliseconds.
- */
-
-uint32_t get_current_time_msec(void);
-
/**
* Wrap i into the range [0, max]
*/
diff --git a/meson.build b/meson.build
index 372c6db0a..436b84d11 100644
--- a/meson.build
+++ b/meson.build
@@ -1,9 +1,9 @@
project(
'sway',
'c',
- version: '1.5', #release_version
+ version: '1.6',
license: 'MIT',
- meson_version: '>=0.53.0',
+ meson_version: '>=0.59.0',
default_options: [
'c_std=c11',
'warning_level=2',
@@ -35,32 +35,33 @@ if is_freebsd
add_project_arguments('-D_C11_SOURCE', language: 'c')
endif
-jsonc = dependency('json-c', version: '>=0.13')
-pcre = dependency('libpcre')
+jsonc = dependency('json-c', version: '>=0.13')
+pcre = dependency('libpcre')
wayland_server = dependency('wayland-server')
wayland_client = dependency('wayland-client')
wayland_cursor = dependency('wayland-cursor')
-wayland_egl = dependency('wayland-egl')
+wayland_egl = dependency('wayland-egl')
wayland_protos = dependency('wayland-protocols', version: '>=1.14')
-xkbcommon = dependency('xkbcommon')
-cairo = dependency('cairo')
-pango = dependency('pango')
-pangocairo = dependency('pangocairo')
-gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf'))
-pixman = dependency('pixman-1')
-glesv2 = dependency('glesv2')
-libevdev = dependency('libevdev')
-libinput = dependency('libinput', version: '>=1.6.0')
-systemd = dependency('libsystemd', version: '>=239', required: false)
-elogind = dependency('libelogind', version: '>=239', required: false)
-xcb = dependency('xcb', required: get_option('xwayland'))
-bash_comp = dependency('bash-completion', required: false)
-fish_comp = dependency('fish', required: false)
-math = cc.find_library('m')
-rt = cc.find_library('rt')
+xkbcommon = dependency('xkbcommon')
+cairo = dependency('cairo')
+pango = dependency('pango')
+pangocairo = dependency('pangocairo')
+gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf'))
+pixman = dependency('pixman-1')
+glesv2 = dependency('glesv2')
+libevdev = dependency('libevdev')
+libinput = dependency('libinput', version: '>=1.6.0')
+xcb = dependency('xcb', required: get_option('xwayland'))
+drm_full = dependency('libdrm') # only needed for drm_fourcc.h
+drm = drm_full.partial_dependency(compile_args: true, includes: true)
+libudev = dependency('libudev')
+bash_comp = dependency('bash-completion', required: false)
+fish_comp = dependency('fish', required: false)
+math = cc.find_library('m')
+rt = cc.find_library('rt')
# Try first to find wlroots as a subproject, then as a system dependency
-wlroots_version = ['>=0.11.0', '<0.12.0']
+wlroots_version = ['>=0.15.0', '<0.16.0']
wlroots_proj = subproject(
'wlroots',
default_options: ['examples=false'],
@@ -69,21 +70,50 @@ wlroots_proj = subproject(
)
if wlroots_proj.found()
wlroots = wlroots_proj.get_variable('wlroots')
- wlroots_conf = wlroots_proj.get_variable('conf_data')
- wlroots_has_xwayland = wlroots_conf.get('WLR_HAS_XWAYLAND') == 1
else
wlroots = dependency('wlroots', version: wlroots_version)
- wlroots_has_xwayland = cc.get_define('WLR_HAS_XWAYLAND', prefix: '#include ', dependencies: wlroots) == '1'
endif
-if get_option('xwayland').enabled() and not wlroots_has_xwayland
+wlroots_features = {
+ 'xwayland': false,
+}
+foreach name, _ : wlroots_features
+ var_name = 'have_' + name.underscorify()
+ have = wlroots.get_variable(pkgconfig: var_name, internal: var_name) == 'true'
+ wlroots_features += { name: have }
+endforeach
+
+if get_option('xwayland').enabled() and not wlroots_features['xwayland']
error('Cannot enable Xwayland in sway: wlroots has been built without Xwayland support')
endif
-have_xwayland = xcb.found() and wlroots_has_xwayland
+have_xwayland = xcb.found() and wlroots_features['xwayland']
-tray_deps_found = systemd.found() or elogind.found()
+if get_option('sd-bus-provider') == 'auto'
+ if not get_option('tray').disabled()
+ assert(get_option('auto_features').auto(), 'sd-bus-provider must not be set to auto since auto_features != auto')
+ endif
+ sdbus = dependency('libsystemd',
+ required: false,
+ version: '>=239',
+ not_found_message: 'libsystemd not found, trying libelogind',
+ )
+ if not sdbus.found()
+ sdbus = dependency('libelogind',
+ required: false,
+ version: '>=239',
+ not_found_message: 'libelogind not found, trying basu',
+ )
+ endif
+ if not sdbus.found()
+ sdbus = dependency('basu', required: false)
+ endif
+else
+ sdbus = dependency(get_option('sd-bus-provider'), required: get_option('tray'))
+endif
+
+tray_deps_found = sdbus.found()
if get_option('tray').enabled() and not tray_deps_found
- error('Building with -Dtray=enabled, but libsystemd and libelogind have not been not found')
+ error('Building with -Dtray=enabled, but sd-bus has not been not found')
endif
have_tray = (not get_option('tray').disabled()) and tray_deps_found
@@ -91,14 +121,14 @@ conf_data = configuration_data()
conf_data.set10('HAVE_XWAYLAND', have_xwayland)
conf_data.set10('HAVE_GDK_PIXBUF', gdk_pixbuf.found())
-conf_data.set10('HAVE_SYSTEMD', systemd.found())
-conf_data.set10('HAVE_ELOGIND', elogind.found())
+conf_data.set10('HAVE_LIBSYSTEMD', sdbus.found() and sdbus.name() == 'libsystemd')
+conf_data.set10('HAVE_LIBELOGIND', sdbus.found() and sdbus.name() == 'libelogind')
+conf_data.set10('HAVE_BASU', sdbus.found() and sdbus.name() == 'basu')
conf_data.set10('HAVE_TRAY', have_tray)
scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: get_option('man-pages'))
if scdoc.found()
- scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true)
- sh = find_program('sh', native: true)
+ scdoc_prog = find_program(scdoc.get_variable(pkgconfig: 'scdoc'), native: true)
mandir = get_option('mandir')
man_files = [
'sway/sway.1.scd',
@@ -109,9 +139,15 @@ if scdoc.found()
'sway/sway-output.5.scd',
'swaybar/swaybar-protocol.7.scd',
'swaymsg/swaymsg.1.scd',
- 'swaynag/swaynag.1.scd',
- 'swaynag/swaynag.5.scd',
]
+
+ if get_option('swaynag')
+ man_files += [
+ 'swaynag/swaynag.1.scd',
+ 'swaynag/swaynag.5.scd',
+ ]
+ endif
+
foreach filename : man_files
topic = filename.split('.')[-3].split('/')[-1]
section = filename.split('.')[-2]
@@ -121,10 +157,10 @@ if scdoc.found()
output,
input: filename,
output: output,
- command: [
- sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output)
- ],
+ command: scdoc_prog,
install: true,
+ feed: true,
+ capture: true,
install_dir: '@0@/man@1@'.format(mandir, section)
)
endforeach
@@ -149,7 +185,7 @@ add_project_arguments('-DSWAY_VERSION=@0@'.format(version), language: 'c')
# Compute the relative path used by compiler invocations.
source_root = meson.current_source_dir().split('/')
-build_root = meson.build_root().split('/')
+build_root = meson.global_build_root().split('/')
relative_dir_parts = []
i = 0
in_prefix = true
@@ -193,9 +229,15 @@ subdir('common')
subdir('sway')
subdir('swaymsg')
-subdir('client')
-subdir('swaybar')
-subdir('swaynag')
+if get_option('swaybar') or get_option('swaynag')
+ subdir('client')
+endif
+if get_option('swaybar')
+ subdir('swaybar')
+endif
+if get_option('swaynag')
+ subdir('swaynag')
+endif
config = configuration_data()
config.set('datadir', join_paths(prefix, datadir))
@@ -243,13 +285,17 @@ endif
if get_option('bash-completions')
bash_files = files(
'completions/bash/sway',
- 'completions/bash/swaybar',
'completions/bash/swaymsg',
)
+
+ if get_option('swaybar')
+ bash_files += files('completions/bash/swaybar')
+ endif
+
if bash_comp.found()
- bash_install_dir = bash_comp.get_pkgconfig_variable(
- 'completionsdir',
- define_variable: ['datadir', datadir]
+ bash_install_dir = bash_comp.get_variable(
+ pkgconfig: 'completionsdir',
+ pkgconfig_define: ['datadir', datadir]
)
else
bash_install_dir = join_paths(datadir, 'bash-completion', 'completions')
@@ -262,12 +308,16 @@ if get_option('fish-completions')
fish_files = files(
'completions/fish/sway.fish',
'completions/fish/swaymsg.fish',
- 'completions/fish/swaynag.fish',
)
+
+ if get_option('swaynag')
+ fish_files += files('completions/fish/swaynag.fish')
+ endif
+
if fish_comp.found()
- fish_install_dir = fish_comp.get_pkgconfig_variable(
- 'completionsdir',
- define_variable: ['datadir', datadir]
+ fish_install_dir = fish_comp.get_variable(
+ pkgconfig: 'completionsdir',
+ pkgconfig_define: ['datadir', datadir]
)
else
fish_install_dir = join_paths(datadir, 'fish', 'vendor_completions.d')
@@ -279,13 +329,7 @@ endif
summary({
'xwayland': have_xwayland,
'gdk-pixbuf': gdk_pixbuf.found(),
- 'systemd': systemd.found(),
- 'elogind': elogind.found(),
'tray': have_tray,
'man-pages': scdoc.found(),
}, bool_yn: true)
-if not systemd.found() and not elogind.found()
- warning('The sway binary must be setuid when compiled without (e)logind')
- warning('You must do this manually post-install: chmod a+s /path/to/sway')
-endif
diff --git a/meson_options.txt b/meson_options.txt
index d3667acfd..6ba675546 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -2,7 +2,10 @@ option('default-wallpaper', type: 'boolean', value: true, description: 'Install
option('zsh-completions', type: 'boolean', value: true, description: 'Install zsh shell completions.')
option('bash-completions', type: 'boolean', value: true, description: 'Install bash shell completions.')
option('fish-completions', type: 'boolean', value: true, description: 'Install fish shell completions.')
+option('swaybar', type: 'boolean', value: true, description: 'Enable support for swaybar')
+option('swaynag', type: 'boolean', value: true, description: 'Enable support for swaynag')
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
option('tray', type: 'feature', value: 'auto', description: 'Enable support for swaybar tray')
option('gdk-pixbuf', type: 'feature', value: 'auto', description: 'Enable support for more image formats in swaybg')
option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages')
+option('sd-bus-provider', type: 'combo', choices: ['auto', 'libsystemd', 'libelogind', 'basu'], value: 'auto', description: 'Provider of the sd-bus library')
diff --git a/protocols/meson.build b/protocols/meson.build
index 124e97777..8e9e65be1 100644
--- a/protocols/meson.build
+++ b/protocols/meson.build
@@ -1,9 +1,9 @@
-wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir')
+wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
wayland_scanner_dep = dependency('wayland-scanner', required: false, native: true)
if wayland_scanner_dep.found()
wayland_scanner = find_program(
- wayland_scanner_dep.get_pkgconfig_variable('wayland_scanner'),
+ wayland_scanner_dep.get_variable(pkgconfig: 'wayland_scanner'),
native: true,
)
else
diff --git a/protocols/wlr-layer-shell-unstable-v1.xml b/protocols/wlr-layer-shell-unstable-v1.xml
index fa67001df..d62fd51e9 100644
--- a/protocols/wlr-layer-shell-unstable-v1.xml
+++ b/protocols/wlr-layer-shell-unstable-v1.xml
@@ -25,7 +25,7 @@
THIS SOFTWARE.
-
+
Clients can use this interface to assign the surface_layer role to
wl_surfaces. Such surfaces are assigned to a "layer" of the output and
@@ -47,6 +47,12 @@
or manipulate a buffer prior to the first layer_surface.configure call
must also be treated as errors.
+ After creating a layer_surface object and setting it up, the client
+ must perform an initial commit without any buffer attached.
+ The compositor will reply with a layer_surface.configure event.
+ The client must acknowledge it and is then allowed to attach a buffer
+ to map the surface.
+
You may pass NULL for output to allow the compositor to decide which
output to use. Generally this will be the one that the user most
recently interacted with.
@@ -94,7 +100,7 @@
-
+
An interface that may be implemented by a wl_surface, for surfaces that
are designed to be rendered as a layer of a stacked desktop-like
@@ -103,6 +109,14 @@
Layer surface state (layer, size, anchor, exclusive zone,
margin, interactivity) is double-buffered, and will be applied at the
time wl_surface.commit of the corresponding wl_surface is called.
+
+ Attaching a null buffer to a layer surface unmaps it.
+
+ Unmapping a layer_surface means that the surface cannot be shown by the
+ compositor until it is explicitly mapped again. The layer_surface
+ returns to the state it had right after layer_shell.get_layer_surface.
+ The client can re-map the surface by performing a commit without any
+ buffer attached, waiting for a configure event and handling it as usual.
@@ -189,21 +203,85 @@
+
+
+ Types of keyboard interaction possible for layer shell surfaces. The
+ rationale for this is twofold: (1) some applications are not interested
+ in keyboard events and not allowing them to be focused can improve the
+ desktop experience; (2) some applications will want to take exclusive
+ keyboard focus.
+
+
+
+
+ This value indicates that this surface is not interested in keyboard
+ events and the compositor should never assign it the keyboard focus.
+
+ This is the default value, set for newly created layer shell surfaces.
+
+ This is useful for e.g. desktop widgets that display information or
+ only have interaction with non-keyboard input devices.
+
+
+
+
+ Request exclusive keyboard focus if this surface is above the shell surface layer.
+
+ For the top and overlay layers, the seat will always give
+ exclusive keyboard focus to the top-most layer which has keyboard
+ interactivity set to exclusive. If this layer contains multiple
+ surfaces with keyboard interactivity set to exclusive, the compositor
+ determines the one receiving keyboard events in an implementation-
+ defined manner. In this case, no guarantee is made when this surface
+ will receive keyboard focus (if ever).
+
+ For the bottom and background layers, the compositor is allowed to use
+ normal focus semantics.
+
+ This setting is mainly intended for applications that need to ensure
+ they receive all keyboard events, such as a lock screen or a password
+ prompt.
+
+
+
+
+ This requests the compositor to allow this surface to be focused and
+ unfocused by the user in an implementation-defined manner. The user
+ should be able to unfocus this surface even regardless of the layer
+ it is on.
+
+ Typically, the compositor will want to use its normal mechanism to
+ manage keyboard focus between layer shell surfaces with this setting
+ and regular toplevels on the desktop layer (e.g. click to focus).
+ Nevertheless, it is possible for a compositor to require a special
+ interaction to focus or unfocus layer shell surfaces (e.g. requiring
+ a click even if focus follows the mouse normally, or providing a
+ keybinding to switch focus between layers).
+
+ This setting is mainly intended for desktop shell components (e.g.
+ panels) that allow keyboard interaction. Using this option can allow
+ implementing a desktop shell that can be fully usable without the
+ mouse.
+
+
+
+
- Set to 1 to request that the seat send keyboard events to this layer
- surface. For layers below the shell surface layer, the seat will use
- normal focus semantics. For layers above the shell surface layers, the
- seat will always give exclusive keyboard focus to the top-most layer
- which has keyboard interactivity set to true.
+ Set how keyboard events are delivered to this surface. By default,
+ layer shell surfaces do not receive keyboard events; this request can
+ be used to change this.
+
+ This setting is inherited by child surfaces set by the get_popup
+ request.
Layer surfaces receive pointer, touch, and tablet events normally. If
you do not want to receive them, set the input region on your surface
to an empty region.
- Events is double-buffered, see wl_surface.commit.
+ Keyboard interactivity is double-buffered, see wl_surface.commit.
-
+
@@ -288,6 +366,7 @@
+
diff --git a/sway/commands.c b/sway/commands.c
index fe1e98b53..205406ad2 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -42,7 +42,7 @@ struct cmd_results *checkarg(int argc, const char *name, enum expected_args type
}
/* Keep alphabetized */
-static struct cmd_handler handlers[] = {
+static const struct cmd_handler handlers[] = {
{ "assign", cmd_assign },
{ "bar", cmd_bar },
{ "bindcode", cmd_bindcode },
@@ -98,7 +98,7 @@ static struct cmd_handler handlers[] = {
};
/* Config-time only commands. Keep alphabetized */
-static struct cmd_handler config_handlers[] = {
+static const struct cmd_handler config_handlers[] = {
{ "default_orientation", cmd_default_orientation },
{ "include", cmd_include },
{ "swaybg_command", cmd_swaybg_command },
@@ -108,7 +108,7 @@ static struct cmd_handler config_handlers[] = {
};
/* Runtime-only commands. Keep alphabetized */
-static struct cmd_handler command_handlers[] = {
+static const struct cmd_handler command_handlers[] = {
{ "border", cmd_border },
{ "create_output", cmd_create_output },
{ "exit", cmd_exit },
@@ -144,22 +144,22 @@ static int handler_compare(const void *_a, const void *_b) {
return strcasecmp(a->command, b->command);
}
-struct cmd_handler *find_handler(char *line, struct cmd_handler *handlers,
- size_t handlers_size) {
+const struct cmd_handler *find_handler(char *line,
+ const struct cmd_handler *handlers, size_t handlers_size) {
if (!handlers || !handlers_size) {
return NULL;
}
- struct cmd_handler query = { .command = line };
+ const struct cmd_handler query = { .command = line };
return bsearch(&query, handlers,
handlers_size / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
}
-static struct cmd_handler *find_handler_ex(char *line,
- struct cmd_handler *config_handlers, size_t config_handlers_size,
- struct cmd_handler *command_handlers, size_t command_handlers_size,
- struct cmd_handler *handlers, size_t handlers_size) {
- struct cmd_handler *handler = NULL;
+static const struct cmd_handler *find_handler_ex(char *line,
+ const struct cmd_handler *config_handlers, size_t config_handlers_size,
+ const struct cmd_handler *command_handlers, size_t command_handlers_size,
+ const struct cmd_handler *handlers, size_t handlers_size) {
+ const struct cmd_handler *handler = NULL;
if (config->reading) {
handler = find_handler(line, config_handlers, config_handlers_size);
} else if (config->active) {
@@ -168,16 +168,17 @@ static struct cmd_handler *find_handler_ex(char *line,
return handler ? handler : find_handler(line, handlers, handlers_size);
}
-static struct cmd_handler *find_core_handler(char *line) {
+static const struct cmd_handler *find_core_handler(char *line) {
return find_handler_ex(line, config_handlers, sizeof(config_handlers),
command_handlers, sizeof(command_handlers),
handlers, sizeof(handlers));
}
-static void set_config_node(struct sway_node *node) {
+static void set_config_node(struct sway_node *node, bool node_overridden) {
config->handler_context.node = node;
config->handler_context.container = NULL;
config->handler_context.workspace = NULL;
+ config->handler_context.node_overridden = node_overridden;
if (node == NULL) {
return;
@@ -186,7 +187,7 @@ static void set_config_node(struct sway_node *node) {
switch (node->type) {
case N_CONTAINER:
config->handler_context.container = node->sway_container;
- config->handler_context.workspace = node->sway_container->workspace;
+ config->handler_context.workspace = node->sway_container->pending.workspace;
break;
case N_WORKSPACE:
config->handler_context.workspace = node->sway_workspace;
@@ -202,6 +203,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
char *cmd;
char matched_delim = ';';
list_t *containers = NULL;
+ bool using_criteria = false;
if (seat == NULL) {
// passing a NULL seat means we just pick the default seat
@@ -225,7 +227,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
for (; isspace(*head); ++head) {}
// Extract criteria (valid for this command list only).
if (matched_delim == ';') {
- config->handler_context.using_criteria = false;
+ using_criteria = false;
if (*head == '[') {
char *error = NULL;
struct criteria *criteria = criteria_parse(head, &error);
@@ -239,7 +241,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
containers = criteria_get_containers(criteria);
head += strlen(criteria->raw);
criteria_destroy(criteria);
- config->handler_context.using_criteria = true;
+ using_criteria = true;
// Skip leading whitespace
for (; isspace(*head); ++head) {}
}
@@ -265,7 +267,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
}
}
}
- struct cmd_handler *handler = find_core_handler(argv[0]);
+ const struct cmd_handler *handler = find_core_handler(argv[0]);
if (!handler) {
list_add(res_list, cmd_results_new(CMD_INVALID,
"Unknown/invalid command '%s'", argv[0]));
@@ -278,11 +280,14 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
argv[i] = do_var_replacement(argv[i]);
}
- if (!config->handler_context.using_criteria) {
- // The container or workspace which this command will run on.
- struct sway_node *node = con ? &con->node :
- seat_get_focus_inactive(seat, &root->node);
- set_config_node(node);
+
+ if (!using_criteria) {
+ if (con) {
+ set_config_node(&con->node, true);
+ } else {
+ set_config_node(seat_get_focus_inactive(seat, &root->node),
+ false);
+ }
struct cmd_results *res = handler->handle(argc-1, argv+1);
list_add(res_list, res);
if (res->status == CMD_INVALID) {
@@ -296,7 +301,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
struct cmd_results *fail_res = NULL;
for (int i = 0; i < containers->length; ++i) {
struct sway_container *container = containers->items[i];
- set_config_node(&container->node);
+ set_config_node(&container->node, true);
struct cmd_results *res = handler->handle(argc-1, argv+1);
if (res->status == CMD_SUCCESS) {
free_cmd_results(res);
@@ -370,7 +375,7 @@ struct cmd_results *config_command(char *exec, char **new_block) {
// Determine the command handler
sway_log(SWAY_INFO, "Config command: %s", exec);
- struct cmd_handler *handler = find_core_handler(argv[0]);
+ const struct cmd_handler *handler = find_core_handler(argv[0]);
if (!handler || !handler->handle) {
const char *error = handler
? "Command '%s' is shimmed, but unimplemented"
@@ -418,12 +423,12 @@ cleanup:
}
struct cmd_results *config_subcommand(char **argv, int argc,
- struct cmd_handler *handlers, size_t handlers_size) {
+ const struct cmd_handler *handlers, size_t handlers_size) {
char *command = join_args(argv, argc);
sway_log(SWAY_DEBUG, "Subcommand: %s", command);
free(command);
- struct cmd_handler *handler = find_handler(argv[0], handlers,
+ const struct cmd_handler *handler = find_handler(argv[0], handlers,
handlers_size);
if (!handler) {
return cmd_results_new(CMD_INVALID,
@@ -453,41 +458,13 @@ struct cmd_results *config_commands_command(char *exec) {
goto cleanup;
}
- struct cmd_handler *handler = find_handler(cmd, NULL, 0);
+ const struct cmd_handler *handler = find_handler(cmd, NULL, 0);
if (!handler && strcmp(cmd, "*") != 0) {
results = cmd_results_new(CMD_INVALID,
"Unknown/invalid command '%s'", cmd);
goto cleanup;
}
- enum command_context context = 0;
-
- struct {
- char *name;
- enum command_context context;
- } context_names[] = {
- { "config", CONTEXT_CONFIG },
- { "binding", CONTEXT_BINDING },
- { "ipc", CONTEXT_IPC },
- { "criteria", CONTEXT_CRITERIA },
- { "all", CONTEXT_ALL },
- };
-
- for (int i = 1; i < argc; ++i) {
- size_t j;
- for (j = 0; j < sizeof(context_names) / sizeof(context_names[0]); ++j) {
- if (strcmp(context_names[j].name, argv[i]) == 0) {
- break;
- }
- }
- if (j == sizeof(context_names) / sizeof(context_names[0])) {
- results = cmd_results_new(CMD_INVALID,
- "Invalid command context %s", argv[i]);
- goto cleanup;
- }
- context |= context_names[j].context;
- }
-
results = cmd_results_new(CMD_SUCCESS, NULL);
cleanup:
diff --git a/sway/commands/bar.c b/sway/commands/bar.c
index 7370910d2..8571d282c 100644
--- a/sway/commands/bar.c
+++ b/sway/commands/bar.c
@@ -8,7 +8,7 @@
#include "log.h"
// Must be in alphabetical order for bsearch
-static struct cmd_handler bar_handlers[] = {
+static const struct cmd_handler bar_handlers[] = {
{ "bindcode", bar_cmd_bindcode },
{ "binding_mode_indicator", bar_cmd_binding_mode_indicator },
{ "bindsym", bar_cmd_bindsym },
@@ -36,11 +36,12 @@ static struct cmd_handler bar_handlers[] = {
{ "unbindcode", bar_cmd_unbindcode },
{ "unbindsym", bar_cmd_unbindsym },
{ "workspace_buttons", bar_cmd_workspace_buttons },
+ { "workspace_min_width", bar_cmd_workspace_min_width },
{ "wrap_scroll", bar_cmd_wrap_scroll },
};
// Must be in alphabetical order for bsearch
-static struct cmd_handler bar_config_handlers[] = {
+static const struct cmd_handler bar_config_handlers[] = {
{ "id", bar_cmd_id },
{ "swaybar_command", bar_cmd_swaybar_command },
};
@@ -115,6 +116,7 @@ struct cmd_results *cmd_bar(int argc, char **argv) {
if (res && res->status != CMD_SUCCESS) {
if (id) {
free_bar_config(config->current_bar);
+ config->current_bar = NULL;
id = NULL;
}
return res;
diff --git a/sway/commands/bar/colors.c b/sway/commands/bar/colors.c
index 2d5b22bf6..275fa3c64 100644
--- a/sway/commands/bar/colors.c
+++ b/sway/commands/bar/colors.c
@@ -4,7 +4,7 @@
#include "util.h"
// Must be in alphabetical order for bsearch
-static struct cmd_handler bar_colors_handlers[] = {
+static const struct cmd_handler bar_colors_handlers[] = {
{ "active_workspace", bar_colors_cmd_active_workspace },
{ "background", bar_colors_cmd_background },
{ "binding_mode", bar_colors_cmd_binding_mode },
diff --git a/sway/commands/bar/font.c b/sway/commands/bar/font.c
index 62987f3e3..891c87af8 100644
--- a/sway/commands/bar/font.c
+++ b/sway/commands/bar/font.c
@@ -11,7 +11,20 @@ struct cmd_results *bar_cmd_font(int argc, char **argv) {
}
char *font = join_args(argv, argc);
free(config->current_bar->font);
- config->current_bar->font = font;
+
+ if (strncmp(font, "pango:", 6) == 0) {
+ if (config->current_bar->pango_markup == PANGO_MARKUP_DEFAULT) {
+ config->current_bar->pango_markup = true;
+ }
+ config->current_bar->font = strdup(font + 6);
+ } else {
+ if (config->current_bar->pango_markup == PANGO_MARKUP_DEFAULT) {
+ config->current_bar->pango_markup = false;
+ }
+ config->current_bar->font = strdup(font);
+ }
+
+ free(font);
sway_log(SWAY_DEBUG, "Settings font '%s' for bar: %s",
config->current_bar->font, config->current_bar->id);
return cmd_results_new(CMD_SUCCESS, NULL);
diff --git a/sway/commands/bar/workspace_min_width.c b/sway/commands/bar/workspace_min_width.c
new file mode 100644
index 000000000..8d65592ca
--- /dev/null
+++ b/sway/commands/bar/workspace_min_width.c
@@ -0,0 +1,33 @@
+#include
+#include
+#include "config.h"
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_workspace_min_width(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "workspace_min_width", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+
+ struct bar_config *bar = config->current_bar;
+
+ char *end;
+ int min_width = strtol(argv[0], &end, 10);
+ if (min_width < 0 || (*end != '\0' && strcasecmp(end, "px") != 0)) {
+ return cmd_results_new(CMD_INVALID,
+ "[Bar %s] Invalid minimum workspace button width value: %s",
+ bar->id, argv[0]);
+ }
+
+ if (argc == 2 && strcasecmp(argv[1], "px") != 0) {
+ return cmd_results_new(CMD_INVALID,
+ "Expected 'workspace_min_width [px]'");
+ }
+
+ sway_log(SWAY_DEBUG, "[Bar %s] Setting minimum workspace button width to %d",
+ bar->id, min_width);
+ config->current_bar->workspace_min_width = min_width;
+ return cmd_results_new(CMD_SUCCESS, NULL);
+}
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index f6e58d991..25be415ea 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -8,6 +8,7 @@
#include
#include "sway/commands.h"
#include "sway/config.h"
+#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/input/keyboard.h"
#include "sway/ipc-server.h"
@@ -559,8 +560,8 @@ struct cmd_results *cmd_bind_or_unbind_switch(int argc, char **argv,
free_switch_binding(binding);
return cmd_results_new(CMD_FAILURE,
"Invalid %s command "
- "(expected switch state: unknown state %d)",
- bindtype, split->items[0]);
+ "(expected switch state: unknown state %s)",
+ bindtype, split->items[1]);
}
list_free_items_and_destroy(split);
@@ -642,6 +643,8 @@ void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding)
if (success) {
ipc_event_binding(binding);
}
+
+ transaction_commit_dirty();
}
/**
diff --git a/sway/commands/border.c b/sway/commands/border.c
index 647663acf..7818fc962 100644
--- a/sway/commands/border.c
+++ b/sway/commands/border.c
@@ -19,11 +19,11 @@ static void set_border(struct sway_container *con,
view_set_csd_from_server(con->view, false);
} else if (!con->view->using_csd && new_border == B_CSD) {
view_set_csd_from_server(con->view, true);
- con->saved_border = con->border;
+ con->saved_border = con->pending.border;
}
}
if (new_border != B_CSD || container_is_floating(con)) {
- con->border = new_border;
+ con->pending.border = new_border;
}
if (con->view) {
con->view->using_csd = new_border == B_CSD;
@@ -35,7 +35,7 @@ static void border_toggle(struct sway_container *con) {
set_border(con, B_NONE);
return;
}
- switch (con->border) {
+ switch (con->pending.border) {
case B_NONE:
set_border(con, B_PIXEL);
break;
@@ -88,7 +88,7 @@ struct cmd_results *cmd_border(int argc, char **argv) {
"or 'border pixel '");
}
if (argc == 2) {
- container->border_thickness = atoi(argv[1]);
+ container->pending.border_thickness = atoi(argv[1]);
}
if (container_is_floating(container)) {
diff --git a/sway/commands/exec.c b/sway/commands/exec.c
index 87d907162..2c6f3d2d5 100644
--- a/sway/commands/exec.c
+++ b/sway/commands/exec.c
@@ -5,12 +5,15 @@
#include "stringop.h"
struct cmd_results *cmd_exec(int argc, char **argv) {
- if (!config->active) return cmd_results_new(CMD_DEFER, NULL);
+ struct cmd_results *error = NULL;
+ if ((error = cmd_exec_validate(argc, argv))) {
+ return error;
+ }
if (config->reloading) {
char *args = join_args(argv, argc);
sway_log(SWAY_DEBUG, "Ignoring 'exec %s' due to reload", args);
free(args);
return cmd_results_new(CMD_SUCCESS, NULL);
}
- return cmd_exec_always(argc, argv);
+ return cmd_exec_process(argc, argv);
}
diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c
index a57242950..b35065c12 100644
--- a/sway/commands/exec_always.c
+++ b/sway/commands/exec_always.c
@@ -7,22 +7,27 @@
#include
#include "sway/commands.h"
#include "sway/config.h"
+#include "sway/server.h"
#include "sway/tree/container.h"
#include "sway/tree/root.h"
#include "sway/tree/workspace.h"
#include "log.h"
#include "stringop.h"
-struct cmd_results *cmd_exec_always(int argc, char **argv) {
+struct cmd_results *cmd_exec_validate(int argc, char **argv) {
struct cmd_results *error = NULL;
- if (!config->active || config->validating) {
- return cmd_results_new(CMD_DEFER, NULL);
- }
if ((error = checkarg(argc, argv[-1], EXPECTED_AT_LEAST, 1))) {
return error;
}
+ if (!config->active || config->validating) {
+ return cmd_results_new(CMD_DEFER, NULL);
+ }
+ return error;
+}
- char *tmp = NULL;
+struct cmd_results *cmd_exec_process(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ char *cmd = NULL;
if (strcmp(argv[0], "--no-startup-id") == 0) {
sway_log(SWAY_INFO, "exec switch '--no-startup-id' not supported, ignored.");
--argc; ++argv;
@@ -32,17 +37,12 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
}
if (argc == 1 && (argv[0][0] == '\'' || argv[0][0] == '"')) {
- tmp = strdup(argv[0]);
- strip_quotes(tmp);
+ cmd = strdup(argv[0]);
+ strip_quotes(cmd);
} else {
- tmp = join_args(argv, argc);
+ cmd = join_args(argv, argc);
}
- // Put argument into cmd array
- char cmd[4096];
- strncpy(cmd, tmp, sizeof(cmd) - 1);
- cmd[sizeof(cmd) - 1] = 0;
- free(tmp);
sway_log(SWAY_DEBUG, "Executing %s", cmd);
int fd[2];
@@ -54,15 +54,18 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
// Fork process
if ((pid = fork()) == 0) {
// Fork child process again
+ restore_nofile_limit();
setsid();
sigset_t set;
sigemptyset(&set);
sigprocmask(SIG_SETMASK, &set, NULL);
+ signal(SIGPIPE, SIG_DFL);
close(fd[0]);
if ((child = fork()) == 0) {
close(fd[1]);
- execl("/bin/sh", "/bin/sh", "-c", cmd, (void *)NULL);
- _exit(0);
+ execlp("sh", "sh", "-c", cmd, (void *)NULL);
+ sway_log_errno(SWAY_ERROR, "execlp failed");
+ _exit(1);
}
ssize_t s = 0;
while ((size_t)s < sizeof(pid_t)) {
@@ -71,10 +74,12 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
close(fd[1]);
_exit(0); // Close child process
} else if (pid < 0) {
+ free(cmd);
close(fd[0]);
close(fd[1]);
return cmd_results_new(CMD_FAILURE, "fork() failed");
}
+ free(cmd);
close(fd[1]); // close write
ssize_t s = 0;
while ((size_t)s < sizeof(pid_t)) {
@@ -92,3 +97,11 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
return cmd_results_new(CMD_SUCCESS, NULL);
}
+
+struct cmd_results *cmd_exec_always(int argc, char **argv) {
+ struct cmd_results *error;
+ if ((error = cmd_exec_validate(argc, argv))) {
+ return error;
+ }
+ return cmd_exec_process(argc, argv);
+}
diff --git a/sway/commands/floating.c b/sway/commands/floating.c
index ce1233454..74f6522c7 100644
--- a/sway/commands/floating.c
+++ b/sway/commands/floating.c
@@ -40,8 +40,8 @@ struct cmd_results *cmd_floating(int argc, char **argv) {
// If the container is in a floating split container,
// operate on the split container instead of the child.
if (container_is_floating_or_child(container)) {
- while (container->parent) {
- container = container->parent;
+ while (container->pending.parent) {
+ container = container->pending.parent;
}
}
@@ -51,8 +51,8 @@ struct cmd_results *cmd_floating(int argc, char **argv) {
container_set_floating(container, wants_floating);
// Floating containers in the scratchpad should be ignored
- if (container->workspace) {
- arrange_workspace(container->workspace);
+ if (container->pending.workspace) {
+ arrange_workspace(container->pending.workspace);
}
return cmd_results_new(CMD_SUCCESS, NULL);
diff --git a/sway/commands/focus.c b/sway/commands/focus.c
index 56c3d981c..ceb43d455 100644
--- a/sway/commands/focus.c
+++ b/sway/commands/focus.c
@@ -141,9 +141,9 @@ static struct sway_node *node_get_in_direction_tiling(
struct sway_container *wrap_candidate = NULL;
struct sway_container *current = container;
while (current) {
- if (current->fullscreen_mode == FULLSCREEN_WORKSPACE) {
+ if (current->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) {
// Fullscreen container with a direction - go straight to outputs
- struct sway_output *output = current->workspace->output;
+ struct sway_output *output = current->pending.workspace->output;
struct sway_output *new_output =
output_get_in_direction(output, dir);
if (!new_output) {
@@ -151,7 +151,7 @@ static struct sway_node *node_get_in_direction_tiling(
}
return get_node_in_output_direction(new_output, dir);
}
- if (current->fullscreen_mode == FULLSCREEN_GLOBAL) {
+ if (current->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
return NULL;
}
@@ -202,11 +202,11 @@ static struct sway_node *node_get_in_direction_tiling(
}
}
- current = current->parent;
+ current = current->pending.parent;
}
// Check a different output
- struct sway_output *output = container->workspace->output;
+ struct sway_output *output = container->pending.workspace->output;
struct sway_output *new_output = output_get_in_direction(output, dir);
if ((config->focus_wrapping != WRAP_WORKSPACE ||
container->node.type == N_WORKSPACE) && new_output) {
@@ -226,23 +226,23 @@ static struct sway_node *node_get_in_direction_tiling(
static struct sway_node *node_get_in_direction_floating(
struct sway_container *con, struct sway_seat *seat,
enum wlr_direction dir) {
- double ref_lx = con->x + con->width / 2;
- double ref_ly = con->y + con->height / 2;
+ double ref_lx = con->pending.x + con->pending.width / 2;
+ double ref_ly = con->pending.y + con->pending.height / 2;
double closest_distance = DBL_MAX;
struct sway_container *closest_con = NULL;
- if (!con->workspace) {
+ if (!con->pending.workspace) {
return NULL;
}
- for (int i = 0; i < con->workspace->floating->length; i++) {
- struct sway_container *floater = con->workspace->floating->items[i];
+ for (int i = 0; i < con->pending.workspace->floating->length; i++) {
+ struct sway_container *floater = con->pending.workspace->floating->items[i];
if (floater == con) {
continue;
}
float distance = dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_RIGHT
- ? (floater->x + floater->width / 2) - ref_lx
- : (floater->y + floater->height / 2) - ref_ly;
+ ? (floater->pending.x + floater->pending.width / 2) - ref_lx
+ : (floater->pending.y + floater->pending.height / 2) - ref_ly;
if (dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_UP) {
distance = -distance;
}
@@ -267,8 +267,22 @@ static struct cmd_results *focus_mode(struct sway_workspace *ws,
new_focus = seat_get_focus_inactive_tiling(seat, ws);
}
if (new_focus) {
+ struct sway_container *new_focus_view =
+ seat_get_focus_inactive_view(seat, &new_focus->node);
+ if (new_focus_view) {
+ new_focus = new_focus_view;
+ }
seat_set_focus_container(seat, new_focus);
- seat_consider_warp_to_focus(seat);
+
+ // If we're on the floating layer and the floating container area
+ // overlaps the position on the tiling layer that would be warped to,
+ // `seat_consider_warp_to_focus` would decide not to warp, but we need
+ // to anyway.
+ if (config->mouse_warping == WARP_CONTAINER) {
+ cursor_warp_to_container(seat->cursor, new_focus, true);
+ } else {
+ seat_consider_warp_to_focus(seat);
+ }
} else {
return cmd_results_new(CMD_FAILURE,
"Failed to find a %s container in workspace",
@@ -325,7 +339,7 @@ static struct cmd_results *focus_output(struct sway_seat *seat,
static struct cmd_results *focus_parent(void) {
struct sway_seat *seat = config->handler_context.seat;
struct sway_container *con = config->handler_context.container;
- if (!con || con->fullscreen_mode) {
+ if (!con || con->pending.fullscreen_mode) {
return cmd_results_new(CMD_SUCCESS, NULL);
}
struct sway_node *parent = node_get_parent(&con->node);
@@ -368,6 +382,13 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
if (container_is_scratchpad_hidden_or_child(container)) {
root_scratchpad_show(container);
}
+ // if we are switching to a container under a fullscreen window, we first
+ // need to exit fullscreen so that the newly focused container becomes visible
+ struct sway_container *obstructing = container_obstructing_fullscreen_container(container);
+ if (obstructing) {
+ container_fullscreen_disable(obstructing);
+ arrange_root();
+ }
seat_set_focus_container(seat, container);
seat_consider_warp_to_focus(seat);
container_raise_floating(container);
diff --git a/sway/commands/font.c b/sway/commands/font.c
index c54365b53..cea720f50 100644
--- a/sway/commands/font.c
+++ b/sway/commands/font.c
@@ -22,6 +22,6 @@ struct cmd_results *cmd_font(int argc, char **argv) {
}
free(font);
- config_update_font_height(true);
+ config_update_font_height();
return cmd_results_new(CMD_SUCCESS, NULL);
}
diff --git a/sway/commands/force_display_urgency_hint.c b/sway/commands/force_display_urgency_hint.c
index 3202fc43a..3d432cba9 100644
--- a/sway/commands/force_display_urgency_hint.c
+++ b/sway/commands/force_display_urgency_hint.c
@@ -1,5 +1,6 @@
#include "sway/commands.h"
#include "sway/config.h"
+#include
struct cmd_results *cmd_force_display_urgency_hint(int argc, char **argv) {
struct cmd_results *error = NULL;
@@ -8,13 +9,16 @@ struct cmd_results *cmd_force_display_urgency_hint(int argc, char **argv) {
return error;
}
- char *err;
- int timeout = (int)strtol(argv[0], &err, 10);
- if (*err) {
- if (strcmp(err, "ms") != 0) {
- return cmd_results_new(CMD_INVALID,
- "Expected 'force_display_urgency_hint ms'");
- }
+ errno = 0;
+ char *end;
+ int timeout = (int)strtol(argv[0], &end, 10);
+ if (errno || end == argv[0] || (*end && strcmp(end, "ms") != 0)) {
+ return cmd_results_new(CMD_INVALID, "timeout integer invalid");
+ }
+
+ if (argc > 1 && strcmp(argv[1], "ms") != 0) {
+ return cmd_results_new(CMD_INVALID,
+ "Expected 'force_display_urgency_hint [ms]'");
}
config->urgent_timeout = timeout > 0 ? timeout : 0;
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c
index 3392a7f7b..21c1e9a09 100644
--- a/sway/commands/fullscreen.c
+++ b/sway/commands/fullscreen.c
@@ -18,30 +18,19 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE,
"Can't run this command while there's no outputs connected.");
}
- struct sway_node *node = config->handler_context.node;
struct sway_container *container = config->handler_context.container;
- struct sway_workspace *workspace = config->handler_context.workspace;
- if (node->type == N_WORKSPACE && workspace->tiling->length == 0) {
- return cmd_results_new(CMD_FAILURE,
- "Can't fullscreen an empty workspace");
- }
- // If in the scratchpad, operate on the highest container
- if (container && !container->workspace) {
- while (container->parent) {
- container = container->parent;
- }
- }
-
- bool is_fullscreen = false;
- for (struct sway_container *curr = container; curr; curr = curr->parent) {
- if (curr->fullscreen_mode != FULLSCREEN_NONE) {
- container = curr;
- is_fullscreen = true;
- break;
+ if (!container) {
+ // If the focus is not a container, do nothing successfully
+ return cmd_results_new(CMD_SUCCESS, NULL);
+ } else if (!container->pending.workspace) {
+ // If in the scratchpad, operate on the highest container
+ while (container->pending.parent) {
+ container = container->pending.parent;
}
}
+ bool is_fullscreen = container->pending.fullscreen_mode != FULLSCREEN_NONE;
bool global = false;
bool enable = !is_fullscreen;
@@ -57,13 +46,6 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) {
global = strcasecmp(argv[1], "global") == 0;
}
- if (enable && node->type == N_WORKSPACE) {
- // Wrap the workspace's children in a container so we can fullscreen it
- container = workspace_wrap_children(workspace);
- workspace->layout = L_HORIZ;
- seat_set_focus_container(config->handler_context.seat, container);
- }
-
enum sway_fullscreen_mode mode = FULLSCREEN_NONE;
if (enable) {
mode = global ? FULLSCREEN_GLOBAL : FULLSCREEN_WORKSPACE;
diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c
index 021df843a..1deeb56e1 100644
--- a/sway/commands/gaps.c
+++ b/sway/commands/gaps.c
@@ -11,7 +11,8 @@
enum gaps_op {
GAPS_OP_SET,
GAPS_OP_ADD,
- GAPS_OP_SUBTRACT
+ GAPS_OP_SUBTRACT,
+ GAPS_OP_TOGGLE
};
struct gaps_data {
@@ -102,6 +103,9 @@ static void apply_gaps_op(int *prop, enum gaps_op op, int amount) {
case GAPS_OP_SUBTRACT:
*prop -= amount;
break;
+ case GAPS_OP_TOGGLE:
+ *prop = *prop ? 0 : amount;
+ break;
}
}
@@ -133,9 +137,9 @@ static void configure_gaps(struct sway_workspace *ws, void *_data) {
}
// gaps inner|outer|horizontal|vertical|top|right|bottom|left current|all
-// set|plus|minus
+// set|plus|minus|toggle
static const char expected_runtime[] = "'gaps inner|outer|horizontal|vertical|"
- "top|right|bottom|left current|all set|plus|minus '";
+ "top|right|bottom|left current|all set|plus|minus|toggle '";
static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4);
if (error) {
@@ -180,6 +184,8 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
data.operation = GAPS_OP_ADD;
} else if (strcasecmp(argv[2], "minus") == 0) {
data.operation = GAPS_OP_SUBTRACT;
+ } else if (strcasecmp(argv[2], "toggle") == 0) {
+ data.operation = GAPS_OP_TOGGLE;
} else {
return cmd_results_new(CMD_INVALID, "Expected %s", expected_runtime);
}
@@ -200,7 +206,7 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
}
// gaps inner|outer|| - sets defaults for workspaces
-// gaps inner|outer|| current|all set|plus|minus - runtime only
+// gaps inner|outer|| current|all set|plus|minus|toggle - runtime only
// = horizontal|vertical
// = top|right|bottom|left
struct cmd_results *cmd_gaps(int argc, char **argv) {
diff --git a/sway/commands/input.c b/sway/commands/input.c
index 53db9a16a..77acb671b 100644
--- a/sway/commands/input.c
+++ b/sway/commands/input.c
@@ -7,7 +7,7 @@
#include "stringop.h"
// must be in order for the bsearch
-static struct cmd_handler input_handlers[] = {
+static const struct cmd_handler input_handlers[] = {
{ "accel_profile", input_cmd_accel_profile },
{ "calibration_matrix", input_cmd_calibration_matrix },
{ "click_method", input_cmd_click_method },
@@ -29,6 +29,7 @@ static struct cmd_handler input_handlers[] = {
{ "scroll_method", input_cmd_scroll_method },
{ "tap", input_cmd_tap },
{ "tap_button_map", input_cmd_tap_button_map },
+ { "tool_mode", input_cmd_tool_mode },
{ "xkb_file", input_cmd_xkb_file },
{ "xkb_layout", input_cmd_xkb_layout },
{ "xkb_model", input_cmd_xkb_model },
@@ -39,7 +40,7 @@ static struct cmd_handler input_handlers[] = {
};
// must be in order for the bsearch
-static struct cmd_handler input_config_handlers[] = {
+static const struct cmd_handler input_config_handlers[] = {
{ "xkb_capslock", input_cmd_xkb_capslock },
{ "xkb_numlock", input_cmd_xkb_numlock },
};
diff --git a/sway/commands/input/map_to_region.c b/sway/commands/input/map_to_region.c
index e85495e53..284b57d0c 100644
--- a/sway/commands/input/map_to_region.c
+++ b/sway/commands/input/map_to_region.c
@@ -1,7 +1,6 @@
#define _POSIX_C_SOURCE 200809L
#include
#include
-#include
#include "sway/commands.h"
#include "sway/config.h"
diff --git a/sway/commands/input/tool_mode.c b/sway/commands/input/tool_mode.c
new file mode 100644
index 000000000..04316857f
--- /dev/null
+++ b/sway/commands/input/tool_mode.c
@@ -0,0 +1,73 @@
+#include
+#include "sway/commands.h"
+#include "sway/config.h"
+
+static void set_tool_mode(struct input_config *ic,
+ enum wlr_tablet_tool_type type, enum sway_tablet_tool_mode mode) {
+ for (int i = 0; i < ic->tools->length; i++) {
+ struct input_config_tool *tool = ic->tools->items[i];
+ if (tool->type == type) {
+ tool->mode = mode;
+ return;
+ }
+ }
+
+ struct input_config_tool *tool = calloc(1, sizeof(*tool));
+ if (tool) {
+ tool->type = type;
+ tool->mode = mode;
+ list_add(ic->tools, tool);
+ }
+}
+
+struct cmd_results *input_cmd_tool_mode(int argc, char **argv) {
+ struct cmd_results *error;
+ if ((error = checkarg(argc, "tool_mode", EXPECTED_AT_LEAST, 2))) {
+ return error;
+ }
+
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
+ return cmd_results_new(CMD_FAILURE, "No input device defined.");
+ }
+
+ enum sway_tablet_tool_mode tool_mode;
+ if (!strcasecmp(argv[1], "absolute")) {
+ tool_mode = SWAY_TABLET_TOOL_MODE_ABSOLUTE;
+ } else if (!strcasecmp(argv[1], "relative")) {
+ tool_mode = SWAY_TABLET_TOOL_MODE_RELATIVE;
+ } else {
+ goto invalid_command;
+ }
+
+ if (!strcasecmp(argv[0], "*")) {
+ set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_PEN, tool_mode);
+ set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_ERASER, tool_mode);
+ set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_BRUSH, tool_mode);
+ set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_PENCIL, tool_mode);
+ set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_AIRBRUSH, tool_mode);
+ } else {
+ enum wlr_tablet_tool_type tool_type;
+ if (!strcasecmp(argv[0], "pen")) {
+ tool_type = WLR_TABLET_TOOL_TYPE_PEN;
+ } else if (!strcasecmp(argv[0], "eraser")) {
+ tool_type = WLR_TABLET_TOOL_TYPE_ERASER;
+ } else if (!strcasecmp(argv[0], "brush")) {
+ tool_type = WLR_TABLET_TOOL_TYPE_BRUSH;
+ } else if (!strcasecmp(argv[0], "pencil")) {
+ tool_type = WLR_TABLET_TOOL_TYPE_PENCIL;
+ } else if (!strcasecmp(argv[0], "airbrush")) {
+ tool_type = WLR_TABLET_TOOL_TYPE_AIRBRUSH;
+ } else {
+ goto invalid_command;
+ }
+
+ set_tool_mode(ic, tool_type, tool_mode);
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL);
+
+invalid_command:
+ return cmd_results_new(CMD_INVALID,
+ "Expected 'tool_mode '");
+}
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index 4b31b442e..2ba61b38e 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -133,7 +133,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
// Operate on parent container, like i3.
if (container) {
- container = container->parent;
+ container = container->pending.parent;
}
// We could be working with a container OR a workspace. These are different
@@ -142,10 +142,10 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
enum sway_container_layout new_layout = L_NONE;
enum sway_container_layout old_layout = L_NONE;
if (container) {
- old_layout = container->layout;
+ old_layout = container->pending.layout;
new_layout = get_layout(argc, argv,
- container->layout, container->prev_split_layout,
- container->workspace->output);
+ container->pending.layout, container->prev_split_layout,
+ container->pending.workspace->output);
} else {
old_layout = workspace->layout;
new_layout = get_layout(argc, argv,
@@ -160,7 +160,13 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
if (old_layout != L_TABBED && old_layout != L_STACKED) {
container->prev_split_layout = old_layout;
}
- container->layout = new_layout;
+ container->pending.layout = new_layout;
+ container_update_representation(container);
+ } else if (config->handler_context.container) {
+ // i3 avoids changing workspace layouts with a new container
+ // https://github.com/i3/i3/blob/3cd1c45eba6de073bc4300eebb4e1cc1a0c4479a/src/con.c#L1817
+ container = workspace_wrap_children(workspace);
+ container->pending.layout = new_layout;
container_update_representation(container);
} else {
if (old_layout != L_TABBED && old_layout != L_STACKED) {
diff --git a/sway/commands/mode.c b/sway/commands/mode.c
index a5871dabe..e23e4ee4d 100644
--- a/sway/commands/mode.c
+++ b/sway/commands/mode.c
@@ -9,7 +9,7 @@
#include "stringop.h"
// Must be in order for the bsearch
-static struct cmd_handler mode_handlers[] = {
+static const struct cmd_handler mode_handlers[] = {
{ "bindcode", cmd_bindcode },
{ "bindswitch", cmd_bindswitch },
{ "bindsym", cmd_bindsym },
diff --git a/sway/commands/move.c b/sway/commands/move.c
index c1d1fade6..f2702fa17 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -113,38 +113,41 @@ static void container_move_to_container_from_direction(
struct sway_container *container, struct sway_container *destination,
enum wlr_direction move_dir) {
if (destination->view) {
- if (destination->parent == container->parent &&
- destination->workspace == container->workspace) {
+ if (destination->pending.parent == container->pending.parent &&
+ destination->pending.workspace == container->pending.workspace) {
sway_log(SWAY_DEBUG, "Swapping siblings");
list_t *siblings = container_get_siblings(container);
int container_index = list_find(siblings, container);
int destination_index = list_find(siblings, destination);
list_swap(siblings, container_index, destination_index);
+ container_update_representation(container);
} else {
sway_log(SWAY_DEBUG, "Promoting to sibling of cousin");
int offset =
move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_UP;
int index = container_sibling_index(destination) + offset;
- if (destination->parent) {
- container_insert_child(destination->parent, container, index);
+ if (destination->pending.parent) {
+ container_insert_child(destination->pending.parent, container, index);
} else {
- workspace_insert_tiling(destination->workspace,
+ workspace_insert_tiling(destination->pending.workspace,
container, index);
}
- container->width = container->height = 0;
+ container->pending.width = container->pending.height = 0;
container->width_fraction = container->height_fraction = 0;
+ workspace_squash(destination->pending.workspace);
}
return;
}
- if (is_parallel(destination->layout, move_dir)) {
+ if (is_parallel(destination->pending.layout, move_dir)) {
sway_log(SWAY_DEBUG, "Reparenting container (parallel)");
int index =
move_dir == WLR_DIRECTION_RIGHT || move_dir == WLR_DIRECTION_DOWN ?
- 0 : destination->children->length;
+ 0 : destination->pending.children->length;
container_insert_child(destination, container, index);
- container->width = container->height = 0;
+ container->pending.width = container->pending.height = 0;
container->width_fraction = container->height_fraction = 0;
+ workspace_squash(destination->pending.workspace);
return;
}
@@ -165,7 +168,7 @@ static void container_move_to_container_from_direction(
static void container_move_to_workspace_from_direction(
struct sway_container *container, struct sway_workspace *workspace,
enum wlr_direction move_dir) {
- container->width = container->height = 0;
+ container->pending.width = container->pending.height = 0;
container->width_fraction = container->height_fraction = 0;
if (is_parallel(workspace->layout, move_dir)) {
@@ -185,8 +188,8 @@ static void container_move_to_workspace_from_direction(
workspace_add_tiling(workspace, container);
return;
}
- while (focus_inactive->parent) {
- focus_inactive = focus_inactive->parent;
+ while (focus_inactive->pending.parent) {
+ focus_inactive = focus_inactive->pending.parent;
}
container_move_to_container_from_direction(container, focus_inactive,
move_dir);
@@ -194,25 +197,25 @@ static void container_move_to_workspace_from_direction(
static void container_move_to_workspace(struct sway_container *container,
struct sway_workspace *workspace) {
- if (container->workspace == workspace) {
+ if (container->pending.workspace == workspace) {
return;
}
- struct sway_workspace *old_workspace = container->workspace;
+ struct sway_workspace *old_workspace = container->pending.workspace;
if (container_is_floating(container)) {
- struct sway_output *old_output = container->workspace->output;
+ struct sway_output *old_output = container->pending.workspace->output;
container_detach(container);
workspace_add_floating(workspace, container);
container_handle_fullscreen_reparent(container);
// If changing output, center it within the workspace
- if (old_output != workspace->output && !container->fullscreen_mode) {
+ if (old_output != workspace->output && !container->pending.fullscreen_mode) {
container_floating_move_to_center(container);
}
} else {
container_detach(container);
- if (workspace_is_empty(workspace) && container->children) {
+ if (workspace_is_empty(workspace) && container->pending.children) {
workspace_unwrap_children(workspace, container);
} else {
- container->width = container->height = 0;
+ container->pending.width = container->pending.height = 0;
container->width_fraction = container->height_fraction = 0;
workspace_add_tiling(workspace, container);
}
@@ -234,13 +237,13 @@ static void container_move_to_container(struct sway_container *container,
return;
}
if (container_is_floating(container)) {
- container_move_to_workspace(container, destination->workspace);
+ container_move_to_workspace(container, destination->pending.workspace);
return;
}
- struct sway_workspace *old_workspace = container->workspace;
+ struct sway_workspace *old_workspace = container->pending.workspace;
container_detach(container);
- container->width = container->height = 0;
+ container->pending.width = container->pending.height = 0;
container->width_fraction = container->height_fraction = 0;
if (destination->view) {
@@ -253,147 +256,154 @@ static void container_move_to_container(struct sway_container *container,
ipc_event_window(container, "move");
}
- if (destination->workspace) {
- workspace_focus_fullscreen(destination->workspace);
- workspace_detect_urgent(destination->workspace);
+ if (destination->pending.workspace) {
+ workspace_focus_fullscreen(destination->pending.workspace);
+ workspace_detect_urgent(destination->pending.workspace);
}
- if (old_workspace && old_workspace != destination->workspace) {
+ if (old_workspace && old_workspace != destination->pending.workspace) {
workspace_detect_urgent(old_workspace);
}
}
-/* Takes one child, sets it aside, wraps the rest of the children in a new
- * container, switches the layout of the workspace, and drops the child back in.
- * In other words, rejigger it. */
-static void workspace_rejigger(struct sway_workspace *ws,
- struct sway_container *child, enum wlr_direction move_dir) {
- if (!child->parent && ws->tiling->length == 1) {
- ws->layout =
- move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_RIGHT ?
- L_HORIZ : L_VERT;
- workspace_update_representation(ws);
- return;
+static bool container_move_to_next_output(struct sway_container *container,
+ struct sway_output *output, enum wlr_direction move_dir) {
+ struct sway_output *next_output =
+ output_get_in_direction(output, move_dir);
+ if (next_output) {
+ struct sway_workspace *ws = output_get_active_workspace(next_output);
+ if (!sway_assert(ws, "Expected output to have a workspace")) {
+ return false;
+ }
+ switch (container->pending.fullscreen_mode) {
+ case FULLSCREEN_NONE:
+ container_move_to_workspace_from_direction(container, ws, move_dir);
+ return true;
+ case FULLSCREEN_WORKSPACE:
+ container_move_to_workspace(container, ws);
+ return true;
+ case FULLSCREEN_GLOBAL:
+ return false;
+ }
}
- container_detach(child);
- workspace_wrap_children(ws);
-
- int index =
- move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_UP ? 0 : 1;
- workspace_insert_tiling(ws, child, index);
- ws->layout =
- move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_RIGHT ?
- L_HORIZ : L_VERT;
- workspace_update_representation(ws);
- child->width = child->height = 0;
+ return false;
}
// Returns true if moved
static bool container_move_in_direction(struct sway_container *container,
enum wlr_direction move_dir) {
// If moving a fullscreen view, only consider outputs
- if (container->fullscreen_mode == FULLSCREEN_WORKSPACE) {
- struct sway_output *new_output =
- output_get_in_direction(container->workspace->output, move_dir);
- if (!new_output) {
- return false;
- }
- struct sway_workspace *ws = output_get_active_workspace(new_output);
- if (!sway_assert(ws, "Expected output to have a workspace")) {
- return false;
- }
- container_move_to_workspace(container, ws);
- return true;
- }
- if (container->fullscreen_mode == FULLSCREEN_GLOBAL) {
+ switch (container->pending.fullscreen_mode) {
+ case FULLSCREEN_NONE:
+ break;
+ case FULLSCREEN_WORKSPACE:
+ return container_move_to_next_output(container,
+ container->pending.workspace->output, move_dir);
+ case FULLSCREEN_GLOBAL:
return false;
}
- // If container is in a split container by itself, move out of the split
- if (container->parent) {
- struct sway_container *new_parent =
- container_flatten(container->parent);
- if (new_parent != container->parent) {
- return true;
- }
- }
-
- // Look for a suitable *container* sibling or parent.
- // The below loop stops once we hit the workspace because current->parent
- // is NULL for the topmost containers in a workspace.
- struct sway_container *current = container;
int offs =
move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_UP ? -1 : 1;
+ int index = -1;
+ int desired = -1;
+ list_t *siblings = NULL;
+ struct sway_container *target = NULL;
- while (current) {
- list_t *siblings = container_get_siblings(current);
- if (siblings) {
- enum sway_container_layout layout = container_parent_layout(current);
- int index = list_find(siblings, current);
- int desired = index + offs;
+ // Look for a suitable ancestor of the container to move within
+ struct sway_container *ancestor = NULL;
+ struct sway_container *current = container;
+ bool wrapped = false;
+ while (!ancestor) {
+ // Don't allow containers to move out of their
+ // fullscreen or floating parent
+ if (current->pending.fullscreen_mode || container_is_floating(current)) {
+ return false;
+ }
- // Don't allow containers to move out of their
- // fullscreen or floating parent
- if (current->fullscreen_mode || container_is_floating(current)) {
- return false;
+ enum sway_container_layout parent_layout = container_parent_layout(current);
+ if (!is_parallel(parent_layout, move_dir)) {
+ if (!current->pending.parent) {
+ // No parallel parent, so we reorient the workspace
+ current = workspace_wrap_children(current->pending.workspace);
+ current->pending.workspace->layout =
+ move_dir == WLR_DIRECTION_LEFT ||
+ move_dir == WLR_DIRECTION_RIGHT ?
+ L_HORIZ : L_VERT;
+ container->pending.height = container->pending.width = 0;
+ container->height_fraction = container->width_fraction = 0;
+ workspace_update_representation(current->pending.workspace);
+ wrapped = true;
+ } else {
+ // Keep looking for a parallel parent
+ current = current->pending.parent;
}
+ continue;
+ }
- if (is_parallel(layout, move_dir)) {
- if (desired == -1 || desired == siblings->length) {
- if (current->parent == container->parent) {
- current = current->parent;
- continue;
- } else {
- // Reparenting
- if (current->parent) {
- container_insert_child(current->parent, container,
- index + (offs < 0 ? 0 : 1));
- } else {
- struct sway_workspace *ws = current->workspace;
- workspace_insert_tiling(ws,
- container_split(container,
- output_get_default_layout(ws->output)),
- index + (offs < 0 ? 0 : 1));
- }
- return true;
- }
- } else {
- // Container can move within its siblings
- container_move_to_container_from_direction(container,
- siblings->items[desired], move_dir);
- return true;
- }
+ // Only scratchpad hidden containers don't have siblings
+ // so siblings != NULL here
+ siblings = container_get_siblings(current);
+ index = list_find(siblings, current);
+ desired = index + offs;
+ target = desired == -1 || desired == siblings->length ?
+ NULL : siblings->items[desired];
+
+ // If the move is simple we can complete it here early
+ if (current == container) {
+ if (target) {
+ // Container will swap with or descend into its neighbor
+ container_move_to_container_from_direction(container,
+ target, move_dir);
+ return true;
+ } else if (!container->pending.parent) {
+ // Container is at workspace level so we move it to the
+ // next workspace if possible
+ return container_move_to_next_output(container,
+ current->pending.workspace->output, move_dir);
+ } else {
+ // Container has escaped its immediate parallel parent
+ current = current->pending.parent;
+ continue;
}
}
- current = current->parent;
+ // We found a suitable ancestor, the loop will end
+ ancestor = current;
}
- // Maybe rejigger the workspace
- struct sway_workspace *ws = container->workspace;
- if (ws) {
- if (!is_parallel(ws->layout, move_dir)) {
- workspace_rejigger(ws, container, move_dir);
- return true;
- } else if (ws->layout == L_TABBED || ws->layout == L_STACKED) {
- workspace_rejigger(ws, container, move_dir);
- return true;
+ if (target) {
+ // Container will move in with its cousin
+ container_move_to_container_from_direction(container,
+ target, move_dir);
+ return true;
+ } else if (!wrapped && !container->pending.parent->pending.parent &&
+ container->pending.parent->pending.children->length == 1) {
+ // Treat singleton children as if they are at workspace level like i3
+ // https://github.com/i3/i3/blob/1d9160f2d247dbaa83fb62f02fd7041dec767fc2/src/move.c#L367
+ return container_move_to_next_output(container,
+ ancestor->pending.workspace->output, move_dir);
+ } else {
+ // Container will be promoted
+ struct sway_container *old_parent = container->pending.parent;
+ if (ancestor->pending.parent) {
+ // Container will move in with its parent
+ container_insert_child(ancestor->pending.parent, container,
+ index + (offs < 0 ? 0 : 1));
+ } else {
+ // Container will move to workspace level,
+ // may be re-split by workspace_layout
+ workspace_insert_tiling(ancestor->pending.workspace, container,
+ index + (offs < 0 ? 0 : 1));
}
-
- // Try adjacent output
- struct sway_output *output =
- output_get_in_direction(container->workspace->output, move_dir);
- if (output) {
- struct sway_workspace *ws = output_get_active_workspace(output);
- if (!sway_assert(ws, "Expected output to have a workspace")) {
- return false;
- }
- container_move_to_workspace_from_direction(container, ws, move_dir);
- return true;
+ ancestor->pending.height = ancestor->pending.width = 0;
+ ancestor->height_fraction = ancestor->width_fraction = 0;
+ if (old_parent) {
+ container_reap_empty(old_parent);
}
- sway_log(SWAY_DEBUG, "Hit edge of output, nowhere else to go");
+ workspace_squash(container->pending.workspace);
+ return true;
}
- return false;
}
static struct cmd_results *cmd_move_to_scratchpad(void);
@@ -417,14 +427,14 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
container = workspace_wrap_children(workspace);
}
- if (container->fullscreen_mode == FULLSCREEN_GLOBAL) {
+ if (container->pending.fullscreen_mode == FULLSCREEN_GLOBAL) {
return cmd_results_new(CMD_FAILURE,
"Can't move fullscreen global container");
}
struct sway_seat *seat = config->handler_context.seat;
- struct sway_container *old_parent = container->parent;
- struct sway_workspace *old_ws = container->workspace;
+ struct sway_container *old_parent = container->pending.parent;
+ struct sway_workspace *old_ws = container->pending.workspace;
struct sway_output *old_output = old_ws ? old_ws->output : NULL;
struct sway_node *destination = NULL;
@@ -481,7 +491,7 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
// We have to create the workspace, but if the container is
// sticky and the workspace is going to be created on the same
// output, we'll bail out first.
- if (container->is_sticky && container_is_floating_or_child(container)) {
+ if (container_is_sticky_or_child(container)) {
struct sway_output *new_output =
workspace_get_initial_output(ws_name);
if (old_output == new_output) {
@@ -498,7 +508,7 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
destination = dst ? &dst->node : &ws->node;
} else if (strcasecmp(argv[0], "output") == 0) {
struct sway_output *new_output = output_in_direction(argv[1],
- old_output, container->x, container->y);
+ old_output, container->pending.x, container->pending.y);
if (!new_output) {
return cmd_results_new(CMD_FAILURE,
"Can't find output with name/direction '%s'", argv[1]);
@@ -520,8 +530,8 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
return cmd_move_to_scratchpad();
}
- if (container->is_sticky && container_is_floating_or_child(container) &&
- old_output && node_has_ancestor(destination, &old_output->node)) {
+ if (container_is_sticky_or_child(container) && old_output &&
+ node_has_ancestor(destination, &old_output->node)) {
return cmd_results_new(CMD_FAILURE, "Can't move sticky "
"container to another workspace on the same output");
}
@@ -536,7 +546,8 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
struct sway_node *focus = seat_get_focus(seat);
// move container
- if (container->scratchpad) {
+ if (container_is_scratchpad_hidden_or_child(container)) {
+ container_detach(container);
root_scratchpad_show(container);
}
switch (destination->type) {
@@ -695,12 +706,12 @@ static struct cmd_results *cmd_move_in_direction(
"Cannot move workspaces in a direction");
}
if (container_is_floating(container)) {
- if (container->fullscreen_mode) {
+ if (container->pending.fullscreen_mode) {
return cmd_results_new(CMD_FAILURE,
"Cannot move fullscreen floating container");
}
- double lx = container->x;
- double ly = container->y;
+ double lx = container->pending.x;
+ double ly = container->pending.y;
switch (direction) {
case WLR_DIRECTION_LEFT:
lx -= move_amt;
@@ -718,14 +729,22 @@ static struct cmd_results *cmd_move_in_direction(
container_floating_move_to(container, lx, ly);
return cmd_results_new(CMD_SUCCESS, NULL);
}
- struct sway_workspace *old_ws = container->workspace;
+ struct sway_workspace *old_ws = container->pending.workspace;
+ struct sway_container *old_parent = container->pending.parent;
if (!container_move_in_direction(container, direction)) {
// Container didn't move
return cmd_results_new(CMD_SUCCESS, NULL);
}
- struct sway_workspace *new_ws = container->workspace;
+ // clean-up, destroying parents if the container was the last child
+ if (old_parent) {
+ container_reap_empty(old_parent);
+ } else if (old_ws) {
+ workspace_consider_destroy(old_ws);
+ }
+
+ struct sway_workspace *new_ws = container->pending.workspace;
if (root->fullscreen_global) {
arrange_root();
@@ -762,8 +781,8 @@ static struct cmd_results *cmd_move_to_position_pointer(
}
struct wlr_cursor *cursor = seat->cursor->cursor;
/* Determine where to put the window. */
- double lx = cursor->x - container->width / 2;
- double ly = cursor->y - container->height / 2;
+ double lx = cursor->x - container->pending.width / 2;
+ double ly = cursor->y - container->pending.height / 2;
/* Correct target coordinates to be in bounds (on screen). */
struct wlr_output *output = wlr_output_layout_output_at(
@@ -773,11 +792,11 @@ static struct cmd_results *cmd_move_to_position_pointer(
wlr_output_layout_get_box(root->output_layout, output);
lx = fmax(lx, box->x);
ly = fmax(ly, box->y);
- if (lx + container->width > box->x + box->width) {
- lx = box->x + box->width - container->width;
+ if (lx + container->pending.width > box->x + box->width) {
+ lx = box->x + box->width - container->pending.width;
}
- if (ly + container->height > box->y + box->height) {
- ly = box->y + box->height - container->height;
+ if (ly + container->pending.height > box->y + box->height) {
+ ly = box->y + box->height - container->pending.height;
}
}
@@ -827,16 +846,16 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
} else if (strcmp(argv[0], "center") == 0) {
double lx, ly;
if (absolute) {
- lx = root->x + (root->width - container->width) / 2;
- ly = root->y + (root->height - container->height) / 2;
+ lx = root->x + (root->width - container->pending.width) / 2;
+ ly = root->y + (root->height - container->pending.height) / 2;
} else {
- struct sway_workspace *ws = container->workspace;
+ struct sway_workspace *ws = container->pending.workspace;
if (!ws) {
struct sway_seat *seat = config->handler_context.seat;
ws = seat_get_focused_workspace(seat);
}
- lx = ws->x + (ws->width - container->width) / 2;
- ly = ws->y + (ws->height - container->height) / 2;
+ lx = ws->x + (ws->width - container->pending.width) / 2;
+ ly = ws->y + (ws->height - container->pending.height) / 2;
}
container_floating_move_to(container, lx, ly);
return cmd_results_new(CMD_SUCCESS, NULL);
@@ -867,7 +886,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
return cmd_results_new(CMD_INVALID, "Invalid y position specified");
}
- struct sway_workspace *ws = container->workspace;
+ struct sway_workspace *ws = container->pending.workspace;
if (!ws) {
struct sway_seat *seat = config->handler_context.seat;
ws = seat_get_focused_workspace(seat);
@@ -941,14 +960,14 @@ static struct cmd_results *cmd_move_to_scratchpad(void) {
// If the container is in a floating split container,
// operate on the split container instead of the child.
if (container_is_floating_or_child(con)) {
- while (con->parent) {
- con = con->parent;
+ while (con->pending.parent) {
+ con = con->pending.parent;
}
}
if (!con->scratchpad) {
root_scratchpad_add_container(con, NULL);
- } else if (con->workspace) {
+ } else if (con->pending.workspace) {
root_scratchpad_hide(con);
}
return cmd_results_new(CMD_SUCCESS, NULL);
diff --git a/sway/commands/output.c b/sway/commands/output.c
index 5186a2ba1..d8ef28857 100644
--- a/sway/commands/output.c
+++ b/sway/commands/output.c
@@ -6,7 +6,7 @@
#include "log.h"
// must be in order for the bsearch
-static struct cmd_handler output_handlers[] = {
+static const struct cmd_handler output_handlers[] = {
{ "adaptive_sync", output_cmd_adaptive_sync },
{ "background", output_cmd_background },
{ "bg", output_cmd_background },
@@ -15,6 +15,7 @@ static struct cmd_handler output_handlers[] = {
{ "enable", output_cmd_enable },
{ "max_render_time", output_cmd_max_render_time },
{ "mode", output_cmd_mode },
+ { "modeline", output_cmd_modeline },
{ "pos", output_cmd_position },
{ "position", output_cmd_position },
{ "res", output_cmd_mode },
diff --git a/sway/commands/output/dpms.c b/sway/commands/output/dpms.c
index 9d75a80e8..638c0aded 100644
--- a/sway/commands/output/dpms.c
+++ b/sway/commands/output/dpms.c
@@ -1,6 +1,8 @@
#include "sway/commands.h"
#include "sway/config.h"
+#include "sway/output.h"
#include "util.h"
+#include
struct cmd_results *output_cmd_dpms(int argc, char **argv) {
if (!config->handler_context.output_config) {
@@ -10,7 +12,28 @@ struct cmd_results *output_cmd_dpms(int argc, char **argv) {
return cmd_results_new(CMD_INVALID, "Missing dpms argument.");
}
- if (parse_boolean(argv[0], true)) {
+ enum config_dpms current_dpms = DPMS_ON;
+
+ if (strcasecmp(argv[0], "toggle") == 0) {
+
+ const char *oc_name = config->handler_context.output_config->name;
+ if (strcmp(oc_name, "*") == 0) {
+ return cmd_results_new(CMD_INVALID,
+ "Cannot apply toggle to all outputs.");
+ }
+
+ struct sway_output *sway_output = all_output_by_name_or_id(oc_name);
+ if (!sway_output || !sway_output->wlr_output) {
+ return cmd_results_new(CMD_FAILURE,
+ "Cannot apply toggle to unknown output %s", oc_name);
+ }
+
+ if (sway_output->enabled && !sway_output->wlr_output->enabled) {
+ current_dpms = DPMS_OFF;
+ }
+ }
+
+ if (parse_boolean(argv[0], current_dpms == DPMS_ON)) {
config->handler_context.output_config->dpms_state = DPMS_ON;
} else {
config->handler_context.output_config->dpms_state = DPMS_OFF;
diff --git a/sway/commands/output/mode.c b/sway/commands/output/mode.c
index 5b710713a..019d625a7 100644
--- a/sway/commands/output/mode.c
+++ b/sway/commands/output/mode.c
@@ -20,6 +20,9 @@ struct cmd_results *output_cmd_mode(int argc, char **argv) {
output->custom_mode = 0;
}
+ // Reset custom modeline, if any
+ output->drm_mode.type = 0;
+
char *end;
output->width = strtol(*argv, &end, 10);
if (*end) {
@@ -58,3 +61,58 @@ struct cmd_results *output_cmd_mode(int argc, char **argv) {
return NULL;
}
+static bool parse_modeline(char **argv, drmModeModeInfo *mode) {
+ mode->type = DRM_MODE_TYPE_USERDEF;
+ mode->clock = strtof(argv[0], NULL) * 1000;
+ mode->hdisplay = strtol(argv[1], NULL, 10);
+ mode->hsync_start = strtol(argv[2], NULL, 10);
+ mode->hsync_end = strtol(argv[3], NULL, 10);
+ mode->htotal = strtol(argv[4], NULL, 10);
+ mode->vdisplay = strtol(argv[5], NULL, 10);
+ mode->vsync_start = strtol(argv[6], NULL, 10);
+ mode->vsync_end = strtol(argv[7], NULL, 10);
+ mode->vtotal = strtol(argv[8], NULL, 10);
+
+ mode->vrefresh = mode->clock * 1000.0 * 1000.0
+ / mode->htotal / mode->vtotal;
+ if (strcasecmp(argv[9], "+hsync") == 0) {
+ mode->flags |= DRM_MODE_FLAG_PHSYNC;
+ } else if (strcasecmp(argv[9], "-hsync") == 0) {
+ mode->flags |= DRM_MODE_FLAG_NHSYNC;
+ } else {
+ return false;
+ }
+
+ if (strcasecmp(argv[10], "+vsync") == 0) {
+ mode->flags |= DRM_MODE_FLAG_PVSYNC;
+ } else if (strcasecmp(argv[10], "-vsync") == 0) {
+ mode->flags |= DRM_MODE_FLAG_NVSYNC;
+ } else {
+ return false;
+ }
+
+ snprintf(mode->name, sizeof(mode->name), "%dx%d@%d",
+ mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000);
+
+ return true;
+}
+
+struct cmd_results *output_cmd_modeline(int argc, char **argv) {
+ if (!config->handler_context.output_config) {
+ return cmd_results_new(CMD_FAILURE, "Missing output config");
+ }
+ if (!argc) {
+ return cmd_results_new(CMD_INVALID, "Missing modeline argument.");
+ }
+
+ struct output_config *output = config->handler_context.output_config;
+
+ if (argc != 11 || !parse_modeline(argv, &output->drm_mode)) {
+ return cmd_results_new(CMD_INVALID, "Invalid modeline");
+ }
+
+ config->handler_context.leftovers.argc = argc - 12;
+ config->handler_context.leftovers.argv = argv + 12;
+ return NULL;
+}
+
diff --git a/sway/commands/reload.c b/sway/commands/reload.c
index 3c994d54f..76f14bba3 100644
--- a/sway/commands/reload.c
+++ b/sway/commands/reload.c
@@ -48,7 +48,6 @@ static void do_reload(void *data) {
}
list_free_items_and_destroy(bar_ids);
- config_update_font_height(true);
root_for_each_container(rebuild_textures_iterator, NULL);
arrange_root();
diff --git a/sway/commands/resize.c b/sway/commands/resize.c
index 4038e331b..425069de3 100644
--- a/sway/commands/resize.c
+++ b/sway/commands/resize.c
@@ -57,7 +57,7 @@ struct sway_container *container_find_resize_parent(struct sway_container *con,
(allow_last || index < siblings->length - 1)) {
return con;
}
- con = con->parent;
+ con = con->pending.parent;
}
return NULL;
@@ -115,13 +115,13 @@ void container_resize_tiled(struct sway_container *con,
int sibling_amount = prev ? ceil((double)amount / 2.0) : amount;
if (is_horizontal(axis)) {
- if (con->width + amount < MIN_SANE_W) {
+ if (con->pending.width + amount < MIN_SANE_W) {
return;
}
- if (next->width - sibling_amount < MIN_SANE_W) {
+ if (next->pending.width - sibling_amount < MIN_SANE_W) {
return;
}
- if (prev && prev->width - sibling_amount < MIN_SANE_W) {
+ if (prev && prev->pending.width - sibling_amount < MIN_SANE_W) {
return;
}
if (con->child_total_width <= 0) {
@@ -133,7 +133,7 @@ void container_resize_tiled(struct sway_container *con,
list_t *siblings = container_get_siblings(con);
for (int i = 0; i < siblings->length; ++i) {
struct sway_container *con = siblings->items[i];
- con->width_fraction = con->width / con->child_total_width;
+ con->width_fraction = con->pending.width / con->child_total_width;
}
double amount_fraction = (double)amount / con->child_total_width;
@@ -146,13 +146,13 @@ void container_resize_tiled(struct sway_container *con,
prev->width_fraction -= sibling_amount_fraction;
}
} else {
- if (con->height + amount < MIN_SANE_H) {
+ if (con->pending.height + amount < MIN_SANE_H) {
return;
}
- if (next->height - sibling_amount < MIN_SANE_H) {
+ if (next->pending.height - sibling_amount < MIN_SANE_H) {
return;
}
- if (prev && prev->height - sibling_amount < MIN_SANE_H) {
+ if (prev && prev->pending.height - sibling_amount < MIN_SANE_H) {
return;
}
if (con->child_total_height <= 0) {
@@ -164,7 +164,7 @@ void container_resize_tiled(struct sway_container *con,
list_t *siblings = container_get_siblings(con);
for (int i = 0; i < siblings->length; ++i) {
struct sway_container *con = siblings->items[i];
- con->height_fraction = con->height / con->child_total_height;
+ con->height_fraction = con->pending.height / con->child_total_height;
}
double amount_fraction = (double)amount / con->child_total_height;
@@ -178,10 +178,10 @@ void container_resize_tiled(struct sway_container *con,
}
}
- if (con->parent) {
- arrange_container(con->parent);
+ if (con->pending.parent) {
+ arrange_container(con->pending.parent);
} else {
- arrange_workspace(con->workspace);
+ arrange_workspace(con->pending.workspace);
}
}
@@ -203,15 +203,15 @@ static struct cmd_results *resize_adjust_floating(uint32_t axis,
int min_width, max_width, min_height, max_height;
floating_calculate_constraints(&min_width, &max_width,
&min_height, &max_height);
- if (con->width + grow_width < min_width) {
- grow_width = min_width - con->width;
- } else if (con->width + grow_width > max_width) {
- grow_width = max_width - con->width;
+ if (con->pending.width + grow_width < min_width) {
+ grow_width = min_width - con->pending.width;
+ } else if (con->pending.width + grow_width > max_width) {
+ grow_width = max_width - con->pending.width;
}
- if (con->height + grow_height < min_height) {
- grow_height = min_height - con->height;
- } else if (con->height + grow_height > max_height) {
- grow_height = max_height - con->height;
+ if (con->pending.height + grow_height < min_height) {
+ grow_height = min_height - con->pending.height;
+ } else if (con->pending.height + grow_height > max_height) {
+ grow_height = max_height - con->pending.height;
}
int grow_x = 0, grow_y = 0;
@@ -224,18 +224,18 @@ static struct cmd_results *resize_adjust_floating(uint32_t axis,
} else if (axis == WLR_EDGE_LEFT) {
grow_x = -grow_width;
}
- if (grow_x == 0 && grow_y == 0) {
+ if (grow_width == 0 && grow_height == 0) {
return cmd_results_new(CMD_INVALID, "Cannot resize any further");
}
- con->x += grow_x;
- con->y += grow_y;
- con->width += grow_width;
- con->height += grow_height;
+ con->pending.x += grow_x;
+ con->pending.y += grow_y;
+ con->pending.width += grow_width;
+ con->pending.height += grow_height;
- con->content_x += grow_x;
- con->content_y += grow_y;
- con->content_width += grow_width;
- con->content_height += grow_height;
+ con->pending.content_x += grow_x;
+ con->pending.content_y += grow_y;
+ con->pending.content_width += grow_width;
+ con->pending.content_height += grow_height;
arrange_container(con);
@@ -256,9 +256,9 @@ static struct cmd_results *resize_adjust_tiled(uint32_t axis,
float pct = amount->amount / 100.0f;
if (is_horizontal(axis)) {
- amount->amount = (float)current->width * pct;
+ amount->amount = (float)current->pending.width * pct;
} else {
- amount->amount = (float)current->height * pct;
+ amount->amount = (float)current->pending.height * pct;
}
}
@@ -281,20 +281,20 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con,
if (width->unit == MOVEMENT_UNIT_PPT ||
width->unit == MOVEMENT_UNIT_DEFAULT) {
// Convert to px
- struct sway_container *parent = con->parent;
- while (parent && parent->layout != L_HORIZ) {
- parent = parent->parent;
+ struct sway_container *parent = con->pending.parent;
+ while (parent && parent->pending.layout != L_HORIZ) {
+ parent = parent->pending.parent;
}
if (parent) {
- width->amount = parent->width * width->amount / 100;
+ width->amount = parent->pending.width * width->amount / 100;
} else {
- width->amount = con->workspace->width * width->amount / 100;
+ width->amount = con->pending.workspace->width * width->amount / 100;
}
width->unit = MOVEMENT_UNIT_PX;
}
if (width->unit == MOVEMENT_UNIT_PX) {
container_resize_tiled(con, AXIS_HORIZONTAL,
- width->amount - con->width);
+ width->amount - con->pending.width);
}
}
@@ -302,20 +302,20 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con,
if (height->unit == MOVEMENT_UNIT_PPT ||
height->unit == MOVEMENT_UNIT_DEFAULT) {
// Convert to px
- struct sway_container *parent = con->parent;
- while (parent && parent->layout != L_VERT) {
- parent = parent->parent;
+ struct sway_container *parent = con->pending.parent;
+ while (parent && parent->pending.layout != L_VERT) {
+ parent = parent->pending.parent;
}
if (parent) {
- height->amount = parent->height * height->amount / 100;
+ height->amount = parent->pending.height * height->amount / 100;
} else {
- height->amount = con->workspace->height * height->amount / 100;
+ height->amount = con->pending.workspace->height * height->amount / 100;
}
height->unit = MOVEMENT_UNIT_PX;
}
if (height->unit == MOVEMENT_UNIT_PX) {
container_resize_tiled(con, AXIS_VERTICAL,
- height->amount - con->height);
+ height->amount - con->pending.height);
}
}
@@ -339,15 +339,15 @@ static struct cmd_results *resize_set_floating(struct sway_container *con,
"Cannot resize a hidden scratchpad container by ppt");
}
// Convert to px
- width->amount = con->workspace->width * width->amount / 100;
+ width->amount = con->pending.workspace->width * width->amount / 100;
width->unit = MOVEMENT_UNIT_PX;
// Falls through
case MOVEMENT_UNIT_PX:
case MOVEMENT_UNIT_DEFAULT:
width->amount = fmax(min_width, fmin(width->amount, max_width));
- grow_width = width->amount - con->width;
- con->x -= grow_width / 2;
- con->width = width->amount;
+ grow_width = width->amount - con->pending.width;
+ con->pending.x -= grow_width / 2;
+ con->pending.width = width->amount;
break;
case MOVEMENT_UNIT_INVALID:
sway_assert(false, "invalid width unit");
@@ -363,15 +363,15 @@ static struct cmd_results *resize_set_floating(struct sway_container *con,
"Cannot resize a hidden scratchpad container by ppt");
}
// Convert to px
- height->amount = con->workspace->height * height->amount / 100;
+ height->amount = con->pending.workspace->height * height->amount / 100;
height->unit = MOVEMENT_UNIT_PX;
// Falls through
case MOVEMENT_UNIT_PX:
case MOVEMENT_UNIT_DEFAULT:
height->amount = fmax(min_height, fmin(height->amount, max_height));
- grow_height = height->amount - con->height;
- con->y -= grow_height / 2;
- con->height = height->amount;
+ grow_height = height->amount - con->pending.height;
+ con->pending.y -= grow_height / 2;
+ con->pending.height = height->amount;
break;
case MOVEMENT_UNIT_INVALID:
sway_assert(false, "invalid height unit");
@@ -379,10 +379,10 @@ static struct cmd_results *resize_set_floating(struct sway_container *con,
}
}
- con->content_x -= grow_width / 2;
- con->content_y -= grow_height / 2;
- con->content_width += grow_width;
- con->content_height += grow_height;
+ con->pending.content_x -= grow_width / 2;
+ con->pending.content_y -= grow_height / 2;
+ con->pending.content_width += grow_width;
+ con->pending.content_height += grow_height;
arrange_container(con);
@@ -437,10 +437,10 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) {
// If 0, don't resize that dimension
struct sway_container *con = config->handler_context.container;
if (width.amount <= 0) {
- width.amount = con->width;
+ width.amount = con->pending.width;
}
if (height.amount <= 0) {
- height.amount = con->height;
+ height.amount = con->pending.height;
}
if (container_is_floating(con)) {
diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c
index 34871bc6a..c995f2f08 100644
--- a/sway/commands/scratchpad.c
+++ b/sway/commands/scratchpad.c
@@ -21,8 +21,8 @@ static void scratchpad_toggle_auto(void) {
// If the focus is in a floating split container,
// operate on the split container instead of the child.
if (focus && container_is_floating_or_child(focus)) {
- while (focus->parent) {
- focus = focus->parent;
+ while (focus->pending.parent) {
+ focus = focus->pending.parent;
}
}
@@ -52,7 +52,7 @@ static void scratchpad_toggle_auto(void) {
// In this case we move it to the current workspace.
for (int i = 0; i < root->scratchpad->length; ++i) {
struct sway_container *con = root->scratchpad->items[i];
- if (con->parent) {
+ if (con->pending.parent) {
sway_log(SWAY_DEBUG,
"Moving a visible scratchpad window (%s) to this workspace",
con->title);
@@ -80,7 +80,7 @@ static void scratchpad_toggle_container(struct sway_container *con) {
struct sway_seat *seat = input_manager_current_seat();
struct sway_workspace *ws = seat_get_focused_workspace(seat);
// Check if it matches a currently visible scratchpad window and hide it.
- if (con->workspace && ws == con->workspace) {
+ if (con->pending.workspace && ws == con->pending.workspace) {
root_scratchpad_hide(con);
return;
}
@@ -105,21 +105,22 @@ struct cmd_results *cmd_scratchpad(int argc, char **argv) {
return cmd_results_new(CMD_INVALID, "Scratchpad is empty");
}
- if (config->handler_context.using_criteria) {
+ if (config->handler_context.node_overridden) {
struct sway_container *con = config->handler_context.container;
// If the container is in a floating split container,
// operate on the split container instead of the child.
- if (container_is_floating_or_child(con)) {
- while (con->parent) {
- con = con->parent;
+ if (con && container_is_floating_or_child(con)) {
+ while (con->pending.parent) {
+ con = con->pending.parent;
}
}
// If using criteria, this command is executed for every container which
// matches the criteria. If this container isn't in the scratchpad,
- // we'll just silently return a success.
- if (!con->scratchpad) {
+ // we'll just silently return a success. The same is true if the
+ // overridden node is not a container.
+ if (!con || !con->scratchpad) {
return cmd_results_new(CMD_SUCCESS, NULL);
}
scratchpad_toggle_container(con);
diff --git a/sway/commands/seat.c b/sway/commands/seat.c
index 84c6ba535..2d197b692 100644
--- a/sway/commands/seat.c
+++ b/sway/commands/seat.c
@@ -8,13 +8,13 @@
// must be in order for the bsearch
// these handlers perform actions on the seat
-static struct cmd_handler seat_action_handlers[] = {
+static const struct cmd_handler seat_action_handlers[] = {
{ "cursor", seat_cmd_cursor },
};
// must be in order for the bsearch
// these handlers alter the seat config
-static struct cmd_handler seat_handlers[] = {
+static const struct cmd_handler seat_handlers[] = {
{ "attach", seat_cmd_attach },
{ "fallback", seat_cmd_fallback },
{ "hide_cursor", seat_cmd_hide_cursor },
diff --git a/sway/commands/seat/attach.c b/sway/commands/seat/attach.c
index 7615eef9b..00bfdab69 100644
--- a/sway/commands/seat/attach.c
+++ b/sway/commands/seat/attach.c
@@ -12,7 +12,7 @@ struct cmd_results *seat_cmd_attach(int argc, char **argv) {
if (!config->handler_context.seat_config) {
return cmd_results_new(CMD_FAILURE, "No seat defined");
}
- if (config->reading) {
+ if (!config->active) {
return cmd_results_new(CMD_DEFER, NULL);
}
diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c
index ad7dc9059..749235eb2 100644
--- a/sway/commands/seat/cursor.c
+++ b/sway/commands/seat/cursor.c
@@ -45,6 +45,7 @@ static struct cmd_results *handle_command(struct sway_cursor *cursor,
}
}
+ cursor_handle_activity_from_idle_source(cursor, IDLE_SOURCE_POINTER);
return cmd_results_new(CMD_SUCCESS, NULL);
}
diff --git a/sway/commands/seat/hide_cursor.c b/sway/commands/seat/hide_cursor.c
index 3bfce6977..e09b82d99 100644
--- a/sway/commands/seat/hide_cursor.c
+++ b/sway/commands/seat/hide_cursor.c
@@ -3,26 +3,48 @@
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/input/seat.h"
+#include "sway/input/cursor.h"
+#include "sway/server.h"
#include "stringop.h"
+#include "util.h"
struct cmd_results *seat_cmd_hide_cursor(int argc, char **argv) {
struct cmd_results *error = NULL;
- if ((error = checkarg(argc, "hide_cursor", EXPECTED_EQUAL_TO, 1))) {
+ if ((error = checkarg(argc, "hide_cursor", EXPECTED_AT_LEAST, 1))) {
return error;
}
- if (!config->handler_context.seat_config) {
+ if ((error = checkarg(argc, "hide_cursor", EXPECTED_AT_MOST, 2))) {
+ return error;
+ }
+ struct seat_config *seat_config = config->handler_context.seat_config;
+ if (!seat_config) {
return cmd_results_new(CMD_FAILURE, "No seat defined");
}
- char *end;
- int timeout = strtol(argv[0], &end, 10);
- if (*end) {
- return cmd_results_new(CMD_INVALID, "Expected an integer timeout");
+ if (argc == 1) {
+ char *end;
+ int timeout = strtol(argv[0], &end, 10);
+ if (*end) {
+ return cmd_results_new(CMD_INVALID, "Expected an integer timeout");
+ }
+ if (timeout < 100 && timeout != 0) {
+ timeout = 100;
+ }
+ seat_config->hide_cursor_timeout = timeout;
+ } else {
+ if (strcmp(argv[0], "when-typing") != 0) {
+ return cmd_results_new(CMD_INVALID,
+ "Expected 'hide_cursor |when-typing [enable|disable]'");
+ }
+ seat_config->hide_cursor_when_typing = parse_boolean(argv[1], true) ?
+ HIDE_WHEN_TYPING_ENABLE : HIDE_WHEN_TYPING_DISABLE;
+
+ // Invalidate all the caches for this config
+ struct sway_seat *seat = NULL;
+ wl_list_for_each(seat, &server.input->seats, link) {
+ seat->cursor->hide_when_typing = HIDE_WHEN_TYPING_DEFAULT;
+ }
}
- if (timeout < 100 && timeout != 0) {
- timeout = 100;
- }
- config->handler_context.seat_config->hide_cursor_timeout = timeout;
return cmd_results_new(CMD_SUCCESS, NULL);
}
diff --git a/sway/commands/smart_gaps.c b/sway/commands/smart_gaps.c
index b27f9ccde..a6d165dc3 100644
--- a/sway/commands/smart_gaps.c
+++ b/sway/commands/smart_gaps.c
@@ -15,7 +15,12 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) {
return error;
}
- config->smart_gaps = parse_boolean(argv[0], config->smart_gaps);
+ if (strcmp(argv[0], "inverse_outer") == 0) {
+ config->smart_gaps = SMART_GAPS_INVERSE_OUTER;
+ } else {
+ config->smart_gaps = parse_boolean(argv[0], config->smart_gaps)
+ ? SMART_GAPS_ON : SMART_GAPS_OFF;
+ }
arrange_root();
diff --git a/sway/commands/split.c b/sway/commands/split.c
index ec56c2f08..c8a2cfc1f 100644
--- a/sway/commands/split.c
+++ b/sway/commands/split.c
@@ -14,7 +14,7 @@ static struct cmd_results *do_split(int layout) {
struct sway_workspace *ws = config->handler_context.workspace;
if (con) {
if (container_is_scratchpad_hidden_or_child(con) &&
- con->fullscreen_mode != FULLSCREEN_GLOBAL) {
+ con->pending.fullscreen_mode != FULLSCREEN_GLOBAL) {
return cmd_results_new(CMD_FAILURE,
"Cannot split a hidden scratchpad container");
}
@@ -23,8 +23,23 @@ static struct cmd_results *do_split(int layout) {
workspace_split(ws, layout);
}
- if (con && con->parent && con->parent->parent) {
- container_flatten(con->parent->parent);
+ if (root->fullscreen_global) {
+ arrange_root();
+ } else {
+ arrange_workspace(ws);
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL);
+}
+
+static struct cmd_results *do_unsplit() {
+ struct sway_container *con = config->handler_context.container;
+ struct sway_workspace *ws = config->handler_context.workspace;
+
+ if (con && con->pending.parent && con->pending.parent->pending.children->length == 1) {
+ container_flatten(con->pending.parent);
+ } else {
+ return cmd_results_new(CMD_FAILURE, "Can only flatten a child container with no siblings");
}
if (root->fullscreen_global) {
@@ -32,7 +47,6 @@ static struct cmd_results *do_split(int layout) {
} else {
arrange_workspace(ws);
}
-
return cmd_results_new(CMD_SUCCESS, NULL);
}
@@ -59,6 +73,9 @@ struct cmd_results *cmd_split(int argc, char **argv) {
} else {
return do_split(L_VERT);
}
+ } else if (strcasecmp(argv[0], "n") == 0 ||
+ strcasecmp(argv[0], "none") == 0) {
+ return do_unsplit();
} else {
return cmd_results_new(CMD_FAILURE,
"Invalid split command (expected either horizontal or vertical).");
diff --git a/sway/commands/sticky.c b/sway/commands/sticky.c
index 9df1fe09d..9b09a0f9d 100644
--- a/sway/commands/sticky.c
+++ b/sway/commands/sticky.c
@@ -25,18 +25,18 @@ struct cmd_results *cmd_sticky(int argc, char **argv) {
container->is_sticky = parse_boolean(argv[0], container->is_sticky);
- if (container->is_sticky && container_is_floating_or_child(container) &&
+ if (container_is_sticky_or_child(container) &&
!container_is_scratchpad_hidden(container)) {
// move container to active workspace
struct sway_workspace *active_workspace =
- output_get_active_workspace(container->workspace->output);
+ output_get_active_workspace(container->pending.workspace->output);
if (!sway_assert(active_workspace,
"Expected output to have a workspace")) {
return cmd_results_new(CMD_FAILURE,
"Expected output to have a workspace");
}
- if (container->workspace != active_workspace) {
- struct sway_workspace *old_workspace = container->workspace;
+ if (container->pending.workspace != active_workspace) {
+ struct sway_workspace *old_workspace = container->pending.workspace;
container_detach(container);
workspace_add_floating(active_workspace, container);
container_handle_fullscreen_reparent(container);
diff --git a/sway/commands/swap.c b/sway/commands/swap.c
index a7f9691bf..ce5e5128b 100644
--- a/sway/commands/swap.c
+++ b/sway/commands/swap.c
@@ -16,46 +16,46 @@ static const char expected_syntax[] =
static void swap_places(struct sway_container *con1,
struct sway_container *con2) {
struct sway_container *temp = malloc(sizeof(struct sway_container));
- temp->x = con1->x;
- temp->y = con1->y;
- temp->width = con1->width;
- temp->height = con1->height;
+ temp->pending.x = con1->pending.x;
+ temp->pending.y = con1->pending.y;
+ temp->pending.width = con1->pending.width;
+ temp->pending.height = con1->pending.height;
temp->width_fraction = con1->width_fraction;
temp->height_fraction = con1->height_fraction;
- temp->parent = con1->parent;
- temp->workspace = con1->workspace;
+ temp->pending.parent = con1->pending.parent;
+ temp->pending.workspace = con1->pending.workspace;
bool temp_floating = container_is_floating(con1);
- con1->x = con2->x;
- con1->y = con2->y;
- con1->width = con2->width;
- con1->height = con2->height;
+ con1->pending.x = con2->pending.x;
+ con1->pending.y = con2->pending.y;
+ con1->pending.width = con2->pending.width;
+ con1->pending.height = con2->pending.height;
con1->width_fraction = con2->width_fraction;
con1->height_fraction = con2->height_fraction;
- con2->x = temp->x;
- con2->y = temp->y;
- con2->width = temp->width;
- con2->height = temp->height;
+ con2->pending.x = temp->pending.x;
+ con2->pending.y = temp->pending.y;
+ con2->pending.width = temp->pending.width;
+ con2->pending.height = temp->pending.height;
con2->width_fraction = temp->width_fraction;
con2->height_fraction = temp->height_fraction;
int temp_index = container_sibling_index(con1);
- if (con2->parent) {
- container_insert_child(con2->parent, con1,
+ if (con2->pending.parent) {
+ container_insert_child(con2->pending.parent, con1,
container_sibling_index(con2));
} else if (container_is_floating(con2)) {
- workspace_add_floating(con2->workspace, con1);
+ workspace_add_floating(con2->pending.workspace, con1);
} else {
- workspace_insert_tiling(con2->workspace, con1,
+ workspace_insert_tiling(con2->pending.workspace, con1,
container_sibling_index(con2));
}
- if (temp->parent) {
- container_insert_child(temp->parent, con2, temp_index);
+ if (temp->pending.parent) {
+ container_insert_child(temp->pending.parent, con2, temp_index);
} else if (temp_floating) {
- workspace_add_floating(temp->workspace, con2);
+ workspace_add_floating(temp->pending.workspace, con2);
} else {
- workspace_insert_tiling(temp->workspace, con2, temp_index);
+ workspace_insert_tiling(temp->pending.workspace, con2, temp_index);
}
free(temp);
@@ -65,8 +65,8 @@ static void swap_focus(struct sway_container *con1,
struct sway_container *con2, struct sway_seat *seat,
struct sway_container *focus) {
if (focus == con1 || focus == con2) {
- struct sway_workspace *ws1 = con1->workspace;
- struct sway_workspace *ws2 = con2->workspace;
+ struct sway_workspace *ws1 = con1->pending.workspace;
+ struct sway_workspace *ws2 = con2->pending.workspace;
enum sway_container_layout layout1 = container_parent_layout(con1);
enum sway_container_layout layout2 = container_parent_layout(con2);
if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) {
@@ -125,8 +125,8 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) {
root_scratchpad_remove_container(con2);
}
- enum sway_fullscreen_mode fs1 = con1->fullscreen_mode;
- enum sway_fullscreen_mode fs2 = con2->fullscreen_mode;
+ enum sway_fullscreen_mode fs1 = con1->pending.fullscreen_mode;
+ enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode;
if (fs1) {
container_fullscreen_disable(con1);
}
@@ -137,9 +137,9 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) {
struct sway_seat *seat = config->handler_context.seat;
struct sway_container *focus = seat_get_focused_container(seat);
struct sway_workspace *vis1 =
- output_get_active_workspace(con1->workspace->output);
+ output_get_active_workspace(con1->pending.workspace->output);
struct sway_workspace *vis2 =
- output_get_active_workspace(con2->workspace->output);
+ output_get_active_workspace(con2->pending.workspace->output);
if (!sway_assert(vis1 && vis2, "con1 or con2 are on an output without a"
"workspace. This should not happen")) {
return;
diff --git a/sway/commands/title_format.c b/sway/commands/title_format.c
index 9d312470e..a2446b7e4 100644
--- a/sway/commands/title_format.c
+++ b/sway/commands/title_format.c
@@ -23,6 +23,5 @@ struct cmd_results *cmd_title_format(int argc, char **argv) {
}
view->title_format = format;
view_update_title(view, true);
- config_update_font_height(true);
return cmd_results_new(CMD_SUCCESS, NULL);
}
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c
index cedfcfb2c..19274dfbf 100644
--- a/sway/commands/unmark.c
+++ b/sway/commands/unmark.c
@@ -21,7 +21,7 @@ static void remove_all_marks_iterator(struct sway_container *con, void *data) {
struct cmd_results *cmd_unmark(int argc, char **argv) {
// Determine the container
struct sway_container *con = NULL;
- if (config->handler_context.using_criteria) {
+ if (config->handler_context.node_overridden) {
con = config->handler_context.container;
}
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c
index 2858a2840..a6a0bedad 100644
--- a/sway/commands/workspace.c
+++ b/sway/commands/workspace.c
@@ -178,21 +178,16 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
"Can't switch workspaces while fullscreen global");
}
- bool no_auto_back_and_forth = false;
+ bool auto_back_and_forth = true;
while (strcasecmp(argv[0], "--no-auto-back-and-forth") == 0) {
- no_auto_back_and_forth = true;
+ auto_back_and_forth = false;
if ((error = checkarg(--argc, "workspace", EXPECTED_AT_LEAST, 1))) {
return error;
}
++argv;
}
- bool create = argc > 1 && strcasecmp(argv[1], "--create") == 0;
struct sway_seat *seat = config->handler_context.seat;
- struct sway_workspace *current = seat_get_focused_workspace(seat);
- if (!current) {
- return cmd_results_new(CMD_FAILURE, "No workspace to switch from");
- }
struct sway_workspace *ws = NULL;
if (strcasecmp(argv[0], "number") == 0) {
@@ -209,14 +204,15 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
ws = workspace_create(NULL, name);
free(name);
}
+ if (ws && auto_back_and_forth) {
+ ws = workspace_auto_back_and_forth(ws);
+ }
} else if (strcasecmp(argv[0], "next") == 0 ||
strcasecmp(argv[0], "prev") == 0 ||
+ strcasecmp(argv[0], "next_on_output") == 0 ||
+ strcasecmp(argv[0], "prev_on_output") == 0 ||
strcasecmp(argv[0], "current") == 0) {
ws = workspace_by_name(argv[0]);
- } else if (strcasecmp(argv[0], "next_on_output") == 0) {
- ws = workspace_output_next(current, create);
- } else if (strcasecmp(argv[0], "prev_on_output") == 0) {
- ws = workspace_output_prev(current, create);
} else if (strcasecmp(argv[0], "back_and_forth") == 0) {
if (!seat->prev_workspace_name) {
return cmd_results_new(CMD_INVALID,
@@ -231,11 +227,14 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
ws = workspace_create(NULL, name);
}
free(name);
+ if (ws && auto_back_and_forth) {
+ ws = workspace_auto_back_and_forth(ws);
+ }
}
if (!ws) {
return cmd_results_new(CMD_FAILURE, "No workspace to switch to");
}
- workspace_switch(ws, no_auto_back_and_forth);
+ workspace_switch(ws);
seat_consider_warp_to_focus(seat);
}
return cmd_results_new(CMD_SUCCESS, NULL);
diff --git a/sway/config.c b/sway/config.c
index 71382b864..358372124 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -26,7 +26,7 @@
#include "sway/tree/arrange.h"
#include "sway/tree/root.h"
#include "sway/tree/workspace.h"
-#include "cairo.h"
+#include "cairo_util.h"
#include "pango.h"
#include "stringop.h"
#include "list.h"
@@ -236,7 +236,6 @@ static void config_defaults(struct sway_config *config) {
config->default_layout = L_NONE;
config->default_orientation = L_NONE;
if (!(config->font = strdup("monospace 10"))) goto cleanup;
- config->font_height = 17; // height of monospace 10
config->urgent_timeout = 500;
config->focus_on_window_activation = FOWA_URGENT;
config->popup_during_fullscreen = POPUP_SMART;
@@ -267,7 +266,7 @@ static void config_defaults(struct sway_config *config) {
config->tiling_drag = true;
config->tiling_drag_threshold = 9;
- config->smart_gaps = false;
+ config->smart_gaps = SMART_GAPS_OFF;
config->gaps_inner = 0;
config->gaps_outer.top = 0;
config->gaps_outer.right = 0;
@@ -338,35 +337,62 @@ static bool file_exists(const char *path) {
return path && access(path, R_OK) != -1;
}
+static char *config_path(const char *prefix, const char *config_folder) {
+ if (!prefix || !prefix[0] || !config_folder || !config_folder[0]) {
+ return NULL;
+ }
+
+ const char *filename = "config";
+
+ size_t size = 3 + strlen(prefix) + strlen(config_folder) + strlen(filename);
+ char *path = calloc(size, sizeof(char));
+ snprintf(path, size, "%s/%s/%s", prefix, config_folder, filename);
+ return path;
+}
+
static char *get_config_path(void) {
- static const char *config_paths[] = {
- "$HOME/.sway/config",
- "$XDG_CONFIG_HOME/sway/config",
- "$HOME/.i3/config",
- "$XDG_CONFIG_HOME/i3/config",
- SYSCONFDIR "/sway/config",
- SYSCONFDIR "/i3/config",
+ char *path = NULL;
+ const char *home = getenv("HOME");
+ char *config_home_fallback = NULL;
+
+ const char *config_home = getenv("XDG_CONFIG_HOME");
+ if ((config_home == NULL || config_home[0] == '\0') && home != NULL) {
+ size_t size_fallback = 1 + strlen(home) + strlen("/.config");
+ config_home_fallback = calloc(size_fallback, sizeof(char));
+ if (config_home_fallback != NULL)
+ snprintf(config_home_fallback, size_fallback, "%s/.config", home);
+ config_home = config_home_fallback;
+ }
+
+ struct config_path {
+ const char *prefix;
+ const char *config_folder;
};
- char *config_home = getenv("XDG_CONFIG_HOME");
- if (!config_home || !*config_home) {
- config_paths[1] = "$HOME/.config/sway/config";
- config_paths[3] = "$HOME/.config/i3/config";
- }
+ struct config_path config_paths[] = {
+ { .prefix = home, .config_folder = ".sway"},
+ { .prefix = config_home, .config_folder = "sway"},
+ { .prefix = home, .config_folder = ".i3"},
+ { .prefix = config_home, .config_folder = "i3"},
+ { .prefix = SYSCONFDIR, .config_folder = "sway"},
+ { .prefix = SYSCONFDIR, .config_folder = "i3"}
+ };
- for (size_t i = 0; i < sizeof(config_paths) / sizeof(char *); ++i) {
- wordexp_t p;
- if (wordexp(config_paths[i], &p, WRDE_UNDEF) == 0) {
- char *path = strdup(p.we_wordv[0]);
- wordfree(&p);
- if (file_exists(path)) {
- return path;
- }
- free(path);
+ size_t num_config_paths = sizeof(config_paths)/sizeof(config_paths[0]);
+ for (size_t i = 0; i < num_config_paths; i++) {
+ path = config_path(config_paths[i].prefix, config_paths[i].config_folder);
+ if (!path) {
+ continue;
}
+ if (file_exists(path)) {
+ break;
+ }
+ free(path);
+ path = NULL;
}
- return NULL;
+ free(config_home_fallback);
+ return path;
}
static bool load_config(const char *path, struct sway_config *config,
@@ -407,10 +433,14 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
} else {
path = get_config_path();
}
+ if (path == NULL) {
+ sway_log(SWAY_ERROR, "Cannot find config file");
+ return false;
+ }
char *real_path = realpath(path, NULL);
if (real_path == NULL) {
- sway_log(SWAY_DEBUG, "%s not found.", path);
+ sway_log(SWAY_ERROR, "%s not found", path);
free(path);
return false;
}
@@ -510,6 +540,9 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
return success;
}
+ // Only really necessary if not explicitly `font` is set in the config.
+ config_update_font_height();
+
if (is_active && !validating) {
input_manager_verify_fallback_seat();
@@ -960,31 +993,11 @@ int workspace_output_cmp_workspace(const void *a, const void *b) {
return lenient_strcmp(wsa->workspace, wsb->workspace);
}
-static void find_font_height_iterator(struct sway_container *con, void *data) {
- size_t amount_below_baseline = con->title_height - con->title_baseline;
- size_t extended_height = config->font_baseline + amount_below_baseline;
- if (extended_height > config->font_height) {
- config->font_height = extended_height;
- }
-}
-static void find_baseline_iterator(struct sway_container *con, void *data) {
- bool *recalculate = data;
- if (*recalculate) {
- container_calculate_title_height(con);
- }
- if (con->title_baseline > config->font_baseline) {
- config->font_baseline = con->title_baseline;
- }
-}
+void config_update_font_height(void) {
+ int prev_max_height = config->font_height;
-void config_update_font_height(bool recalculate) {
- size_t prev_max_height = config->font_height;
- config->font_height = 0;
- config->font_baseline = 0;
-
- root_for_each_container(find_baseline_iterator, &recalculate);
- root_for_each_container(find_font_height_iterator, NULL);
+ get_text_metrics(config->font, &config->font_height, &config->font_baseline);
if (config->font_height != prev_max_height) {
arrange_root();
diff --git a/sway/config/bar.c b/sway/config/bar.c
index 1c7c13b2e..d1b342e69 100644
--- a/sway/config/bar.c
+++ b/sway/config/bar.c
@@ -91,7 +91,7 @@ struct bar_config *default_bar_config(void) {
}
bar->outputs = NULL;
bar->position = strdup("bottom");
- bar->pango_markup = false;
+ bar->pango_markup = PANGO_MARKUP_DEFAULT;
bar->swaybar_command = NULL;
bar->font = NULL;
bar->height = 0;
@@ -105,6 +105,7 @@ struct bar_config *default_bar_config(void) {
bar->modifier = get_modifier_mask_by_name("Mod4");
bar->status_padding = 1;
bar->status_edge_padding = 3;
+ bar->workspace_min_width = 0;
if (!(bar->mode = strdup("dock"))) {
goto cleanup;
}
@@ -216,6 +217,9 @@ static void invoke_swaybar(struct bar_config *bar) {
sigset_t set;
sigemptyset(&set);
sigprocmask(SIG_SETMASK, &set, NULL);
+ signal(SIGPIPE, SIG_DFL);
+
+ restore_nofile_limit();
pid = fork();
if (pid < 0) {
diff --git a/sway/config/input.c b/sway/config/input.c
index 2ed9c0165..a998e1704 100644
--- a/sway/config/input.c
+++ b/sway/config/input.c
@@ -40,6 +40,7 @@ struct input_config *new_input_config(const char* identifier) {
input->xkb_numlock = INT_MIN;
input->xkb_capslock = INT_MIN;
input->xkb_file_is_set = false;
+ input->tools = create_list();
return input;
}
@@ -153,6 +154,22 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
memcpy(dst->calibration_matrix.matrix, src->calibration_matrix.matrix,
sizeof(src->calibration_matrix.matrix));
}
+ for (int i = 0; i < src->tools->length; i++) {
+ struct input_config_tool *src_tool = src->tools->items[i];
+ for (int j = 0; j < dst->tools->length; j++) {
+ struct input_config_tool *dst_tool = dst->tools->items[j];
+ if (src_tool->type == dst_tool->type) {
+ dst_tool->mode = src_tool->mode;
+ goto tool_merge_outer;
+ }
+ }
+
+ struct input_config_tool *dst_tool = malloc(sizeof(*dst_tool));
+ memcpy(dst_tool, src_tool, sizeof(*dst_tool));
+ list_add(dst->tools, dst_tool);
+
+ tool_merge_outer:;
+ }
}
static bool validate_xkb_merge(struct input_config *dest,
@@ -358,6 +375,7 @@ void free_input_config(struct input_config *ic) {
free(ic->mapped_from_region);
free(ic->mapped_to_output);
free(ic->mapped_to_region);
+ list_free_items_and_destroy(ic->tools);
free(ic);
}
diff --git a/sway/config/output.c b/sway/config/output.c
index b59cabd4e..6d39c2f55 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
#include "sway/config.h"
#include "sway/input/cursor.h"
#include "sway/output.h"
@@ -58,6 +59,7 @@ struct output_config *new_output_config(const char *name) {
oc->width = oc->height = -1;
oc->refresh_rate = -1;
oc->custom_mode = -1;
+ oc->drm_mode.type = -1;
oc->x = oc->y = -1;
oc->scale = -1;
oc->scale_filter = SCALE_FILTER_DEFAULT;
@@ -99,6 +101,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
if (src->custom_mode != -1) {
dst->custom_mode = src->custom_mode;
}
+ if (src->drm_mode.type != (uint32_t) -1) {
+ memcpy(&dst->drm_mode, &src->drm_mode, sizeof(src->drm_mode));
+ }
if (src->transform != -1) {
dst->transform = src->transform;
}
@@ -237,7 +242,10 @@ struct output_config *store_output_config(struct output_config *oc) {
static void set_mode(struct wlr_output *output, int width, int height,
float refresh_rate, bool custom) {
- int mhz = (int)(refresh_rate * 1000);
+ // Not all floating point integers can be represented exactly
+ // as (int)(1000 * mHz / 1000.f)
+ // round() the result to avoid any error
+ int mhz = (int)round(refresh_rate * 1000);
if (wl_list_empty(&output->modes) || custom) {
sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name);
@@ -268,6 +276,18 @@ static void set_mode(struct wlr_output *output, int width, int height,
wlr_output_set_mode(output, best);
}
+static void set_modeline(struct wlr_output *output, drmModeModeInfo *drm_mode) {
+ if (!wlr_output_is_drm(output)) {
+ sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
+ return;
+ }
+ sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name);
+ struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode);
+ if (mode) {
+ wlr_output_set_mode(output, mode);
+ }
+}
+
/* Some manufacturers hardcode the aspect-ratio of the output in the physical
* size field. */
static bool phys_size_is_aspect_ratio(struct wlr_output *output) {
@@ -348,14 +368,36 @@ static void queue_output_config(struct output_config *oc,
sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name);
wlr_output_enable(wlr_output, true);
- if (oc && oc->width > 0 && oc->height > 0) {
+ if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) {
+ sway_log(SWAY_DEBUG, "Set %s modeline",
+ wlr_output->name);
+ set_modeline(wlr_output, &oc->drm_mode);
+ } else if (oc && oc->width > 0 && oc->height > 0) {
sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)",
wlr_output->name, oc->width, oc->height, oc->refresh_rate);
set_mode(wlr_output, oc->width, oc->height,
oc->refresh_rate, oc->custom_mode == 1);
} else if (!wl_list_empty(&wlr_output->modes)) {
- struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
- wlr_output_set_mode(wlr_output, mode);
+ sway_log(SWAY_DEBUG, "Set preferred mode");
+ struct wlr_output_mode *preferred_mode =
+ wlr_output_preferred_mode(wlr_output);
+ wlr_output_set_mode(wlr_output, preferred_mode);
+
+ if (!wlr_output_test(wlr_output)) {
+ sway_log(SWAY_DEBUG, "Preferred mode rejected, "
+ "falling back to another mode");
+ struct wlr_output_mode *mode;
+ wl_list_for_each(mode, &wlr_output->modes, link) {
+ if (mode == preferred_mode) {
+ continue;
+ }
+
+ wlr_output_set_mode(wlr_output, mode);
+ if (wlr_output_test(wlr_output)) {
+ break;
+ }
+ }
+ }
}
if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) {
@@ -364,9 +406,16 @@ static void queue_output_config(struct output_config *oc,
wlr_output_set_subpixel(wlr_output, oc->subpixel);
}
+ enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL;
if (oc && oc->transform >= 0) {
- sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, oc->transform);
- wlr_output_set_transform(wlr_output, oc->transform);
+ tr = oc->transform;
+ } else if (wlr_output_is_drm(wlr_output)) {
+ tr = wlr_drm_connector_get_panel_orientation(wlr_output);
+ sway_log(SWAY_DEBUG, "Auto-detected output transform: %d", tr);
+ }
+ if (wlr_output->transform != tr) {
+ sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, tr);
+ wlr_output_set_transform(wlr_output, tr);
}
// Apply the scale last before the commit, because the scale auto-detection
@@ -480,6 +529,8 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
// this output came online, and some config items (like map_to_output) are
// dependent on an output being present.
input_manager_configure_all_inputs();
+ // Reconfigure the cursor images, since the scale may have changed.
+ input_manager_configure_xcursor();
return true;
}
@@ -699,6 +750,8 @@ static bool _spawn_swaybg(char **command) {
sway_log_errno(SWAY_ERROR, "fork failed");
return false;
} else if (pid == 0) {
+ restore_nofile_limit();
+
pid = fork();
if (pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed");
diff --git a/sway/config/seat.c b/sway/config/seat.c
index e2702de5d..84260aa39 100644
--- a/sway/config/seat.c
+++ b/sway/config/seat.c
@@ -29,6 +29,7 @@ struct seat_config *new_seat_config(const char* name) {
return NULL;
}
seat->hide_cursor_timeout = -1;
+ seat->hide_cursor_when_typing = HIDE_WHEN_TYPING_DEFAULT;
seat->allow_constrain = CONSTRAIN_DEFAULT;
seat->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT;
seat->keyboard_grouping = KEYBOARD_GROUP_DEFAULT;
@@ -151,6 +152,10 @@ void merge_seat_config(struct seat_config *dest, struct seat_config *source) {
dest->hide_cursor_timeout = source->hide_cursor_timeout;
}
+ if (source->hide_cursor_when_typing != HIDE_WHEN_TYPING_DEFAULT) {
+ dest->hide_cursor_when_typing = source->hide_cursor_when_typing;
+ }
+
if (source->allow_constrain != CONSTRAIN_DEFAULT) {
dest->allow_constrain = source->allow_constrain;
}
diff --git a/sway/criteria.c b/sway/criteria.c
index 02b04fc89..d2a5566f6 100644
--- a/sway/criteria.c
+++ b/sway/criteria.c
@@ -188,7 +188,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->title->match_type) {
case PATTERN_FOCUSED:
- if (focused && strcmp(title, view_get_title(focused))) {
+ if (focused && lenient_strcmp(title, view_get_title(focused))) {
return false;
}
break;
@@ -228,7 +228,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->app_id->match_type) {
case PATTERN_FOCUSED:
- if (focused && strcmp(app_id, view_get_app_id(focused))) {
+ if (focused && lenient_strcmp(app_id, view_get_app_id(focused))) {
return false;
}
break;
@@ -260,7 +260,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->class->match_type) {
case PATTERN_FOCUSED:
- if (focused && strcmp(class, view_get_class(focused))) {
+ if (focused && lenient_strcmp(class, view_get_class(focused))) {
return false;
}
break;
@@ -351,7 +351,7 @@ static bool criteria_matches_view(struct criteria *criteria,
}
if (criteria->workspace) {
- struct sway_workspace *ws = view->container->workspace;
+ struct sway_workspace *ws = view->container->pending.workspace;
if (!ws) {
return false;
}
@@ -359,7 +359,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->workspace->match_type) {
case PATTERN_FOCUSED:
if (focused &&
- strcmp(ws->name, focused->container->workspace->name)) {
+ strcmp(ws->name, focused->container->pending.workspace->name)) {
return false;
}
break;
diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c
index a5cfd5b25..823530385 100644
--- a/sway/desktop/idle_inhibit_v1.c
+++ b/sway/desktop/idle_inhibit_v1.c
@@ -36,7 +36,7 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) {
inhibitor->manager = manager;
inhibitor->mode = INHIBIT_IDLE_APPLICATION;
- inhibitor->view = view_from_wlr_surface(wlr_inhibitor->surface);
+ inhibitor->wlr_inhibitor = wlr_inhibitor;
wl_list_insert(&manager->inhibitors, &inhibitor->link);
inhibitor->destroy.notify = handle_destroy;
@@ -69,8 +69,8 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view(
struct sway_idle_inhibitor_v1 *inhibitor;
wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors,
link) {
- if (inhibitor->view == view &&
- inhibitor->mode != INHIBIT_IDLE_APPLICATION) {
+ if (inhibitor->mode != INHIBIT_IDLE_APPLICATION &&
+ inhibitor->view == view) {
return inhibitor;
}
}
@@ -82,8 +82,8 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_vi
struct sway_idle_inhibitor_v1 *inhibitor;
wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors,
link) {
- if (inhibitor->view == view &&
- inhibitor->mode == INHIBIT_IDLE_APPLICATION) {
+ if (inhibitor->mode == INHIBIT_IDLE_APPLICATION &&
+ view_from_wlr_surface(inhibitor->wlr_inhibitor->surface) == view) {
return inhibitor;
}
}
@@ -104,10 +104,10 @@ void sway_idle_inhibit_v1_user_inhibitor_destroy(
bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) {
switch (inhibitor->mode) {
- case INHIBIT_IDLE_APPLICATION:
+ case INHIBIT_IDLE_APPLICATION:;
// If there is no view associated with the inhibitor, assume visible
- return !inhibitor->view || !inhibitor->view->container ||
- view_is_visible(inhibitor->view);
+ struct sway_view *view = view_from_wlr_surface(inhibitor->wlr_inhibitor->surface);
+ return !view || !view->container || view_is_visible(view);
case INHIBIT_IDLE_FOCUS:;
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &server.input->seats, link) {
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 738b17979..7f5a337b3 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -2,7 +2,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -115,9 +114,10 @@ static void arrange_layer(struct sway_output *output, struct wl_list *list,
// Horizontal axis
const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
- if ((state->anchor & both_horiz) && box.width == 0) {
+ if (box.width == 0) {
box.x = bounds.x;
- box.width = bounds.width;
+ } else if ((state->anchor & both_horiz) == both_horiz) {
+ box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
box.x = bounds.x;
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
@@ -128,9 +128,10 @@ static void arrange_layer(struct sway_output *output, struct wl_list *list,
// Vertical axis
const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
| ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
- if ((state->anchor & both_vert) && box.height == 0) {
+ if (box.height == 0) {
box.y = bounds.y;
- box.height = bounds.height;
+ } else if ((state->anchor & both_vert) == both_vert) {
+ box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
box.y = bounds.y;
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
@@ -139,25 +140,30 @@ static void arrange_layer(struct sway_output *output, struct wl_list *list,
box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
}
// Margin
- if ((state->anchor & both_horiz) == both_horiz) {
+ if (box.width == 0) {
box.x += state->margin.left;
- box.width -= state->margin.left + state->margin.right;
+ box.width = bounds.width -
+ (state->margin.left + state->margin.right);
+ } else if ((state->anchor & both_horiz) == both_horiz) {
+ // don't apply margins
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
box.x += state->margin.left;
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
box.x -= state->margin.right;
}
- if ((state->anchor & both_vert) == both_vert) {
+ if (box.height == 0) {
box.y += state->margin.top;
- box.height -= state->margin.top + state->margin.bottom;
+ box.height = bounds.height -
+ (state->margin.top + state->margin.bottom);
+ } else if ((state->anchor & both_vert) == both_vert) {
+ // don't apply margins
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
box.y += state->margin.top;
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
box.y -= state->margin.bottom;
}
- if (box.width < 0 || box.height < 0) {
- // TODO: Bubble up a protocol error?
- wlr_layer_surface_v1_close(layer);
+ if (!sway_assert(box.width >= 0 && box.height >= 0,
+ "Expected layer surface to have positive size")) {
continue;
}
// Apply
@@ -191,7 +197,7 @@ void arrange_layers(struct sway_output *output) {
arrange_output(output);
}
- // Arrange non-exlusive surfaces from top->bottom
+ // Arrange non-exclusive surfaces from top->bottom
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
&usable_area, false);
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
@@ -277,7 +283,7 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) {
}
sway_layer->layer_surface->output = NULL;
- wlr_layer_surface_v1_close(sway_layer->layer_surface);
+ wlr_layer_surface_v1_destroy(sway_layer->layer_surface);
}
static void handle_surface_commit(struct wl_listener *listener, void *data) {
@@ -290,21 +296,30 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
}
struct sway_output *output = wlr_output->data;
- struct wlr_box old_geo = layer->geo;
- arrange_layers(output);
+ struct wlr_box old_extent = layer->extent;
- bool geo_changed =
- memcmp(&old_geo, &layer->geo, sizeof(struct wlr_box)) != 0;
- bool layer_changed = layer->layer != layer_surface->current.layer;
- if (layer_changed) {
- wl_list_remove(&layer->link);
- wl_list_insert(&output->layers[layer_surface->current.layer],
- &layer->link);
- layer->layer = layer_surface->current.layer;
+ bool layer_changed = false;
+ if (layer_surface->current.committed != 0
+ || layer->mapped != layer_surface->mapped) {
+ layer->mapped = layer_surface->mapped;
+ layer_changed = layer->layer != layer_surface->current.layer;
+ if (layer_changed) {
+ wl_list_remove(&layer->link);
+ wl_list_insert(&output->layers[layer_surface->current.layer],
+ &layer->link);
+ layer->layer = layer_surface->current.layer;
+ }
+ arrange_layers(output);
}
- if (geo_changed || layer_changed) {
- output_damage_surface(output, old_geo.x, old_geo.y,
- layer_surface->surface, true);
+
+ wlr_surface_get_extends(layer_surface->surface, &layer->extent);
+ layer->extent.x += layer->geo.x;
+ layer->extent.y += layer->geo.y;
+
+ bool extent_changed =
+ memcmp(&old_extent, &layer->extent, sizeof(struct wlr_box)) != 0;
+ if (extent_changed || layer_changed) {
+ output_damage_box(output, &old_extent);
output_damage_surface(output, layer->geo.x, layer->geo.y,
layer_surface->surface, true);
} else {
@@ -351,6 +366,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&sway_layer->unmap.link);
wl_list_remove(&sway_layer->surface_commit.link);
wl_list_remove(&sway_layer->new_popup.link);
+ wl_list_remove(&sway_layer->new_subsurface.link);
if (sway_layer->layer_surface->output != NULL) {
struct sway_output *output = sway_layer->layer_surface->output->data;
if (output != NULL) {
@@ -380,6 +396,82 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
unmap(sway_layer);
}
+static void subsurface_damage(struct sway_layer_subsurface *subsurface,
+ bool whole) {
+ struct sway_layer_surface *layer = subsurface->layer_surface;
+ struct wlr_output *wlr_output = layer->layer_surface->output;
+ if (!wlr_output) {
+ return;
+ }
+ struct sway_output *output = wlr_output->data;
+ int ox = subsurface->wlr_subsurface->current.x + layer->geo.x;
+ int oy = subsurface->wlr_subsurface->current.y + layer->geo.y;
+ output_damage_surface(
+ output, ox, oy, subsurface->wlr_subsurface->surface, whole);
+}
+
+static void subsurface_handle_unmap(struct wl_listener *listener, void *data) {
+ struct sway_layer_subsurface *subsurface =
+ wl_container_of(listener, subsurface, unmap);
+ subsurface_damage(subsurface, true);
+}
+
+static void subsurface_handle_map(struct wl_listener *listener, void *data) {
+ struct sway_layer_subsurface *subsurface =
+ wl_container_of(listener, subsurface, map);
+ subsurface_damage(subsurface, true);
+}
+
+static void subsurface_handle_commit(struct wl_listener *listener, void *data) {
+ struct sway_layer_subsurface *subsurface =
+ wl_container_of(listener, subsurface, commit);
+ subsurface_damage(subsurface, false);
+}
+
+static void subsurface_handle_destroy(struct wl_listener *listener,
+ void *data) {
+ struct sway_layer_subsurface *subsurface =
+ wl_container_of(listener, subsurface, destroy);
+
+ wl_list_remove(&subsurface->map.link);
+ wl_list_remove(&subsurface->unmap.link);
+ wl_list_remove(&subsurface->destroy.link);
+ wl_list_remove(&subsurface->commit.link);
+ free(subsurface);
+}
+
+static struct sway_layer_subsurface *create_subsurface(
+ struct wlr_subsurface *wlr_subsurface,
+ struct sway_layer_surface *layer_surface) {
+ struct sway_layer_subsurface *subsurface =
+ calloc(1, sizeof(struct sway_layer_subsurface));
+ if (subsurface == NULL) {
+ return NULL;
+ }
+
+ subsurface->wlr_subsurface = wlr_subsurface;
+ subsurface->layer_surface = layer_surface;
+
+ subsurface->map.notify = subsurface_handle_map;
+ wl_signal_add(&wlr_subsurface->events.map, &subsurface->map);
+ subsurface->unmap.notify = subsurface_handle_unmap;
+ wl_signal_add(&wlr_subsurface->events.unmap, &subsurface->unmap);
+ subsurface->destroy.notify = subsurface_handle_destroy;
+ wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
+ subsurface->commit.notify = subsurface_handle_commit;
+ wl_signal_add(&wlr_subsurface->surface->events.commit, &subsurface->commit);
+
+ return subsurface;
+}
+
+static void handle_new_subsurface(struct wl_listener *listener, void *data) {
+ struct sway_layer_surface *sway_layer_surface =
+ wl_container_of(listener, sway_layer_surface, new_subsurface);
+ struct wlr_subsurface *wlr_subsurface = data;
+ create_subsurface(wlr_subsurface, sway_layer_surface);
+}
+
+
static struct sway_layer_surface *popup_get_layer(
struct sway_layer_popup *popup) {
while (popup->parent_type == LAYER_PARENT_POPUP) {
@@ -391,8 +483,8 @@ static struct sway_layer_surface *popup_get_layer(
static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) {
struct wlr_xdg_popup *popup = layer_popup->wlr_popup;
struct wlr_surface *surface = popup->base->surface;
- int popup_sx = popup->geometry.x - popup->base->geometry.x;
- int popup_sy = popup->geometry.y - popup->base->geometry.y;
+ int popup_sx = popup->geometry.x - popup->base->current.geometry.x;
+ int popup_sy = popup->geometry.y - popup->base->current.geometry.y;
int ox = popup_sx, oy = popup_sy;
struct sway_layer_surface *layer;
while (true) {
@@ -513,14 +605,14 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
sway_log(SWAY_DEBUG, "new layer surface: namespace %s layer %d anchor %" PRIu32
" size %" PRIu32 "x%" PRIu32 " margin %" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",",
layer_surface->namespace,
- layer_surface->client_pending.layer,
- layer_surface->client_pending.anchor,
- layer_surface->client_pending.desired_width,
- layer_surface->client_pending.desired_height,
- layer_surface->client_pending.margin.top,
- layer_surface->client_pending.margin.right,
- layer_surface->client_pending.margin.bottom,
- layer_surface->client_pending.margin.left);
+ layer_surface->pending.layer,
+ layer_surface->pending.anchor,
+ layer_surface->pending.desired_width,
+ layer_surface->pending.desired_height,
+ layer_surface->pending.margin.top,
+ layer_surface->pending.margin.right,
+ layer_surface->pending.margin.bottom,
+ layer_surface->pending.margin.left);
if (!layer_surface->output) {
// Assign last active output
@@ -537,7 +629,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
sway_log(SWAY_ERROR,
"no output to auto-assign layer surface '%s' to",
layer_surface->namespace);
- wlr_layer_surface_v1_close(layer_surface);
+ wlr_layer_surface_v1_destroy(layer_surface);
return;
}
output = root->outputs->items[0];
@@ -563,6 +655,9 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
wl_signal_add(&layer_surface->events.unmap, &sway_layer->unmap);
sway_layer->new_popup.notify = handle_new_popup;
wl_signal_add(&layer_surface->events.new_popup, &sway_layer->new_popup);
+ sway_layer->new_subsurface.notify = handle_new_subsurface;
+ wl_signal_add(&layer_surface->surface->events.new_subsurface,
+ &sway_layer->new_subsurface);
sway_layer->layer_surface = layer_surface;
layer_surface->data = sway_layer;
@@ -571,13 +666,13 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
sway_layer->output_destroy.notify = handle_output_destroy;
wl_signal_add(&output->events.destroy, &sway_layer->output_destroy);
- wl_list_insert(&output->layers[layer_surface->client_pending.layer],
+ wl_list_insert(&output->layers[layer_surface->pending.layer],
&sway_layer->link);
- // Temporarily set the layer's current state to client_pending
+ // Temporarily set the layer's current state to pending
// So that we can easily arrange it
struct wlr_layer_surface_v1_state old_state = layer_surface->current;
- layer_surface->current = layer_surface->client_pending;
+ layer_surface->current = layer_surface->pending;
arrange_layers(output);
layer_surface->current = old_state;
}
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 4d0e9b33c..5945b8cbf 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -4,9 +4,10 @@
#include
#include
#include
+#include
#include
-#include
#include
+#include
#include
#include
#include
@@ -56,26 +57,6 @@ struct sway_output *all_output_by_name_or_id(const char *name_or_id) {
return NULL;
}
-/**
- * Rotate a child's position relative to a parent. The parent size is (pw, ph),
- * the child position is (*sx, *sy) and its size is (sw, sh).
- */
-static void rotate_child_position(double *sx, double *sy, double sw, double sh,
- double pw, double ph, float rotation) {
- if (rotation == 0.0f) {
- return;
- }
-
- // Coordinates relative to the center of the subsurface
- double ox = *sx - pw/2 + sw/2,
- oy = *sy - ph/2 + sh/2;
- // Rotated coordinates
- double rx = cos(-rotation)*ox - sin(-rotation)*oy,
- ry = cos(-rotation)*oy + sin(-rotation)*ox;
- *sx = rx + pw/2 - sw/2;
- *sy = ry + ph/2 - sh/2;
-}
-
struct surface_iterator_data {
sway_surface_iterator_func_t user_iterator;
void *user_data;
@@ -84,7 +65,6 @@ struct surface_iterator_data {
struct sway_view *view;
double ox, oy;
int width, height;
- float rotation;
};
static bool get_surface_box(struct surface_iterator_data *data,
@@ -99,14 +79,9 @@ static bool get_surface_box(struct surface_iterator_data *data,
int sw = surface->current.width;
int sh = surface->current.height;
- double _sx = sx + surface->sx;
- double _sy = sy + surface->sy;
- rotate_child_position(&_sx, &_sy, sw, sh, data->width, data->height,
- data->rotation);
-
struct wlr_box box = {
- .x = data->ox + _sx,
- .y = data->oy + _sy,
+ .x = floor(data->ox + sx),
+ .y = floor(data->oy + sy),
.width = sw,
.height = sh,
};
@@ -114,16 +89,13 @@ static bool get_surface_box(struct surface_iterator_data *data,
memcpy(surface_box, &box, sizeof(struct wlr_box));
}
- struct wlr_box rotated_box;
- wlr_box_rotated_bounds(&rotated_box, &box, data->rotation);
-
struct wlr_box output_box = {
.width = output->width,
.height = output->height,
};
struct wlr_box intersection;
- return wlr_box_intersection(&intersection, &output_box, &rotated_box);
+ return wlr_box_intersection(&intersection, &output_box, &box);
}
static void output_for_each_surface_iterator(struct wlr_surface *surface,
@@ -136,7 +108,7 @@ static void output_for_each_surface_iterator(struct wlr_surface *surface,
return;
}
- data->user_iterator(data->output, data->view, surface, &box, data->rotation,
+ data->user_iterator(data->output, data->view, surface, &box,
data->user_data);
}
@@ -152,7 +124,6 @@ void output_surface_for_each_surface(struct sway_output *output,
.oy = oy,
.width = surface->current.width,
.height = surface->current.height,
- .rotation = 0,
};
wlr_surface_for_each_surface(surface,
@@ -173,13 +144,12 @@ void output_view_for_each_surface(struct sway_output *output,
- view->geometry.y,
.width = view->container->current.content_width,
.height = view->container->current.content_height,
- .rotation = 0, // TODO
};
view_for_each_surface(view, output_for_each_surface_iterator, &data);
}
-void output_view_for_each_popup(struct sway_output *output,
+void output_view_for_each_popup_surface(struct sway_output *output,
struct sway_view *view, sway_surface_iterator_func_t iterator,
void *user_data) {
struct surface_iterator_data data = {
@@ -193,10 +163,9 @@ void output_view_for_each_popup(struct sway_output *output,
- view->geometry.y,
.width = view->container->current.content_width,
.height = view->container->current.content_height,
- .rotation = 0, // TODO
};
- view_for_each_popup(view, output_for_each_surface_iterator, &data);
+ view_for_each_popup_surface(view, output_for_each_surface_iterator, &data);
}
void output_layer_for_each_surface(struct sway_output *output,
@@ -206,44 +175,23 @@ void output_layer_for_each_surface(struct sway_output *output,
wl_list_for_each(layer_surface, layer_surfaces, link) {
struct wlr_layer_surface_v1 *wlr_layer_surface_v1 =
layer_surface->layer_surface;
- output_surface_for_each_surface(output, wlr_layer_surface_v1->surface,
- layer_surface->geo.x, layer_surface->geo.y, iterator,
- user_data);
-
- struct wlr_xdg_popup *state;
- wl_list_for_each(state, &wlr_layer_surface_v1->popups, link) {
- struct wlr_xdg_surface *popup = state->base;
- if (!popup->configured) {
- continue;
- }
-
- double popup_sx, popup_sy;
- popup_sx = layer_surface->geo.x +
- popup->popup->geometry.x - popup->geometry.x;
- popup_sy = layer_surface->geo.y +
- popup->popup->geometry.y - popup->geometry.y;
-
- struct wlr_surface *surface = popup->surface;
-
- struct surface_iterator_data data = {
- .user_iterator = iterator,
- .user_data = user_data,
- .output = output,
- .view = NULL,
- .ox = popup_sx,
- .oy = popup_sy,
- .width = surface->current.width,
- .height = surface->current.height,
- .rotation = 0,
- };
-
- wlr_xdg_surface_for_each_surface(
- popup, output_for_each_surface_iterator, &data);
- }
+ struct wlr_surface *surface = wlr_layer_surface_v1->surface;
+ struct surface_iterator_data data = {
+ .user_iterator = iterator,
+ .user_data = user_data,
+ .output = output,
+ .view = NULL,
+ .ox = layer_surface->geo.x,
+ .oy = layer_surface->geo.y,
+ .width = surface->current.width,
+ .height = surface->current.height,
+ };
+ wlr_layer_surface_v1_for_each_surface(wlr_layer_surface_v1,
+ output_for_each_surface_iterator, &data);
}
}
-void output_layer_for_each_surface_toplevel(struct sway_output *output,
+void output_layer_for_each_toplevel_surface(struct sway_output *output,
struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
void *user_data) {
struct sway_layer_surface *layer_surface;
@@ -257,44 +205,26 @@ void output_layer_for_each_surface_toplevel(struct sway_output *output,
}
-void output_layer_for_each_surface_popup(struct sway_output *output,
+void output_layer_for_each_popup_surface(struct sway_output *output,
struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
void *user_data) {
struct sway_layer_surface *layer_surface;
wl_list_for_each(layer_surface, layer_surfaces, link) {
struct wlr_layer_surface_v1 *wlr_layer_surface_v1 =
layer_surface->layer_surface;
-
- struct wlr_xdg_popup *state;
- wl_list_for_each(state, &wlr_layer_surface_v1->popups, link) {
- struct wlr_xdg_surface *popup = state->base;
- if (!popup->configured) {
- continue;
- }
-
- double popup_sx, popup_sy;
- popup_sx = layer_surface->geo.x +
- popup->popup->geometry.x - popup->geometry.x;
- popup_sy = layer_surface->geo.y +
- popup->popup->geometry.y - popup->geometry.y;
-
- struct wlr_surface *surface = popup->surface;
-
- struct surface_iterator_data data = {
- .user_iterator = iterator,
- .user_data = user_data,
- .output = output,
- .view = NULL,
- .ox = popup_sx,
- .oy = popup_sy,
- .width = surface->current.width,
- .height = surface->current.height,
- .rotation = 0,
- };
-
- wlr_xdg_surface_for_each_surface(
- popup, output_for_each_surface_iterator, &data);
- }
+ struct wlr_surface *surface = wlr_layer_surface_v1->surface;
+ struct surface_iterator_data data = {
+ .user_iterator = iterator,
+ .user_data = user_data,
+ .output = output,
+ .view = NULL,
+ .ox = layer_surface->geo.x,
+ .oy = layer_surface->geo.y,
+ .width = surface->current.width,
+ .height = surface->current.height,
+ };
+ wlr_layer_surface_v1_for_each_popup_surface(wlr_layer_surface_v1,
+ output_for_each_surface_iterator, &data);
}
}
@@ -463,9 +393,9 @@ struct send_frame_done_data {
int msec_until_refresh;
};
-static void send_frame_done_iterator(struct sway_output *output, struct sway_view *view,
- struct wlr_surface *surface, struct wlr_box *box, float rotation,
- void *user_data) {
+static void send_frame_done_iterator(struct sway_output *output,
+ struct sway_view *view, struct wlr_surface *surface,
+ struct wlr_box *box, void *user_data) {
int view_max_render_time = 0;
if (view != NULL) {
view_max_render_time = view->max_render_time;
@@ -488,9 +418,9 @@ static void send_frame_done(struct sway_output *output, struct send_frame_done_d
output_for_each_surface(output, send_frame_done_iterator, data);
}
-static void count_surface_iterator(struct sway_output *output, struct sway_view *view,
- struct wlr_surface *surface, struct wlr_box *_box, float rotation,
- void *data) {
+static void count_surface_iterator(struct sway_output *output,
+ struct sway_view *view, struct wlr_surface *surface,
+ struct wlr_box *box, void *data) {
size_t *n = data;
(*n)++;
}
@@ -548,10 +478,14 @@ static bool scan_out_fullscreen_view(struct sway_output *output,
return false;
}
+ wlr_output_attach_buffer(wlr_output, &surface->buffer->base);
+ if (!wlr_output_test(wlr_output)) {
+ return false;
+ }
+
wlr_presentation_surface_sampled_on_output(server.presentation, surface,
wlr_output);
- wlr_output_attach_buffer(wlr_output, &surface->buffer->base);
return wlr_output_commit(wlr_output);
}
@@ -573,17 +507,20 @@ static int output_repaint_timer_handler(void *data) {
fullscreen_con = workspace->current.fullscreen;
}
- if (fullscreen_con && fullscreen_con->view) {
+ if (fullscreen_con && fullscreen_con->view && !debug.noscanout) {
// Try to scan-out the fullscreen view
static bool last_scanned_out = false;
bool scanned_out =
scan_out_fullscreen_view(output, fullscreen_con->view);
if (scanned_out && !last_scanned_out) {
- sway_log(SWAY_DEBUG, "Scanning out fullscreen view");
+ sway_log(SWAY_DEBUG, "Scanning out fullscreen view on %s",
+ output->wlr_output->name);
}
if (last_scanned_out && !scanned_out) {
- sway_log(SWAY_DEBUG, "Stopping fullscreen view scan out");
+ sway_log(SWAY_DEBUG, "Stopping fullscreen view scan out on %s",
+ output->wlr_output->name);
+ output_damage_whole(output);
}
last_scanned_out = scanned_out;
@@ -687,18 +624,15 @@ void output_damage_whole(struct sway_output *output) {
}
}
-static void damage_surface_iterator(struct sway_output *output, struct sway_view *view,
- struct wlr_surface *surface, struct wlr_box *_box, float rotation,
- void *_data) {
+static void damage_surface_iterator(struct sway_output *output,
+ struct sway_view *view, struct wlr_surface *surface,
+ struct wlr_box *_box, void *_data) {
bool *data = _data;
bool whole = *data;
struct wlr_box box = *_box;
scale_box(&box, output->wlr_output->scale);
- int center_x = box.x + box.width/2;
- int center_y = box.y + box.height/2;
-
if (pixman_region32_not_empty(&surface->buffer_damage)) {
pixman_region32_t damage;
pixman_region32_init(&damage);
@@ -711,14 +645,11 @@ static void damage_surface_iterator(struct sway_output *output, struct sway_view
ceil(output->wlr_output->scale) - surface->current.scale);
}
pixman_region32_translate(&damage, box.x, box.y);
- wlr_region_rotated_bounds(&damage, &damage, rotation,
- center_x, center_y);
wlr_output_damage_add(output->damage, &damage);
pixman_region32_fini(&damage);
}
if (whole) {
- wlr_box_rotated_bounds(&box, &box, rotation);
wlr_output_damage_add_box(output->damage, &box);
}
@@ -810,7 +741,7 @@ static void update_output_manager_config(struct sway_server *server) {
struct wlr_box *output_box = wlr_output_layout_get_box(
root->output_layout, output->wlr_output);
// We mark the output enabled even if it is switched off by DPMS
- config_head->state.enabled = output->enabled;
+ config_head->state.enabled = output->current_mode != NULL && output->enabled;
config_head->state.mode = output->current_mode;
if (output_box) {
config_head->state.x = output_box->x;
@@ -832,9 +763,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
output_begin_destroy(output);
wl_list_remove(&output->destroy.link);
+ wl_list_remove(&output->commit.link);
wl_list_remove(&output->mode.link);
- wl_list_remove(&output->transform.link);
- wl_list_remove(&output->scale.link);
wl_list_remove(&output->present.link);
transaction_commit_dirty();
@@ -867,41 +797,37 @@ static void handle_mode(struct wl_listener *listener, void *data) {
update_output_manager_config(output->server);
}
-static void handle_transform(struct wl_listener *listener, void *data) {
- struct sway_output *output = wl_container_of(listener, output, transform);
- if (!output->enabled) {
- return;
- }
- arrange_layers(output);
- arrange_output(output);
- transaction_commit_dirty();
-
- update_output_manager_config(output->server);
-}
-
static void update_textures(struct sway_container *con, void *data) {
container_update_title_textures(con);
container_update_marks_textures(con);
}
-static void handle_scale(struct wl_listener *listener, void *data) {
- struct sway_output *output = wl_container_of(listener, output, scale);
+static void handle_commit(struct wl_listener *listener, void *data) {
+ struct sway_output *output = wl_container_of(listener, output, commit);
+ struct wlr_output_event_commit *event = data;
+
if (!output->enabled) {
return;
}
- arrange_layers(output);
- output_for_each_container(output, update_textures, NULL);
- arrange_output(output);
- transaction_commit_dirty();
- update_output_manager_config(output->server);
+ if (event->committed & WLR_OUTPUT_STATE_SCALE) {
+ output_for_each_container(output, update_textures, NULL);
+ }
+
+ if (event->committed & (WLR_OUTPUT_STATE_TRANSFORM | WLR_OUTPUT_STATE_SCALE)) {
+ arrange_layers(output);
+ arrange_output(output);
+ transaction_commit_dirty();
+
+ update_output_manager_config(output->server);
+ }
}
static void handle_present(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, present);
struct wlr_output_event_present *output_event = data;
- if (!output->enabled) {
+ if (!output->enabled || !output_event->presented) {
return;
}
@@ -912,7 +838,17 @@ static void handle_present(struct wl_listener *listener, void *data) {
void handle_new_output(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server, new_output);
struct wlr_output *wlr_output = data;
- sway_log(SWAY_DEBUG, "New output %p: %s", wlr_output, wlr_output->name);
+ sway_log(SWAY_DEBUG, "New output %p: %s (non-desktop: %d)",
+ wlr_output, wlr_output->name, wlr_output->non_desktop);
+
+ if (wlr_output->non_desktop) {
+ sway_log(SWAY_DEBUG, "Not configuring non-desktop output");
+ if (server->drm_lease_manager) {
+ wlr_drm_lease_v1_manager_offer_output(server->drm_lease_manager,
+ wlr_output);
+ }
+ return;
+ }
struct sway_output *output = output_create(wlr_output);
if (!output) {
@@ -925,12 +861,10 @@ void handle_new_output(struct wl_listener *listener, void *data) {
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
output->destroy.notify = handle_destroy;
+ wl_signal_add(&wlr_output->events.commit, &output->commit);
+ output->commit.notify = handle_commit;
wl_signal_add(&wlr_output->events.mode, &output->mode);
output->mode.notify = handle_mode;
- wl_signal_add(&wlr_output->events.transform, &output->transform);
- output->transform.notify = handle_transform;
- wl_signal_add(&wlr_output->events.scale, &output->scale);
- output->scale.notify = handle_scale;
wl_signal_add(&wlr_output->events.present, &output->present);
output->present.notify = handle_present;
wl_signal_add(&output->damage->events.frame, &output->damage_frame);
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index d3d927c83..17fc8f6fb 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -7,7 +7,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -32,6 +31,7 @@
struct render_data {
pixman_region32_t *damage;
float alpha;
+ struct wlr_box *clip_box;
};
/**
@@ -104,9 +104,6 @@ static void render_texture(struct wlr_output *wlr_output,
wlr_backend_get_renderer(wlr_output->backend);
struct sway_output *output = wlr_output->data;
- struct wlr_gles2_texture_attribs attribs;
- wlr_gles2_texture_get_attribs(texture, &attribs);
-
pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_union_rect(&damage, &damage, dst_box->x, dst_box->y,
@@ -133,9 +130,9 @@ damage_finish:
pixman_region32_fini(&damage);
}
-static void render_surface_iterator(struct sway_output *output, struct sway_view *view,
- struct wlr_surface *surface, struct wlr_box *_box, float rotation,
- void *_data) {
+static void render_surface_iterator(struct sway_output *output,
+ struct sway_view *view, struct wlr_surface *surface,
+ struct wlr_box *_box, void *_data) {
struct render_data *data = _data;
struct wlr_output *wlr_output = output->wlr_output;
pixman_region32_t *output_damage = data->damage;
@@ -149,15 +146,23 @@ static void render_surface_iterator(struct sway_output *output, struct sway_view
struct wlr_fbox src_box;
wlr_surface_get_buffer_source_box(surface, &src_box);
- struct wlr_box dst_box = *_box;
- scale_box(&dst_box, wlr_output->scale);
+ struct wlr_box proj_box = *_box;
+ scale_box(&proj_box, wlr_output->scale);
float matrix[9];
enum wl_output_transform transform =
wlr_output_transform_invert(surface->current.transform);
- wlr_matrix_project_box(matrix, &dst_box, transform, rotation,
+ wlr_matrix_project_box(matrix, &proj_box, transform, 0.0,
wlr_output->transform_matrix);
+ struct wlr_box dst_box = *_box;
+ struct wlr_box *clip_box = data->clip_box;
+ if (clip_box != NULL) {
+ dst_box.width = fmin(dst_box.width, clip_box->width);
+ dst_box.height = fmin(dst_box.height, clip_box->height);
+ }
+ scale_box(&dst_box, wlr_output->scale);
+
render_texture(wlr_output, output_damage, texture,
&src_box, &dst_box, matrix, alpha);
@@ -171,7 +176,7 @@ static void render_layer_toplevel(struct sway_output *output,
.damage = damage,
.alpha = 1.0f,
};
- output_layer_for_each_surface_toplevel(output, layer_surfaces,
+ output_layer_for_each_toplevel_surface(output, layer_surfaces,
render_surface_iterator, &data);
}
@@ -181,7 +186,7 @@ static void render_layer_popups(struct sway_output *output,
.damage = damage,
.alpha = 1.0f,
};
- output_layer_for_each_surface_popup(output, layer_surfaces,
+ output_layer_for_each_popup_surface(output, layer_surfaces,
render_surface_iterator, &data);
}
@@ -256,6 +261,14 @@ static void render_view_toplevels(struct sway_view *view,
.damage = damage,
.alpha = alpha,
};
+ struct wlr_box clip_box;
+ if (!container_is_current_floating(view->container)) {
+ // As we pass the geometry offsets to the surface iterator, we will
+ // need to account for the offsets in the clip dimensions.
+ clip_box.width = view->container->current.content_width + view->geometry.x;
+ clip_box.height = view->container->current.content_height + view->geometry.y;
+ data.clip_box = &clip_box;
+ }
// Render all toplevels without descending into popups
double ox = view->container->surface_x -
output->lx - view->geometry.x;
@@ -265,24 +278,14 @@ static void render_view_toplevels(struct sway_view *view,
render_surface_iterator, &data);
}
-static void render_popup_iterator(struct sway_output *output, struct sway_view *view,
- struct wlr_surface *surface, struct wlr_box *box, float rotation,
- void *data) {
- // Render this popup's surface
- render_surface_iterator(output, view, surface, box, rotation, data);
-
- // Render this popup's child toplevels
- output_surface_for_each_surface(output, surface, box->x, box->y,
- render_surface_iterator, data);
-}
-
static void render_view_popups(struct sway_view *view,
struct sway_output *output, pixman_region32_t *damage, float alpha) {
struct render_data data = {
.damage = damage,
.alpha = alpha,
};
- output_view_for_each_popup(output, view, render_popup_iterator, &data);
+ output_view_for_each_popup_surface(output, view,
+ render_surface_iterator, &data);
}
static void render_saved_view(struct sway_view *view,
@@ -292,17 +295,18 @@ static void render_saved_view(struct sway_view *view,
if (wl_list_empty(&view->saved_buffers)) {
return;
}
+
+ bool floating = container_is_current_floating(view->container);
+
struct sway_saved_buffer *saved_buf;
wl_list_for_each(saved_buf, &view->saved_buffers, link) {
if (!saved_buf->buffer->texture) {
continue;
}
- struct wlr_box box = {
- .x = view->container->surface_x - output->lx -
- view->saved_geometry.x + saved_buf->x,
- .y = view->container->surface_y - output->ly -
- view->saved_geometry.y + saved_buf->y,
+ struct wlr_box proj_box = {
+ .x = saved_buf->x - view->saved_geometry.x - output->lx,
+ .y = saved_buf->y - view->saved_geometry.y - output->ly,
.width = saved_buf->width,
.height = saved_buf->height,
};
@@ -313,20 +317,31 @@ static void render_saved_view(struct sway_view *view,
};
struct wlr_box intersection;
- bool intersects = wlr_box_intersection(&intersection, &output_box, &box);
+ bool intersects = wlr_box_intersection(&intersection, &output_box, &proj_box);
if (!intersects) {
continue;
}
- scale_box(&box, wlr_output->scale);
+ struct wlr_box dst_box = proj_box;
+ scale_box(&proj_box, wlr_output->scale);
float matrix[9];
enum wl_output_transform transform = wlr_output_transform_invert(saved_buf->transform);
- wlr_matrix_project_box(matrix, &box, transform, 0,
+ wlr_matrix_project_box(matrix, &proj_box, transform, 0,
wlr_output->transform_matrix);
+ if (!floating) {
+ dst_box.width = fmin(dst_box.width,
+ view->container->current.content_width -
+ (saved_buf->x - view->container->current.content_x) + view->saved_geometry.x);
+ dst_box.height = fmin(dst_box.height,
+ view->container->current.content_height -
+ (saved_buf->y - view->container->current.content_y) + view->saved_geometry.y);
+ }
+ scale_box(&dst_box, wlr_output->scale);
+
render_texture(wlr_output, damage, saved_buf->buffer->texture,
- &saved_buf->source_box, &box, matrix, alpha);
+ &saved_buf->source_box, &dst_box, matrix, alpha);
}
// FIXME: we should set the surface that this saved buffer originates from
@@ -358,8 +373,8 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
if (state->border_left) {
memcpy(&color, colors->child_border, sizeof(float) * 4);
premultiply_alpha(color, con->alpha);
- box.x = state->x;
- box.y = state->content_y;
+ box.x = floor(state->x);
+ box.y = floor(state->content_y);
box.width = state->border_thickness;
box.height = state->content_height;
scale_box(&box, output_scale);
@@ -371,14 +386,14 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
container_current_parent_layout(con);
if (state->border_right) {
- if (con->current.parent && siblings->length == 1 && layout == L_HORIZ) {
+ if (!container_is_current_floating(con) && siblings->length == 1 && layout == L_HORIZ) {
memcpy(&color, colors->indicator, sizeof(float) * 4);
} else {
memcpy(&color, colors->child_border, sizeof(float) * 4);
}
premultiply_alpha(color, con->alpha);
- box.x = state->content_x + state->content_width;
- box.y = state->content_y;
+ box.x = floor(state->content_x + state->content_width);
+ box.y = floor(state->content_y);
box.width = state->border_thickness;
box.height = state->content_height;
scale_box(&box, output_scale);
@@ -386,14 +401,14 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
}
if (state->border_bottom) {
- if (con->current.parent && siblings->length == 1 && layout == L_VERT) {
+ if (!container_is_current_floating(con) && siblings->length == 1 && layout == L_VERT) {
memcpy(&color, colors->indicator, sizeof(float) * 4);
} else {
memcpy(&color, colors->child_border, sizeof(float) * 4);
}
premultiply_alpha(color, con->alpha);
- box.x = state->x;
- box.y = state->content_y + state->content_height;
+ box.x = floor(state->x);
+ box.y = floor(state->content_y + state->content_height);
box.width = state->width;
box.height = state->border_thickness;
scale_box(&box, output_scale);
@@ -474,9 +489,10 @@ static void render_titlebar(struct sway_output *output,
int ob_marks_x = 0; // output-buffer-local
int ob_marks_width = 0; // output-buffer-local
if (config->show_marks && marks_texture) {
- struct wlr_box texture_box;
- wlr_texture_get_size(marks_texture,
- &texture_box.width, &texture_box.height);
+ struct wlr_box texture_box = {
+ .width = marks_texture->width,
+ .height = marks_texture->height,
+ };
ob_marks_width = texture_box.width;
// The marks texture might be shorter than the config->font_height, in
@@ -527,15 +543,23 @@ static void render_titlebar(struct sway_output *output,
int ob_title_x = 0; // output-buffer-local
int ob_title_width = 0; // output-buffer-local
if (title_texture) {
- struct wlr_box texture_box;
- wlr_texture_get_size(title_texture,
- &texture_box.width, &texture_box.height);
+ struct wlr_box texture_box = {
+ .width = title_texture->width,
+ .height = title_texture->height,
+ };
+
+ // The effective output may be NULL when con is not on any output.
+ // This can happen because we render all children of containers,
+ // even those that are out of the bounds of any output.
+ struct sway_output *effective = container_get_effective_output(con);
+ float title_scale = effective ? effective->wlr_output->scale : output_scale;
+ texture_box.width = texture_box.width * output_scale / title_scale;
+ texture_box.height = texture_box.height * output_scale / title_scale;
ob_title_width = texture_box.width;
// The title texture might be shorter than the config->font_height,
// in which case we need to pad it above and below.
- int ob_padding_above = round((config->font_baseline -
- con->title_baseline + titlebar_v_padding -
+ int ob_padding_above = round((titlebar_v_padding -
titlebar_border_thickness) * output_scale);
int ob_padding_below = ob_bg_height - ob_padding_above -
texture_box.height;
@@ -670,8 +694,8 @@ static void render_top_border(struct sway_output *output,
// Child border - top edge
memcpy(&color, colors->child_border, sizeof(float) * 4);
premultiply_alpha(color, con->alpha);
- box.x = state->x;
- box.y = state->y;
+ box.x = floor(state->x);
+ box.y = floor(state->y);
box.width = state->width;
box.height = state->border_thickness;
scale_box(&box, output_scale);
@@ -726,8 +750,8 @@ static void render_containers_linear(struct sway_output *output,
}
if (state->border == B_NORMAL) {
- render_titlebar(output, damage, child, state->x,
- state->y, state->width, colors,
+ render_titlebar(output, damage, child, floor(state->x),
+ floor(state->y), state->width, colors,
title_texture, marks_texture);
} else if (state->border == B_PIXEL) {
render_top_border(output, damage, child, colors);
@@ -781,7 +805,7 @@ static void render_containers_tabbed(struct sway_output *output,
marks_texture = child->marks_unfocused;
}
- int x = cstate->x + tab_width * i;
+ int x = floor(cstate->x + tab_width * i);
// Make last tab use the remaining width of the parent
if (i == parent->children->length - 1) {
@@ -894,8 +918,8 @@ static void render_container(struct sway_output *output,
struct parent_data data = {
.layout = con->current.layout,
.box = {
- .x = con->current.x,
- .y = con->current.y,
+ .x = floor(con->current.x),
+ .y = floor(con->current.y),
.width = con->current.width,
.height = con->current.height,
},
@@ -911,8 +935,8 @@ static void render_workspace(struct sway_output *output,
struct parent_data data = {
.layout = ws->current.layout,
.box = {
- .x = ws->current.x,
- .y = ws->current.y,
+ .x = floor(ws->current.x),
+ .y = floor(ws->current.y),
.width = ws->current.width,
.height = ws->current.height,
},
@@ -946,8 +970,8 @@ static void render_floating_container(struct sway_output *soutput,
}
if (con->current.border == B_NORMAL) {
- render_titlebar(soutput, damage, con, con->current.x,
- con->current.y, con->current.width, colors,
+ render_titlebar(soutput, damage, con, floor(con->current.x),
+ floor(con->current.y), con->current.width, colors,
title_texture, marks_texture);
} else if (con->current.border == B_PIXEL) {
render_top_border(soutput, damage, con, colors);
@@ -969,7 +993,7 @@ static void render_floating(struct sway_output *soutput,
}
for (int k = 0; k < ws->current.floating->length; ++k) {
struct sway_container *floater = ws->current.floating->items[k];
- if (floater->fullscreen_mode != FULLSCREEN_NONE) {
+ if (floater->current.fullscreen_mode != FULLSCREEN_NONE) {
continue;
}
render_floating_container(soutput, damage, floater);
@@ -1009,6 +1033,12 @@ void output_render(struct sway_output *output, struct timespec *when,
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
+ if (debug.damage == DAMAGE_RERENDER) {
+ int width, height;
+ wlr_output_transformed_resolution(wlr_output, &width, &height);
+ pixman_region32_union_rect(damage, damage, 0, 0, width, height);
+ }
+
if (!pixman_region32_not_empty(damage)) {
// Output isn't damaged but needs buffer swap
goto renderer_end;
@@ -1016,10 +1046,6 @@ void output_render(struct sway_output *output, struct timespec *when,
if (debug.damage == DAMAGE_HIGHLIGHT) {
wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1});
- } else if (debug.damage == DAMAGE_RERENDER) {
- int width, height;
- wlr_output_transformed_resolution(wlr_output, &width, &height);
- pixman_region32_union_rect(damage, damage, 0, 0, width, height);
}
if (output_has_opaque_overlay_layer_surface(output)) {
@@ -1120,7 +1146,7 @@ renderer_end:
wlr_region_transform(&frame_damage, &output->damage->current,
transform, width, height);
- if (debug.damage == DAMAGE_HIGHLIGHT) {
+ if (debug.damage != DAMAGE_DEFAULT) {
pixman_region32_union_rect(&frame_damage, &frame_damage,
0, 0, wlr_output->width, wlr_output->height);
}
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index 2b268e2c2..b1f3fb326 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -35,6 +35,8 @@ struct sway_transaction_instruction {
struct sway_container_state container_state;
};
uint32_t serial;
+ bool server_request;
+ bool waiting;
};
static struct sway_transaction *transaction_create(void) {
@@ -86,7 +88,11 @@ static void transaction_destroy(struct sway_transaction *transaction) {
static void copy_output_state(struct sway_output *output,
struct sway_transaction_instruction *instruction) {
struct sway_output_state *state = &instruction->output_state;
- state->workspaces = create_list();
+ if (state->workspaces) {
+ state->workspaces->length = 0;
+ } else {
+ state->workspaces = create_list();
+ }
list_cat(state->workspaces, output->workspaces);
state->active_workspace = output_get_active_workspace(output);
@@ -104,8 +110,16 @@ static void copy_workspace_state(struct sway_workspace *ws,
state->layout = ws->layout;
state->output = ws->output;
- state->floating = create_list();
- state->tiling = create_list();
+ if (state->floating) {
+ state->floating->length = 0;
+ } else {
+ state->floating = create_list();
+ }
+ if (state->tiling) {
+ state->tiling->length = 0;
+ } else {
+ state->tiling = create_list();
+ }
list_cat(state->floating, ws->floating);
list_cat(state->tiling, ws->tiling);
@@ -115,8 +129,8 @@ static void copy_workspace_state(struct sway_workspace *ws,
// Set focused_inactive_child to the direct tiling child
struct sway_container *focus = seat_get_focus_inactive_tiling(seat, ws);
if (focus) {
- while (focus->parent) {
- focus = focus->parent;
+ while (focus->pending.parent) {
+ focus = focus->pending.parent;
}
}
state->focused_inactive_child = focus;
@@ -126,28 +140,19 @@ static void copy_container_state(struct sway_container *container,
struct sway_transaction_instruction *instruction) {
struct sway_container_state *state = &instruction->container_state;
- state->layout = container->layout;
- state->x = container->x;
- state->y = container->y;
- state->width = container->width;
- state->height = container->height;
- state->fullscreen_mode = container->fullscreen_mode;
- state->parent = container->parent;
- state->workspace = container->workspace;
- state->border = container->border;
- state->border_thickness = container->border_thickness;
- state->border_top = container->border_top;
- state->border_left = container->border_left;
- state->border_right = container->border_right;
- state->border_bottom = container->border_bottom;
- state->content_x = container->content_x;
- state->content_y = container->content_y;
- state->content_width = container->content_width;
- state->content_height = container->content_height;
+ if (state->children) {
+ list_free(state->children);
+ }
+
+ memcpy(state, &container->pending, sizeof(struct sway_container_state));
if (!container->view) {
+ // We store a copy of the child list to avoid having it mutated after
+ // we copy the state.
state->children = create_list();
- list_cat(state->children, container->children);
+ list_cat(state->children, container->pending.children);
+ } else {
+ state->children = NULL;
}
struct sway_seat *seat = input_manager_current_seat();
@@ -161,14 +166,36 @@ static void copy_container_state(struct sway_container *container,
}
static void transaction_add_node(struct sway_transaction *transaction,
- struct sway_node *node) {
- struct sway_transaction_instruction *instruction =
- calloc(1, sizeof(struct sway_transaction_instruction));
- if (!sway_assert(instruction, "Unable to allocate instruction")) {
- return;
+ struct sway_node *node, bool server_request) {
+ struct sway_transaction_instruction *instruction = NULL;
+
+ // Check if we have an instruction for this node already, in which case we
+ // update that instead of creating a new one.
+ if (node->ntxnrefs > 0) {
+ for (int idx = 0; idx < transaction->instructions->length; idx++) {
+ struct sway_transaction_instruction *other =
+ transaction->instructions->items[idx];
+ if (other->node == node) {
+ instruction = other;
+ break;
+ }
+ }
+ }
+
+ if (!instruction) {
+ instruction = calloc(1, sizeof(struct sway_transaction_instruction));
+ if (!sway_assert(instruction, "Unable to allocate instruction")) {
+ return;
+ }
+ instruction->transaction = transaction;
+ instruction->node = node;
+ instruction->server_request = server_request;
+
+ list_add(transaction->instructions, instruction);
+ node->ntxnrefs++;
+ } else if (server_request) {
+ instruction->server_request = true;
}
- instruction->transaction = transaction;
- instruction->node = node;
switch (node->type) {
case N_ROOT:
@@ -183,9 +210,6 @@ static void transaction_add_node(struct sway_transaction *transaction,
copy_container_state(node->sway_container, instruction);
break;
}
-
- list_add(transaction->instructions, instruction);
- node->ntxnrefs++;
}
static void apply_output_state(struct sway_output *output,
@@ -214,8 +238,8 @@ static void apply_container_state(struct sway_container *container,
struct sway_saved_buffer *saved_buf;
wl_list_for_each(saved_buf, &view->saved_buffers, link) {
struct wlr_box box = {
- .x = container->current.content_x - view->saved_geometry.x + saved_buf->x,
- .y = container->current.content_y - view->saved_geometry.y + saved_buf->y,
+ .x = saved_buf->x - view->saved_geometry.x,
+ .y = saved_buf->y - view->saved_geometry.y,
.width = saved_buf->width,
.height = saved_buf->height,
};
@@ -238,6 +262,13 @@ static void apply_container_state(struct sway_container *container,
}
}
+ // If the view hasn't responded to the configure, center it within
+ // the container. This is important for fullscreen views which
+ // refuse to resize to the size of the output.
+ if (view && view->surface) {
+ view_center_surface(view);
+ }
+
// Damage the new location
desktop_damage_whole_container(container);
if (view && view->surface) {
@@ -251,24 +282,6 @@ static void apply_container_state(struct sway_container *container,
desktop_damage_box(&box);
}
- // If the view hasn't responded to the configure, center it within
- // the container. This is important for fullscreen views which
- // refuse to resize to the size of the output.
- if (view && view->surface) {
- if (view->geometry.width < container->current.content_width) {
- container->surface_x = container->current.content_x +
- (container->current.content_width - view->geometry.width) / 2;
- } else {
- container->surface_x = container->current.content_x;
- }
- if (view->geometry.height < container->current.content_height) {
- container->surface_y = container->current.content_y +
- (container->current.content_height - view->geometry.height) / 2;
- } else {
- container->surface_y = container->current.content_y;
- }
- }
-
if (!container->node.destroying) {
container_discover_outputs(container);
}
@@ -317,61 +330,25 @@ static void transaction_apply(struct sway_transaction *transaction) {
cursor_rebase_all();
}
-static void transaction_commit(struct sway_transaction *transaction);
+static void transaction_commit_pending(void);
-// Return true if both transactions operate on the same nodes
-static bool transaction_same_nodes(struct sway_transaction *a,
- struct sway_transaction *b) {
- if (a->instructions->length != b->instructions->length) {
- return false;
- }
- for (int i = 0; i < a->instructions->length; ++i) {
- struct sway_transaction_instruction *a_inst = a->instructions->items[i];
- struct sway_transaction_instruction *b_inst = b->instructions->items[i];
- if (a_inst->node != b_inst->node) {
- return false;
- }
- }
- return true;
-}
-
-static void transaction_progress_queue(void) {
- if (!server.transactions->length) {
+static void transaction_progress(void) {
+ if (!server.queued_transaction) {
return;
}
- // Only the first transaction in the queue is committed, so that's the one
- // we try to process.
- struct sway_transaction *transaction = server.transactions->items[0];
- if (transaction->num_waiting) {
+ if (server.queued_transaction->num_waiting > 0) {
return;
}
- transaction_apply(transaction);
- transaction_destroy(transaction);
- list_del(server.transactions, 0);
+ transaction_apply(server.queued_transaction);
+ transaction_destroy(server.queued_transaction);
+ server.queued_transaction = NULL;
- if (server.transactions->length == 0) {
- // The transaction queue is empty, so we're done.
+ if (!server.pending_transaction) {
sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
return;
}
- // If there's a bunch of consecutive transactions which all apply to the
- // same views, skip all except the last one.
- while (server.transactions->length >= 2) {
- struct sway_transaction *a = server.transactions->items[0];
- struct sway_transaction *b = server.transactions->items[1];
- if (transaction_same_nodes(a, b)) {
- list_del(server.transactions, 0);
- transaction_destroy(a);
- } else {
- break;
- }
- }
-
- // We again commit the first transaction in the queue to process it.
- transaction = server.transactions->items[0];
- transaction_commit(transaction);
- transaction_progress_queue();
+ transaction_commit_pending();
}
static int handle_timeout(void *data) {
@@ -379,7 +356,7 @@ static int handle_timeout(void *data) {
sway_log(SWAY_DEBUG, "Transaction %p timed out (%zi waiting)",
transaction, transaction->num_waiting);
transaction->num_waiting = 0;
- transaction_progress_queue();
+ transaction_progress();
return 0;
}
@@ -391,14 +368,21 @@ static bool should_configure(struct sway_node *node,
if (node->destroying) {
return false;
}
+ if (!instruction->server_request) {
+ return false;
+ }
struct sway_container_state *cstate = &node->sway_container->current;
struct sway_container_state *istate = &instruction->container_state;
#if HAVE_XWAYLAND
// Xwayland views are position-aware and need to be reconfigured
// when their position changes.
if (node->sway_container->view->type == SWAY_VIEW_XWAYLAND) {
- if (cstate->content_x != istate->content_x ||
- cstate->content_y != istate->content_y) {
+ // Sway logical coordinates are doubles, but they get truncated to
+ // integers when sent to Xwayland through `xcb_configure_window`.
+ // X11 apps will not respond to duplicate configure requests (from their
+ // truncated point of view) and cause transactions to time out.
+ if ((int)cstate->content_x != (int)istate->content_x ||
+ (int)cstate->content_y != (int)istate->content_y) {
return true;
}
}
@@ -418,13 +402,18 @@ static void transaction_commit(struct sway_transaction *transaction) {
struct sway_transaction_instruction *instruction =
transaction->instructions->items[i];
struct sway_node *node = instruction->node;
+ bool hidden = node_is_view(node) &&
+ !view_is_visible(node->sway_container->view);
if (should_configure(node, instruction)) {
instruction->serial = view_configure(node->sway_container->view,
instruction->container_state.content_x,
instruction->container_state.content_y,
instruction->container_state.content_width,
instruction->container_state.content_height);
- ++transaction->num_waiting;
+ if (!hidden) {
+ instruction->waiting = true;
+ ++transaction->num_waiting;
+ }
// From here on we are rendering a saved buffer of the view, which
// means we can send a frame done event to make the client redraw it
@@ -435,7 +424,8 @@ static void transaction_commit(struct sway_transaction *transaction) {
wlr_surface_send_frame_done(
node->sway_container->view->surface, &now);
}
- if (node_is_view(node) && wl_list_empty(&node->sway_container->view->saved_buffers)) {
+ if (!hidden && node_is_view(node) &&
+ wl_list_empty(&node->sway_container->view->saved_buffers)) {
view_save_buffer(node->sway_container->view);
memcpy(&node->sway_container->view->saved_geometry,
&node->sway_container->view->geometry,
@@ -470,6 +460,17 @@ static void transaction_commit(struct sway_transaction *transaction) {
}
}
+static void transaction_commit_pending(void) {
+ if (server.queued_transaction) {
+ return;
+ }
+ struct sway_transaction *transaction = server.pending_transaction;
+ server.pending_transaction = NULL;
+ server.queued_transaction = transaction;
+ transaction_commit(transaction);
+ transaction_progress();
+}
+
static void set_instruction_ready(
struct sway_transaction_instruction *instruction) {
struct sway_transaction *transaction = instruction->transaction;
@@ -488,13 +489,14 @@ static void set_instruction_ready(
}
// If the transaction has timed out then its num_waiting will be 0 already.
- if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) {
+ if (instruction->waiting && transaction->num_waiting > 0 &&
+ --transaction->num_waiting == 0) {
sway_log(SWAY_DEBUG, "Transaction %p is ready", transaction);
wl_event_source_timer_update(transaction->timer, 0);
}
instruction->node->instruction = NULL;
- transaction_progress_queue();
+ transaction_progress();
}
void transaction_notify_view_ready_by_serial(struct sway_view *view,
@@ -506,39 +508,45 @@ void transaction_notify_view_ready_by_serial(struct sway_view *view,
}
}
-void transaction_notify_view_ready_by_size(struct sway_view *view,
- int width, int height) {
+void transaction_notify_view_ready_by_geometry(struct sway_view *view,
+ double x, double y, int width, int height) {
struct sway_transaction_instruction *instruction =
view->container->node.instruction;
if (instruction != NULL &&
+ (int)instruction->container_state.content_x == (int)x &&
+ (int)instruction->container_state.content_y == (int)y &&
instruction->container_state.content_width == width &&
instruction->container_state.content_height == height) {
set_instruction_ready(instruction);
}
}
-void transaction_commit_dirty(void) {
+static void _transaction_commit_dirty(bool server_request) {
if (!server.dirty_nodes->length) {
return;
}
- struct sway_transaction *transaction = transaction_create();
- if (!transaction) {
- return;
+
+ if (!server.pending_transaction) {
+ server.pending_transaction = transaction_create();
+ if (!server.pending_transaction) {
+ return;
+ }
}
+
for (int i = 0; i < server.dirty_nodes->length; ++i) {
struct sway_node *node = server.dirty_nodes->items[i];
- transaction_add_node(transaction, node);
+ transaction_add_node(server.pending_transaction, node, server_request);
node->dirty = false;
}
server.dirty_nodes->length = 0;
- list_add(server.transactions, transaction);
-
- // We only commit the first transaction added to the queue.
- if (server.transactions->length == 1) {
- transaction_commit(transaction);
- // Attempting to progress the queue here is useful
- // if the transaction has nothing to wait for.
- transaction_progress_queue();
- }
+ transaction_commit_pending();
+}
+
+void transaction_commit_dirty(void) {
+ _transaction_commit_dirty(true);
+}
+
+void transaction_commit_dirty_client(void) {
+ _transaction_commit_dirty(false);
}
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index 03f372416..c1e5bc681 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -21,18 +21,15 @@
static const struct sway_view_child_impl popup_impl;
-static void popup_get_root_coords(struct sway_view_child *child,
- int *root_sx, int *root_sy) {
+static void popup_get_view_coords(struct sway_view_child *child,
+ int *sx, int *sy) {
struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child;
struct wlr_xdg_surface *surface = popup->wlr_xdg_surface;
- int x_offset = -child->view->geometry.x - surface->geometry.x;
- int y_offset = -child->view->geometry.y - surface->geometry.y;
-
wlr_xdg_popup_get_toplevel_coords(surface->popup,
- x_offset + surface->popup->geometry.x,
- y_offset + surface->popup->geometry.y,
- root_sx, root_sy);
+ surface->popup->geometry.x - surface->current.geometry.x,
+ surface->popup->geometry.y - surface->current.geometry.y,
+ sx, sy);
}
static void popup_destroy(struct sway_view_child *child) {
@@ -47,7 +44,7 @@ static void popup_destroy(struct sway_view_child *child) {
}
static const struct sway_view_child_impl popup_impl = {
- .get_root_coords = popup_get_root_coords,
+ .get_view_coords = popup_get_view_coords,
.destroy = popup_destroy,
};
@@ -70,13 +67,13 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) {
struct sway_view *view = popup->child.view;
struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup;
- struct sway_output *output = view->container->workspace->output;
+ struct sway_output *output = view->container->pending.workspace->output;
// the output box expressed in the coordinate system of the toplevel parent
// of the popup
struct wlr_box output_toplevel_sx_box = {
- .x = output->lx - view->container->content_x,
- .y = output->ly - view->container->content_y,
+ .x = output->lx - view->container->pending.content_x,
+ .y = output->ly - view->container->pending.content_y,
.width = output->width,
.height = output->height,
};
@@ -211,12 +208,13 @@ static void for_each_surface(struct sway_view *view,
user_data);
}
-static void for_each_popup(struct sway_view *view,
+static void for_each_popup_surface(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data) {
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface, iterator, user_data);
+ wlr_xdg_surface_for_each_popup_surface(view->wlr_xdg_surface, iterator,
+ user_data);
}
static bool is_transient_for(struct sway_view *child,
@@ -271,7 +269,7 @@ static const struct sway_view_impl view_impl = {
.set_resizing = set_resizing,
.wants_floating = wants_floating,
.for_each_surface = for_each_surface,
- .for_each_popup = for_each_popup,
+ .for_each_popup_surface = for_each_popup_surface,
.is_transient_for = is_transient_for,
.close = _close,
.close_popups = close_popups,
@@ -284,29 +282,31 @@ static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_view *view = &xdg_shell_view->view;
struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface;
- if (view->container->node.instruction) {
- wlr_xdg_surface_get_geometry(xdg_surface, &view->geometry);
- transaction_notify_view_ready_by_serial(view,
- xdg_surface->configure_serial);
- } else {
- struct wlr_box new_geo;
- wlr_xdg_surface_get_geometry(xdg_surface, &new_geo);
+ struct wlr_box new_geo;
+ wlr_xdg_surface_get_geometry(xdg_surface, &new_geo);
+ bool new_size = new_geo.width != view->geometry.width ||
+ new_geo.height != view->geometry.height ||
+ new_geo.x != view->geometry.x ||
+ new_geo.y != view->geometry.y;
- if ((new_geo.width != view->geometry.width ||
- new_geo.height != view->geometry.height ||
- new_geo.x != view->geometry.x ||
- new_geo.y != view->geometry.y)) {
- // The view has unexpectedly sent a new size
- desktop_damage_view(view);
- view_update_size(view, new_geo.width, new_geo.height);
- memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
- desktop_damage_view(view);
- transaction_commit_dirty();
- transaction_notify_view_ready_by_size(view,
- new_geo.width, new_geo.height);
+ if (new_size) {
+ // The client changed its surface size in this commit. For floating
+ // containers, we resize the container to match. For tiling containers,
+ // we only recenter the surface.
+ desktop_damage_view(view);
+ memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
+ if (container_is_floating(view->container)) {
+ view_update_size(view);
+ transaction_commit_dirty_client();
} else {
- memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
+ view_center_surface(view);
}
+ desktop_damage_view(view);
+ }
+
+ if (view->container->node.instruction) {
+ transaction_notify_view_ready_by_serial(view,
+ xdg_surface->current.configure_serial);
}
view_damage_from(view);
@@ -351,29 +351,26 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
return;
}
+ struct sway_container *container = view->container;
if (e->fullscreen && e->output && e->output->data) {
struct sway_output *output = e->output->data;
struct sway_workspace *ws = output_get_active_workspace(output);
- if (ws && !container_is_scratchpad_hidden(view->container)) {
- if (container_is_floating(view->container)) {
- workspace_add_floating(ws, view->container);
+ if (ws && !container_is_scratchpad_hidden(container) &&
+ container->pending.workspace != ws) {
+ if (container_is_floating(container)) {
+ workspace_add_floating(ws, container);
} else {
- workspace_add_tiling(ws, view->container);
+ container = workspace_add_tiling(ws, container);
}
}
}
- container_set_fullscreen(view->container, e->fullscreen);
+ container_set_fullscreen(container, e->fullscreen);
arrange_root();
transaction_commit_dirty();
}
-static void handle_request_maximize(struct wl_listener *listener, void *data) {
- struct wlr_xdg_surface *surface = data;
- wlr_xdg_surface_schedule_configure(surface);
-}
-
static void handle_request_move(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, request_move);
@@ -416,7 +413,6 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
wl_list_remove(&xdg_shell_view->commit.link);
wl_list_remove(&xdg_shell_view->new_popup.link);
wl_list_remove(&xdg_shell_view->request_fullscreen.link);
- wl_list_remove(&xdg_shell_view->request_maximize.link);
wl_list_remove(&xdg_shell_view->request_move.link);
wl_list_remove(&xdg_shell_view->request_resize.link);
wl_list_remove(&xdg_shell_view->set_title.link);
@@ -429,8 +425,8 @@ static void handle_map(struct wl_listener *listener, void *data) {
struct sway_view *view = &xdg_shell_view->view;
struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface;
- view->natural_width = view->wlr_xdg_surface->geometry.width;
- view->natural_height = view->wlr_xdg_surface->geometry.height;
+ view->natural_width = view->wlr_xdg_surface->current.geometry.width;
+ view->natural_height = view->wlr_xdg_surface->current.geometry.height;
if (!view->natural_width && !view->natural_height) {
view->natural_width = view->wlr_xdg_surface->surface->current.width;
view->natural_height = view->wlr_xdg_surface->surface->current.height;
@@ -438,17 +434,20 @@ static void handle_map(struct wl_listener *listener, void *data) {
bool csd = false;
- if (!view->xdg_decoration) {
+ if (view->xdg_decoration) {
+ enum wlr_xdg_toplevel_decoration_v1_mode mode =
+ view->xdg_decoration->wlr_xdg_decoration->requested_mode;
+ csd = mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
+ } else {
struct sway_server_decoration *deco =
decoration_from_surface(xdg_surface->surface);
csd = !deco || deco->wlr_server_decoration->mode ==
WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT;
-
}
view_map(view, view->wlr_xdg_surface->surface,
- xdg_surface->toplevel->client_pending.fullscreen,
- xdg_surface->toplevel->client_pending.fullscreen_output,
+ xdg_surface->toplevel->requested.fullscreen,
+ xdg_surface->toplevel->requested.fullscreen_output,
csd);
transaction_commit_dirty();
@@ -465,10 +464,6 @@ static void handle_map(struct wl_listener *listener, void *data) {
wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
&xdg_shell_view->request_fullscreen);
- xdg_shell_view->request_maximize.notify = handle_request_maximize;
- wl_signal_add(&xdg_surface->toplevel->events.request_maximize,
- &xdg_shell_view->request_maximize);
-
xdg_shell_view->request_move.notify = handle_request_move;
wl_signal_add(&xdg_surface->toplevel->events.request_move,
&xdg_shell_view->request_move);
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index db21dc785..40288f973 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -19,17 +19,17 @@
#include "sway/tree/workspace.h"
static const char *atom_map[ATOM_LAST] = {
- "_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",
+ [NET_WM_WINDOW_TYPE_NORMAL] = "_NET_WM_WINDOW_TYPE_NORMAL",
+ [NET_WM_WINDOW_TYPE_DIALOG] = "_NET_WM_WINDOW_TYPE_DIALOG",
+ [NET_WM_WINDOW_TYPE_UTILITY] = "_NET_WM_WINDOW_TYPE_UTILITY",
+ [NET_WM_WINDOW_TYPE_TOOLBAR] = "_NET_WM_WINDOW_TYPE_TOOLBAR",
+ [NET_WM_WINDOW_TYPE_SPLASH] = "_NET_WM_WINDOW_TYPE_SPLASH",
+ [NET_WM_WINDOW_TYPE_MENU] = "_NET_WM_WINDOW_TYPE_MENU",
+ [NET_WM_WINDOW_TYPE_DROPDOWN_MENU] = "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU",
+ [NET_WM_WINDOW_TYPE_POPUP_MENU] = "_NET_WM_WINDOW_TYPE_POPUP_MENU",
+ [NET_WM_WINDOW_TYPE_TOOLTIP] = "_NET_WM_WINDOW_TYPE_TOOLTIP",
+ [NET_WM_WINDOW_TYPE_NOTIFICATION] = "_NET_WM_WINDOW_TYPE_NOTIFICATION",
+ [NET_WM_STATE_MODAL] = "_NET_WM_STATE_MODAL",
};
static void unmanaged_handle_request_configure(struct wl_listener *listener,
@@ -47,6 +47,15 @@ static void unmanaged_handle_commit(struct wl_listener *listener, void *data) {
wl_container_of(listener, surface, commit);
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
+ desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
+ false);
+}
+
+static void unmanaged_handle_set_geometry(struct wl_listener *listener, void *data) {
+ struct sway_xwayland_unmanaged *surface =
+ wl_container_of(listener, surface, set_geometry);
+ struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
+
if (xsurface->x != surface->lx || xsurface->y != surface->ly) {
// Surface has moved
desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
@@ -55,9 +64,6 @@ static void unmanaged_handle_commit(struct wl_listener *listener, void *data) {
surface->ly = xsurface->y;
desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
true);
- } else {
- desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y,
- false);
}
}
@@ -68,6 +74,9 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
wl_list_insert(root->xwayland_unmanaged.prev, &surface->link);
+ wl_signal_add(&xsurface->events.set_geometry, &surface->set_geometry);
+ surface->set_geometry.notify = unmanaged_handle_set_geometry;
+
wl_signal_add(&xsurface->surface->events.commit, &surface->commit);
surface->commit.notify = unmanaged_handle_commit;
@@ -89,25 +98,17 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y, true);
wl_list_remove(&surface->link);
+ wl_list_remove(&surface->set_geometry.link);
wl_list_remove(&surface->commit.link);
struct sway_seat *seat = input_manager_current_seat();
- if (seat->wlr_seat->keyboard_state.focused_surface ==
- xsurface->surface) {
-
- // Try to find another unmanaged surface from the same process to pass
- // focus to. This is necessary because some applications (e.g. Jetbrains
- // IDEs) represent their multi-level menus as unmanaged surfaces, and
- // when closing a submenu, the main menu should get input focus.
- struct sway_xwayland_unmanaged *current;
- wl_list_for_each(current, &root->xwayland_unmanaged, link) {
- struct wlr_xwayland_surface *prev_xsurface =
- current->wlr_xwayland_surface;
- if (prev_xsurface->pid == xsurface->pid &&
- wlr_xwayland_or_surface_wants_focus(prev_xsurface)) {
- seat_set_focus_surface(seat, prev_xsurface->surface, false);
- return;
- }
+ if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) {
+ // This simply returns focus to the parent surface if there's one available.
+ // This seems to handle JetBrains issues.
+ if (xsurface->parent && xsurface->parent->surface
+ && wlr_xwayland_or_surface_wants_focus(xsurface->parent)) {
+ seat_set_focus_surface(seat, xsurface->parent->surface, false);
+ return;
}
// Restore focus
@@ -123,12 +124,36 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, destroy);
+ wl_list_remove(&surface->request_configure.link);
wl_list_remove(&surface->map.link);
wl_list_remove(&surface->unmap.link);
wl_list_remove(&surface->destroy.link);
+ wl_list_remove(&surface->override_redirect.link);
free(surface);
}
+static void handle_map(struct wl_listener *listener, void *data);
+
+struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsurface);
+
+static void unmanaged_handle_override_redirect(struct wl_listener *listener, void *data) {
+ struct sway_xwayland_unmanaged *surface =
+ wl_container_of(listener, surface, override_redirect);
+ struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
+
+ bool mapped = xsurface->mapped;
+ if (mapped) {
+ unmanaged_handle_unmap(&surface->unmap, NULL);
+ }
+
+ unmanaged_handle_destroy(&surface->destroy, NULL);
+ xsurface->data = NULL;
+ struct sway_xwayland_view *xwayland_view = create_xwayland_view(xsurface);
+ if (mapped) {
+ handle_map(&xwayland_view->map, xsurface);
+ }
+}
+
static struct sway_xwayland_unmanaged *create_unmanaged(
struct wlr_xwayland_surface *xsurface) {
struct sway_xwayland_unmanaged *surface =
@@ -149,11 +174,12 @@ static struct sway_xwayland_unmanaged *create_unmanaged(
surface->unmap.notify = unmanaged_handle_unmap;
wl_signal_add(&xsurface->events.destroy, &surface->destroy);
surface->destroy.notify = unmanaged_handle_destroy;
+ wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect);
+ surface->override_redirect.notify = unmanaged_handle_override_redirect;
return surface;
}
-
static struct sway_xwayland_view *xwayland_view_from_view(
struct sway_view *view) {
if (!sway_assert(view->type == SWAY_VIEW_XWAYLAND,
@@ -228,6 +254,7 @@ static void set_activated(struct sway_view *view, bool activated) {
}
wlr_xwayland_surface_activate(surface, activated);
+ wlr_xwayland_surface_restack(surface, NULL, XCB_STACK_MODE_ABOVE);
}
static void set_tiled(struct sway_view *view, bool tiled) {
@@ -369,30 +396,31 @@ static void handle_commit(struct wl_listener *listener, void *data) {
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
struct wlr_surface_state *state = &xsurface->surface->current;
- if (view->container->node.instruction) {
- get_geometry(view, &view->geometry);
- transaction_notify_view_ready_by_size(view,
- state->width, state->height);
- } else {
- struct wlr_box new_geo;
- get_geometry(view, &new_geo);
+ struct wlr_box new_geo;
+ get_geometry(view, &new_geo);
+ bool new_size = new_geo.width != view->geometry.width ||
+ new_geo.height != view->geometry.height ||
+ new_geo.x != view->geometry.x ||
+ new_geo.y != view->geometry.y;
- if ((new_geo.width != view->geometry.width ||
- new_geo.height != view->geometry.height ||
- new_geo.x != view->geometry.x ||
- new_geo.y != view->geometry.y)) {
- // The view has unexpectedly sent a new size
- // eg. The Firefox "Save As" dialog when downloading a file
- desktop_damage_view(view);
- view_update_size(view, new_geo.width, new_geo.height);
- memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
- desktop_damage_view(view);
- transaction_commit_dirty();
- transaction_notify_view_ready_by_size(view,
- new_geo.width, new_geo.height);
+ if (new_size) {
+ // The client changed its surface size in this commit. For floating
+ // containers, we resize the container to match. For tiling containers,
+ // we only recenter the surface.
+ desktop_damage_view(view);
+ memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
+ if (container_is_floating(view->container)) {
+ view_update_size(view);
+ transaction_commit_dirty_client();
} else {
- memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
+ view_center_surface(view);
}
+ desktop_damage_view(view);
+ }
+
+ if (view->container->node.instruction) {
+ transaction_notify_view_ready_by_geometry(view,
+ xsurface->x, xsurface->y, state->width, state->height);
}
view_damage_from(view);
@@ -408,6 +436,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&xwayland_view->commit.link);
}
+ xwayland_view->view.wlr_xwayland_surface = NULL;
+
wl_list_remove(&xwayland_view->destroy.link);
wl_list_remove(&xwayland_view->request_configure.link);
wl_list_remove(&xwayland_view->request_fullscreen.link);
@@ -423,6 +453,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&xwayland_view->set_decorations.link);
wl_list_remove(&xwayland_view->map.link);
wl_list_remove(&xwayland_view->unmap.link);
+ wl_list_remove(&xwayland_view->override_redirect.link);
view_begin_destroy(&xwayland_view->view);
}
@@ -446,16 +477,6 @@ static void handle_map(struct wl_listener *listener, void *data) {
struct wlr_xwayland_surface *xsurface = data;
struct sway_view *view = &xwayland_view->view;
- if (xsurface->override_redirect) {
- // This window used not to have the override redirect flag and has it
- // now. Switch to unmanaged.
- handle_destroy(&xwayland_view->destroy, view);
- xsurface->data = NULL;
- struct sway_xwayland_unmanaged *unmanaged = create_unmanaged(xsurface);
- unmanaged_handle_map(&unmanaged->map, xsurface);
- return;
- }
-
view->natural_width = xsurface->width;
view->natural_height = xsurface->height;
@@ -470,6 +491,25 @@ static void handle_map(struct wl_listener *listener, void *data) {
transaction_commit_dirty();
}
+static void handle_override_redirect(struct wl_listener *listener, void *data) {
+ struct sway_xwayland_view *xwayland_view =
+ wl_container_of(listener, xwayland_view, override_redirect);
+ struct wlr_xwayland_surface *xsurface = data;
+ struct sway_view *view = &xwayland_view->view;
+
+ bool mapped = xsurface->mapped;
+ if (mapped) {
+ handle_unmap(&xwayland_view->unmap, NULL);
+ }
+
+ handle_destroy(&xwayland_view->destroy, view);
+ xsurface->data = NULL;
+ struct sway_xwayland_unmanaged *unmanaged = create_unmanaged(xsurface);
+ if (mapped) {
+ unmanaged_handle_map(&unmanaged->map, xsurface);
+ }
+}
+
static void handle_request_configure(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, request_configure);
@@ -487,10 +527,10 @@ static void handle_request_configure(struct wl_listener *listener, void *data) {
view->natural_height = ev->height;
container_floating_resize_and_center(view->container);
- configure(view, view->container->content_x,
- view->container->content_y,
- view->container->content_width,
- view->container->content_height);
+ configure(view, view->container->pending.content_x,
+ view->container->pending.content_y,
+ view->container->pending.content_width,
+ view->container->pending.content_height);
node_set_dirty(&view->container->node);
} else {
configure(view, view->container->current.content_x,
@@ -642,22 +682,14 @@ struct sway_view *view_from_wlr_xwayland_surface(
return xsurface->data;
}
-void handle_xwayland_surface(struct wl_listener *listener, void *data) {
- struct wlr_xwayland_surface *xsurface = data;
-
- if (xsurface->override_redirect) {
- sway_log(SWAY_DEBUG, "New xwayland unmanaged surface");
- create_unmanaged(xsurface);
- return;
- }
-
+struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsurface) {
sway_log(SWAY_DEBUG, "New xwayland surface title='%s' class='%s'",
xsurface->title, xsurface->class);
struct sway_xwayland_view *xwayland_view =
calloc(1, sizeof(struct sway_xwayland_view));
if (!sway_assert(xwayland_view, "Failed to allocate view")) {
- return;
+ return NULL;
}
view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl);
@@ -716,7 +748,25 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
wl_signal_add(&xsurface->events.map, &xwayland_view->map);
xwayland_view->map.notify = handle_map;
+ wl_signal_add(&xsurface->events.set_override_redirect,
+ &xwayland_view->override_redirect);
+ xwayland_view->override_redirect.notify = handle_override_redirect;
+
xsurface->data = xwayland_view;
+
+ return xwayland_view;
+}
+
+void handle_xwayland_surface(struct wl_listener *listener, void *data) {
+ struct wlr_xwayland_surface *xsurface = data;
+
+ if (xsurface->override_redirect) {
+ sway_log(SWAY_DEBUG, "New xwayland unmanaged surface");
+ create_unmanaged(xsurface);
+ return;
+ }
+
+ create_xwayland_view(xsurface);
}
void handle_xwayland_ready(struct wl_listener *listener, void *data) {
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index e43a0e719..d8b1abeb4 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -4,11 +4,15 @@
#include
#include
#include
+#include
#include
-#include
#include
#include
+#include
+#include
#include
+#include
+#include
#include
#include
#include "config.h"
@@ -16,7 +20,6 @@
#include "util.h"
#include "sway/commands.h"
#include "sway/desktop.h"
-#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/input/keyboard.h"
#include "sway/input/tablet.h"
@@ -28,6 +31,12 @@
#include "sway/tree/workspace.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"
+static uint32_t get_current_time_msec(void) {
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return now.tv_sec * 1000 + now.tv_nsec / 1000000;
+}
+
static struct wlr_surface *layer_surface_at(struct sway_output *output,
struct wl_list *layer, double ox, double oy, double *sx, double *sy) {
struct sway_layer_surface *sway_layer;
@@ -74,7 +83,28 @@ static struct wlr_surface *layer_surface_popup_at(struct sway_output *output,
struct sway_node *node_at_coords(
struct sway_seat *seat, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
- // check for unmanaged views first
+ // find the output the cursor is on
+ struct wlr_output *wlr_output = wlr_output_layout_output_at(
+ root->output_layout, lx, ly);
+ if (wlr_output == NULL) {
+ return NULL;
+ }
+ struct sway_output *output = wlr_output->data;
+ if (!output || !output->enabled) {
+ // output is being destroyed or is being enabled
+ return NULL;
+ }
+ double ox = lx, oy = ly;
+ wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy);
+
+ // layer surfaces on the overlay layer are rendered on top
+ if ((*surface = layer_surface_at(output,
+ &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
+ ox, oy, sx, sy))) {
+ return NULL;
+ }
+
+ // check for unmanaged views
#if HAVE_XWAYLAND
struct wl_list *unmanaged = &root->xwayland_unmanaged;
struct sway_xwayland_unmanaged *unmanaged_surface;
@@ -92,19 +122,6 @@ struct sway_node *node_at_coords(
}
}
#endif
- // find the output the cursor is on
- struct wlr_output *wlr_output = wlr_output_layout_output_at(
- root->output_layout, lx, ly);
- if (wlr_output == NULL) {
- return NULL;
- }
- struct sway_output *output = wlr_output->data;
- if (!output || !output->enabled) {
- // output is being destroyed or is being enabled
- return NULL;
- }
- double ox = lx, oy = ly;
- wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy);
if (root->fullscreen_global) {
// Try fullscreen container
@@ -122,11 +139,6 @@ struct sway_node *node_at_coords(
return NULL;
}
- if ((*surface = layer_surface_at(output,
- &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
- ox, oy, sx, sy))) {
- return NULL;
- }
if (ws->fullscreen) {
// Try transient containers
for (int i = 0; i < ws->floating->length; ++i) {
@@ -253,6 +265,32 @@ int cursor_get_timeout(struct sway_cursor *cursor) {
return timeout;
}
+void cursor_notify_key_press(struct sway_cursor *cursor) {
+ if (cursor->hidden) {
+ return;
+ }
+
+ if (cursor->hide_when_typing == HIDE_WHEN_TYPING_DEFAULT) {
+ // No cached value, need to lookup in the seat_config
+ const struct seat_config *seat_config = seat_get_config(cursor->seat);
+ if (!seat_config) {
+ seat_config = seat_get_config_by_name("*");
+ if (!seat_config) {
+ return;
+ }
+ }
+ cursor->hide_when_typing = seat_config->hide_cursor_when_typing;
+ // The default is currently disabled
+ if (cursor->hide_when_typing == HIDE_WHEN_TYPING_DEFAULT) {
+ cursor->hide_when_typing = HIDE_WHEN_TYPING_DISABLE;
+ }
+ }
+
+ if (cursor->hide_when_typing == HIDE_WHEN_TYPING_ENABLE) {
+ cursor_hide(cursor);
+ }
+}
+
static enum sway_input_idle_source idle_source_from_device(
struct wlr_input_device *device) {
switch (device->type) {
@@ -273,19 +311,28 @@ static enum sway_input_idle_source idle_source_from_device(
abort();
}
-void cursor_handle_activity(struct sway_cursor *cursor,
- struct wlr_input_device *device) {
+void cursor_handle_activity_from_idle_source(struct sway_cursor *cursor,
+ enum sway_input_idle_source idle_source) {
wl_event_source_timer_update(
cursor->hide_source, cursor_get_timeout(cursor));
- enum sway_input_idle_source idle_source = idle_source_from_device(device);
seat_idle_notify_activity(cursor->seat, idle_source);
- if (cursor->hidden && idle_source != IDLE_SOURCE_TOUCH) {
+ if (idle_source != IDLE_SOURCE_TOUCH) {
cursor_unhide(cursor);
}
}
+void cursor_handle_activity_from_device(struct sway_cursor *cursor,
+ struct wlr_input_device *device) {
+ enum sway_input_idle_source idle_source = idle_source_from_device(device);
+ cursor_handle_activity_from_idle_source(cursor, idle_source);
+}
+
void cursor_unhide(struct sway_cursor *cursor) {
+ if (!cursor->hidden) {
+ return;
+ }
+
cursor->hidden = false;
if (cursor->image_surface) {
cursor_set_image_surface(cursor,
@@ -299,6 +346,7 @@ void cursor_unhide(struct sway_cursor *cursor) {
cursor_set_image(cursor, image, cursor->image_client);
}
cursor_rebase(cursor);
+ wl_event_source_timer_update(cursor->hide_source, cursor_get_timeout(cursor));
}
static void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
@@ -332,18 +380,17 @@ static void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
wlr_cursor_move(cursor->cursor, device, dx, dy);
- seatop_pointer_motion(cursor->seat, time_msec, dx, dy);
+ seatop_pointer_motion(cursor->seat, time_msec);
}
static void handle_pointer_motion_relative(
struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, motion);
struct wlr_event_pointer_motion *e = data;
- cursor_handle_activity(cursor, e->device);
+ cursor_handle_activity_from_device(cursor, e->device);
pointer_motion(cursor, e->time_msec, e->device, e->delta_x, e->delta_y,
e->unaccel_dx, e->unaccel_dy);
- transaction_commit_dirty();
}
static void handle_pointer_motion_absolute(
@@ -351,7 +398,7 @@ static void handle_pointer_motion_absolute(
struct sway_cursor *cursor =
wl_container_of(listener, cursor, motion_absolute);
struct wlr_event_pointer_motion_absolute *event = data;
- cursor_handle_activity(cursor, event->device);
+ cursor_handle_activity_from_device(cursor, event->device);
double lx, ly;
wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
@@ -361,7 +408,6 @@ static void handle_pointer_motion_absolute(
double dy = ly - cursor->cursor->y;
pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
- transaction_commit_dirty();
}
void dispatch_cursor_button(struct sway_cursor *cursor,
@@ -377,7 +423,6 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
static void handle_pointer_button(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, button);
struct wlr_event_pointer_button *event = data;
- cursor_handle_activity(cursor, event->device);
if (event->state == WLR_BUTTON_PRESSED) {
cursor->pressed_button_count++;
@@ -389,9 +434,9 @@ static void handle_pointer_button(struct wl_listener *listener, void *data) {
}
}
+ cursor_handle_activity_from_device(cursor, event->device);
dispatch_cursor_button(cursor, event->device,
event->time_msec, event->button, event->state);
- transaction_commit_dirty();
}
void dispatch_cursor_axis(struct sway_cursor *cursor,
@@ -402,9 +447,8 @@ void dispatch_cursor_axis(struct sway_cursor *cursor,
static void handle_pointer_axis(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, axis);
struct wlr_event_pointer_axis *event = data;
- cursor_handle_activity(cursor, event->device);
+ cursor_handle_activity_from_device(cursor, event->device);
dispatch_cursor_axis(cursor, event);
- transaction_commit_dirty();
}
static void handle_pointer_frame(struct wl_listener *listener, void *data) {
@@ -415,7 +459,7 @@ static void handle_pointer_frame(struct wl_listener *listener, void *data) {
static void handle_touch_down(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_down);
struct wlr_event_touch_down *event = data;
- cursor_handle_activity(cursor, event->device);
+ cursor_handle_activity_from_device(cursor, event->device);
cursor_hide(cursor);
struct sway_seat *seat = cursor->seat;
@@ -454,25 +498,21 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
dispatch_cursor_button(cursor, event->device, event->time_msec,
BTN_LEFT, WLR_BUTTON_PRESSED);
- wlr_seat_pointer_notify_frame(wlr_seat);
- transaction_commit_dirty();
}
}
static void handle_touch_up(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_up);
struct wlr_event_touch_up *event = data;
- cursor_handle_activity(cursor, event->device);
+ cursor_handle_activity_from_device(cursor, event->device);
struct wlr_seat *wlr_seat = cursor->seat->wlr_seat;
if (cursor->simulating_pointer_from_touch) {
if (cursor->pointer_touch_id == cursor->seat->touch_id) {
- cursor->simulating_pointer_from_touch = false;
+ cursor->pointer_touch_up = true;
dispatch_cursor_button(cursor, event->device, event->time_msec,
BTN_LEFT, WLR_BUTTON_RELEASED);
- wlr_seat_pointer_notify_frame(wlr_seat);
- transaction_commit_dirty();
}
} else {
wlr_seat_touch_notify_up(wlr_seat, event->time_msec, event->touch_id);
@@ -483,7 +523,7 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, touch_motion);
struct wlr_event_touch_motion *event = data;
- cursor_handle_activity(cursor, event->device);
+ cursor_handle_activity_from_device(cursor, event->device);
struct sway_seat *seat = cursor->seat;
struct wlr_seat *wlr_seat = seat->wlr_seat;
@@ -513,7 +553,6 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
dx = lx - cursor->cursor->x;
dy = ly - cursor->cursor->y;
pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
- transaction_commit_dirty();
}
} else if (surface) {
wlr_seat_touch_notify_motion(wlr_seat, event->time_msec,
@@ -521,6 +560,24 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
}
}
+static void handle_touch_frame(struct wl_listener *listener, void *data) {
+ struct sway_cursor *cursor =
+ wl_container_of(listener, cursor, touch_frame);
+
+ struct wlr_seat *wlr_seat = cursor->seat->wlr_seat;
+
+ if (cursor->simulating_pointer_from_touch) {
+ wlr_seat_pointer_notify_frame(wlr_seat);
+
+ if (cursor->pointer_touch_up) {
+ cursor->pointer_touch_up = false;
+ cursor->simulating_pointer_from_touch = false;
+ }
+ } else {
+ wlr_seat_touch_notify_frame(wlr_seat);
+ }
+}
+
static double apply_mapping_from_coord(double low, double high, double value) {
if (isnan(value)) {
return value;
@@ -566,13 +623,14 @@ static void handle_tablet_tool_position(struct sway_cursor *cursor,
ic->mapped_from_region, &x, &y);
}
- switch (tool->tablet_v2_tool->wlr_tool->type) {
- case WLR_TABLET_TOOL_TYPE_MOUSE:
- wlr_cursor_move(cursor->cursor, input_device->wlr_device, dx, dy);
- break;
- default:
+ switch (tool->mode) {
+ case SWAY_TABLET_TOOL_MODE_ABSOLUTE:
wlr_cursor_warp_absolute(cursor->cursor, input_device->wlr_device,
change_x ? x : NAN, change_y ? y : NAN);
+ break;
+ case SWAY_TABLET_TOOL_MODE_RELATIVE:
+ wlr_cursor_move(cursor->cursor, input_device->wlr_device, dx, dy);
+ break;
}
double sx, sy;
@@ -593,19 +651,17 @@ static void handle_tablet_tool_position(struct sway_cursor *cursor,
if (!cursor->simulating_pointer_from_tool_tip &&
((surface && wlr_surface_accepts_tablet_v2(tablet->tablet_v2, surface)) ||
wlr_tablet_tool_v2_has_implicit_grab(tool->tablet_v2_tool))) {
- seatop_tablet_tool_motion(seat, tool, time_msec, dx, dy);
+ seatop_tablet_tool_motion(seat, tool, time_msec);
} else {
wlr_tablet_v2_tablet_tool_notify_proximity_out(tool->tablet_v2_tool);
pointer_motion(cursor, time_msec, input_device->wlr_device, dx, dy, dx, dy);
}
-
- transaction_commit_dirty();
}
static void handle_tool_axis(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_axis);
struct wlr_event_tablet_tool_axis *event = data;
- cursor_handle_activity(cursor, event->device);
+ cursor_handle_activity_from_device(cursor, event->device);
struct sway_tablet_tool *sway_tool = event->tool->data;
if (!sway_tool) {
@@ -661,7 +717,7 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) {
static void handle_tool_tip(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_tip);
struct wlr_event_tablet_tool_tip *event = data;
- cursor_handle_activity(cursor, event->device);
+ cursor_handle_activity_from_device(cursor, event->device);
struct sway_tablet_tool *sway_tool = event->tool->data;
struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2;
@@ -679,7 +735,6 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
dispatch_cursor_button(cursor, event->device, event->time_msec,
BTN_LEFT, WLR_BUTTON_RELEASED);
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
- transaction_commit_dirty();
} else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) {
// If we started holding the tool tip down on a surface that accepts
// tablet v2, we should notify that surface if it gets released over a
@@ -692,7 +747,6 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
dispatch_cursor_button(cursor, event->device, event->time_msec,
BTN_LEFT, WLR_BUTTON_PRESSED);
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
- transaction_commit_dirty();
}
} else {
seatop_tablet_tool_tip(seat, sway_tool, event->time_msec, event->state);
@@ -714,7 +768,7 @@ static void handle_tool_proximity(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, tool_proximity);
struct wlr_event_tablet_tool_proximity *event = data;
- cursor_handle_activity(cursor, event->device);
+ cursor_handle_activity_from_device(cursor, event->device);
struct wlr_tablet_tool *tool = event->tool;
if (!tool->data) {
@@ -744,7 +798,7 @@ static void handle_tool_proximity(struct wl_listener *listener, void *data) {
static void handle_tool_button(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_button);
struct wlr_event_tablet_tool_button *event = data;
- cursor_handle_activity(cursor, event->device);
+ cursor_handle_activity_from_device(cursor, event->device);
struct sway_tablet_tool *sway_tool = event->tool->data;
if (!sway_tool) {
@@ -779,7 +833,6 @@ static void handle_tool_button(struct wl_listener *listener, void *data) {
break;
}
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
- transaction_commit_dirty();
return;
}
@@ -796,8 +849,8 @@ static void check_constraint_region(struct sway_cursor *cursor) {
struct sway_container *con = view->container;
- double sx = cursor->cursor->x - con->content_x + view->geometry.x;
- double sy = cursor->cursor->y - con->content_y + view->geometry.y;
+ double sx = cursor->cursor->x - con->pending.content_x + view->geometry.x;
+ double sy = cursor->cursor->y - con->pending.content_y + view->geometry.y;
if (!pixman_region32_contains_point(region,
floor(sx), floor(sy), NULL)) {
@@ -808,8 +861,8 @@ static void check_constraint_region(struct sway_cursor *cursor) {
double sy = (boxes[0].y1 + boxes[0].y2) / 2.;
wlr_cursor_warp_closest(cursor->cursor, NULL,
- sx + con->content_x - view->geometry.x,
- sy + con->content_y - view->geometry.y);
+ sx + con->pending.content_x - view->geometry.x,
+ sy + con->pending.content_y - view->geometry.y);
cursor_rebase(cursor);
}
@@ -1010,6 +1063,7 @@ void sway_cursor_destroy(struct sway_cursor *cursor) {
wl_list_remove(&cursor->touch_down.link);
wl_list_remove(&cursor->touch_up.link);
wl_list_remove(&cursor->touch_motion.link);
+ wl_list_remove(&cursor->touch_frame.link);
wl_list_remove(&cursor->tool_axis.link);
wl_list_remove(&cursor->tool_tip.link);
wl_list_remove(&cursor->tool_button.link);
@@ -1085,6 +1139,9 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
&cursor->touch_motion);
cursor->touch_motion.notify = handle_touch_motion;
+ wl_signal_add(&wlr_cursor->events.touch_frame, &cursor->touch_frame);
+ cursor->touch_frame.notify = handle_touch_frame;
+
wl_signal_add(&wlr_cursor->events.tablet_tool_axis,
&cursor->tool_axis);
cursor->tool_axis.notify = handle_tool_axis;
@@ -1113,25 +1170,27 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
/**
* Warps the cursor to the middle of the container argument.
- * Does nothing if the cursor is already inside the container.
- * If container is NULL, returns without doing anything.
+ * Does nothing if the cursor is already inside the container and `force` is
+ * false. If container is NULL, returns without doing anything.
*/
void cursor_warp_to_container(struct sway_cursor *cursor,
- struct sway_container *container) {
+ struct sway_container *container, bool force) {
if (!container) {
return;
}
struct wlr_box box;
container_get_box(container, &box);
- if (wlr_box_contains_point(&box, cursor->cursor->x, cursor->cursor->y)) {
+ if (!force && wlr_box_contains_point(&box, cursor->cursor->x,
+ cursor->cursor->y)) {
return;
}
- double x = container->x + container->width / 2.0;
- double y = container->y + container->height / 2.0;
+ double x = container->pending.x + container->pending.width / 2.0;
+ double y = container->pending.y + container->pending.height / 2.0;
wlr_cursor_warp(cursor->cursor, NULL, x, y);
+ cursor_unhide(cursor);
}
/**
@@ -1148,6 +1207,7 @@ void cursor_warp_to_workspace(struct sway_cursor *cursor,
double y = workspace->y + workspace->height / 2.0;
wlr_cursor_warp(cursor->cursor, NULL, x, y);
+ cursor_unhide(cursor);
}
uint32_t get_mouse_bindsym(const char *name, char **error) {
@@ -1240,8 +1300,8 @@ static void warp_to_constraint_cursor_hint(struct sway_cursor *cursor) {
struct sway_view *view = view_from_wlr_surface(constraint->surface);
struct sway_container *con = view->container;
- double lx = sx + con->content_x - view->geometry.x;
- double ly = sy + con->content_y - view->geometry.y;
+ double lx = sx + con->pending.content_x - view->geometry.x;
+ double ly = sy + con->pending.content_y - view->geometry.y;
wlr_cursor_warp(cursor->cursor, NULL, lx, ly);
@@ -1289,7 +1349,7 @@ void handle_pointer_constraint(struct wl_listener *listener, void *data) {
wl_signal_add(&constraint->events.destroy, &sway_constraint->destroy);
struct sway_node *focus = seat_get_focus(seat);
- if (focus && focus->type == N_CONTAINER && focus->sway_container->view) {
+ if (focus && node_is_view(focus)) {
struct wlr_surface *surface = focus->sway_container->view->surface;
if (surface == constraint->surface) {
sway_cursor_constrain(seat->cursor, constraint);
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index 541fc90d7..f258ac7d5 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -9,10 +9,10 @@
#include
#include
#include "sway/commands.h"
-#include "sway/desktop/transaction.h"
#include "sway/input/input-manager.h"
#include "sway/input/keyboard.h"
#include "sway/input/seat.h"
+#include "sway/input/cursor.h"
#include "sway/ipc-server.h"
#include "log.h"
@@ -124,7 +124,7 @@ static void state_add_key(struct sway_shortcut_state *state,
* Update the shortcut model state in response to new input
*/
static bool update_shortcut_state(struct sway_shortcut_state *state,
- uint32_t keycode, enum wlr_key_state keystate, uint32_t new_key,
+ uint32_t keycode, enum wl_keyboard_key_state keystate, uint32_t new_key,
uint32_t raw_modifiers) {
bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers;
state->last_raw_modifiers = raw_modifiers;
@@ -134,7 +134,7 @@ static bool update_shortcut_state(struct sway_shortcut_state *state,
state_erase_key(state, state->last_keycode);
}
- if (keystate == WLR_KEY_PRESSED) {
+ if (keystate == WL_KEYBOARD_KEY_STATE_PRESSED) {
// Add current key to set; there may be duplicates
state_add_key(state, keycode, new_key);
state->last_keycode = keycode;
@@ -348,7 +348,7 @@ struct key_info {
};
static void update_keyboard_state(struct sway_keyboard *keyboard,
- uint32_t raw_keycode, enum wlr_key_state keystate,
+ uint32_t raw_keycode, enum wl_keyboard_key_state keystate,
struct key_info *keyinfo) {
// Identify new keycode, raw keysym(s), and translated keysym(s)
keyinfo->keycode = raw_keycode + 8;
@@ -378,6 +378,28 @@ static void update_keyboard_state(struct sway_keyboard *keyboard,
}
}
+/**
+ * Get keyboard grab of the seat from sway_keyboard if we should forward events
+ * to it.
+ *
+ * Returns NULL if the keyboard is not grabbed by an input method,
+ * or if event is from virtual keyboard of the same client as grab.
+ * TODO: see swaywm/wlroots#2322
+ */
+static struct wlr_input_method_keyboard_grab_v2 *keyboard_get_im_grab(
+ struct sway_keyboard *keyboard) {
+ struct wlr_input_method_v2 *input_method = keyboard->seat_device->
+ sway_seat->im_relay.input_method;
+ struct wlr_virtual_keyboard_v1 *virtual_keyboard =
+ wlr_input_device_get_virtual_keyboard(keyboard->seat_device->input_device->wlr_device);
+ if (!input_method || !input_method->keyboard_grab || (virtual_keyboard &&
+ wl_resource_get_client(virtual_keyboard->resource) ==
+ wl_resource_get_client(input_method->keyboard_grab->resource))) {
+ return NULL;
+ }
+ return input_method->keyboard_grab;
+}
+
static void handle_key_event(struct sway_keyboard *keyboard,
struct wlr_event_keyboard_key *event) {
struct sway_seat *seat = keyboard->seat_device->sway_seat;
@@ -392,6 +414,10 @@ static void handle_key_event(struct sway_keyboard *keyboard,
keyboard_shortcuts_inhibitor_get_for_focused_surface(seat);
bool shortcuts_inhibited = sway_inhibitor && sway_inhibitor->inhibitor->active;
+ if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ cursor_notify_key_press(seat->cursor);
+ }
+
// Identify new keycode, raw keysym(s), and translated keysym(s)
struct key_info keyinfo;
update_keyboard_state(keyboard, event->keycode, event->state, &keyinfo);
@@ -417,20 +443,20 @@ static void handle_key_event(struct sway_keyboard *keyboard,
// Execute stored release binding once no longer active
if (keyboard->held_binding && binding_released != keyboard->held_binding &&
- event->state == WLR_KEY_RELEASED) {
+ event->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
seat_execute_command(seat, keyboard->held_binding);
handled = true;
}
if (binding_released != keyboard->held_binding) {
keyboard->held_binding = NULL;
}
- if (binding_released && event->state == WLR_KEY_PRESSED) {
+ if (binding_released && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
keyboard->held_binding = binding_released;
}
// Identify and execute active pressed binding
struct sway_binding *binding = NULL;
- if (event->state == WLR_KEY_PRESSED) {
+ if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
get_active_binding(&keyboard->state_keycodes,
config->current_mode->keycode_bindings, &binding,
keyinfo.code_modifiers, false, input_inhibited,
@@ -473,29 +499,53 @@ static void handle_key_event(struct sway_keyboard *keyboard,
}
// Compositor bindings
- if (!handled && event->state == WLR_KEY_PRESSED) {
+ if (!handled && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
handled = keyboard_execute_compositor_binding(
keyboard, keyinfo.translated_keysyms,
keyinfo.translated_modifiers, keyinfo.translated_keysyms_len);
}
- if (!handled && event->state == WLR_KEY_PRESSED) {
+ if (!handled && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
handled = keyboard_execute_compositor_binding(
keyboard, keyinfo.raw_keysyms, keyinfo.raw_modifiers,
keyinfo.raw_keysyms_len);
}
- if (!handled || event->state == WLR_KEY_RELEASED) {
+ if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
+ // If the pressed event was sent to a client, also send the released
+ // event. In particular, don't send the released event to the IM grab.
bool pressed_sent = update_shortcut_state(
- &keyboard->state_pressed_sent, event->keycode, event->state,
- keyinfo.keycode, 0);
- if (pressed_sent || event->state == WLR_KEY_PRESSED) {
+ &keyboard->state_pressed_sent, event->keycode,
+ event->state, keyinfo.keycode, 0);
+ if (pressed_sent) {
wlr_seat_set_keyboard(wlr_seat, wlr_device);
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
- event->keycode, event->state);
+ event->keycode, event->state);
+ handled = true;
}
}
- transaction_commit_dirty();
+ if (!handled) {
+ struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard);
+
+ if (kb_grab) {
+ wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab,
+ wlr_device->keyboard);
+ wlr_input_method_keyboard_grab_v2_send_key(kb_grab,
+ event->time_msec, event->keycode, event->state);
+ handled = true;
+ }
+ }
+
+ if (!handled && event->state != WL_KEYBOARD_KEY_STATE_RELEASED) {
+ // If a released event failed pressed sent test, and not in sent to
+ // keyboard grab, it is still not handled. Don't handle released here.
+ update_shortcut_state(
+ &keyboard->state_pressed_sent, event->keycode, event->state,
+ keyinfo.keycode, 0);
+ wlr_seat_set_keyboard(wlr_seat, wlr_device);
+ wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
+ event->keycode, event->state);
+ }
free(device_identifier);
}
@@ -523,7 +573,7 @@ static void handle_keyboard_group_enter(struct wl_listener *listener,
uint32_t *keycode;
wl_array_for_each(keycode, keycodes) {
struct key_info keyinfo;
- update_keyboard_state(keyboard, *keycode, WLR_KEY_PRESSED, &keyinfo);
+ update_keyboard_state(keyboard, *keycode, WL_KEYBOARD_KEY_STATE_PRESSED, &keyinfo);
}
}
@@ -539,10 +589,10 @@ static void handle_keyboard_group_leave(struct wl_listener *listener,
uint32_t *keycode;
wl_array_for_each(keycode, keycodes) {
struct key_info keyinfo;
- update_keyboard_state(keyboard, *keycode, WLR_KEY_RELEASED, &keyinfo);
+ update_keyboard_state(keyboard, *keycode, WL_KEYBOARD_KEY_STATE_RELEASED, &keyinfo);
pressed_sent |= update_shortcut_state(&keyboard->state_pressed_sent,
- *keycode, WLR_KEY_RELEASED, keyinfo.keycode, 0);
+ *keycode, WL_KEYBOARD_KEY_STATE_RELEASED, keyinfo.keycode, 0);
}
if (!pressed_sent) {
@@ -582,7 +632,6 @@ static int handle_keyboard_repeat(void *data) {
seat_execute_command(keyboard->seat_device->sway_seat,
keyboard->repeat_binding);
- transaction_commit_dirty();
}
return 0;
}
@@ -612,19 +661,30 @@ static void handle_modifier_event(struct sway_keyboard *keyboard) {
struct wlr_input_device *wlr_device =
keyboard->seat_device->input_device->wlr_device;
if (!wlr_device->keyboard->group) {
- struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
- wlr_seat_set_keyboard(wlr_seat, wlr_device);
- wlr_seat_keyboard_notify_modifiers(wlr_seat,
- &wlr_device->keyboard->modifiers);
+ struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard);
+
+ if (kb_grab) {
+ wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab,
+ wlr_device->keyboard);
+ wlr_input_method_keyboard_grab_v2_send_modifiers(kb_grab,
+ &wlr_device->keyboard->modifiers);
+ } else {
+ struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
+ wlr_seat_set_keyboard(wlr_seat, wlr_device);
+ wlr_seat_keyboard_notify_modifiers(wlr_seat,
+ &wlr_device->keyboard->modifiers);
+ }
uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard);
determine_bar_visibility(modifiers);
}
- if (wlr_device->keyboard->modifiers.group != keyboard->effective_layout &&
- !wlr_keyboard_group_from_wlr_keyboard(wlr_device->keyboard)) {
+ if (wlr_device->keyboard->modifiers.group != keyboard->effective_layout) {
keyboard->effective_layout = wlr_device->keyboard->modifiers.group;
- ipc_event_input("xkb_layout", keyboard->seat_device->input_device);
+
+ if (!wlr_keyboard_group_from_wlr_keyboard(wlr_device->keyboard)) {
+ ipc_event_input("xkb_layout", keyboard->seat_device->input_device);
+ }
}
}
diff --git a/sway/input/libinput.c b/sway/input/libinput.c
index 108fc7b24..3c0f359d8 100644
--- a/sway/input/libinput.c
+++ b/sway/input/libinput.c
@@ -1,5 +1,6 @@
#include
#include
+#include
#include
#include
#include "log.h"
@@ -186,17 +187,23 @@ static bool set_calibration_matrix(struct libinput_device *dev, float mat[6]) {
return changed;
}
-static bool config_libinput_pointer(struct libinput_device *device,
- struct input_config *ic, const char *device_id) {
- sway_log(SWAY_DEBUG, "config_libinput_pointer('%s' on '%s')",
- ic->identifier, device_id);
- bool changed = false;
+void sway_input_configure_libinput_device(struct sway_input_device *input_device) {
+ struct input_config *ic = input_device_get_config(input_device);
+ if (!ic || !wlr_input_device_is_libinput(input_device->wlr_device)) {
+ return;
+ }
+ struct libinput_device *device =
+ wlr_libinput_get_device_handle(input_device->wlr_device);
+ sway_log(SWAY_DEBUG, "sway_input_configure_libinput_device('%s' on '%s')",
+ ic->identifier, input_device->identifier);
+
+ bool changed = false;
if (ic->mapped_to_output &&
!output_by_name_or_id(ic->mapped_to_output)) {
sway_log(SWAY_DEBUG,
- "Pointer '%s' is mapped to offline output '%s'; disabling input",
- ic->identifier, ic->mapped_to_output);
+ "%s '%s' is mapped to offline output '%s'; disabling input",
+ ic->input_type, ic->identifier, ic->mapped_to_output);
changed |= set_send_events(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
} else if (ic->send_events != INT_MIN) {
@@ -221,7 +228,6 @@ static bool config_libinput_pointer(struct libinput_device *device,
if (ic->drag_lock != INT_MIN) {
changed |= set_tap_drag_lock(device, ic->drag_lock);
}
-
if (ic->pointer_accel != FLT_MIN) {
changed |= set_accel_speed(device, ic->pointer_accel);
}
@@ -249,71 +255,26 @@ static bool config_libinput_pointer(struct libinput_device *device,
if (ic->dwt != INT_MIN) {
changed |= set_dwt(device, ic->dwt);
}
- return changed;
-}
-
-static bool config_libinput_keyboard(struct libinput_device *device,
- struct input_config *ic, const char *device_id) {
- sway_log(SWAY_DEBUG, "config_libinput_keyboard('%s' on '%s')",
- ic->identifier, device_id);
- if (ic->send_events != INT_MIN) {
- return set_send_events(device, ic->send_events);
- }
- return false;
-}
-
-static bool config_libinput_switch(struct libinput_device *device,
- struct input_config *ic, const char *device_id) {
- sway_log(SWAY_DEBUG, "config_libinput_switch('%s' on '%s')",
- ic->identifier, device_id);
- if (ic->send_events != INT_MIN) {
- return set_send_events(device, ic->send_events);
- }
- return false;
-}
-
-static bool config_libinput_touch(struct libinput_device *device,
- struct input_config *ic, const char *device_id) {
- sway_log(SWAY_DEBUG, "config_libinput_touch('%s' on '%s')",
- ic->identifier, device_id);
- bool changed = false;
- if (ic->send_events != INT_MIN) {
- changed |= set_send_events(device, ic->send_events);
- }
if (ic->calibration_matrix.configured) {
changed |= set_calibration_matrix(device, ic->calibration_matrix.matrix);
}
- return changed;
+
+ if (changed) {
+ ipc_event_input("libinput_config", input_device);
+ }
}
-void sway_input_configure_libinput_device(struct sway_input_device *device) {
- struct input_config *ic = input_device_get_config(device);
- if (!ic || !wlr_input_device_is_libinput(device->wlr_device)) {
+void sway_input_reset_libinput_device(struct sway_input_device *input_device) {
+ if (!wlr_input_device_is_libinput(input_device->wlr_device)) {
return;
}
- bool changed = false;
- const char *device_id = device->identifier;
- struct libinput_device *libinput_device =
- wlr_libinput_get_device_handle(device->wlr_device);
- if (device->wlr_device->type == WLR_INPUT_DEVICE_POINTER ||
- device->wlr_device->type == WLR_INPUT_DEVICE_TABLET_TOOL) {
- changed = config_libinput_pointer(libinput_device, ic, device_id);
- } else if (device->wlr_device->type == WLR_INPUT_DEVICE_KEYBOARD) {
- changed = config_libinput_keyboard(libinput_device, ic, device_id);
- } else if (device->wlr_device->type == WLR_INPUT_DEVICE_SWITCH) {
- changed = config_libinput_switch(libinput_device, ic, device_id);
- } else if (device->wlr_device->type == WLR_INPUT_DEVICE_TOUCH) {
- changed = config_libinput_touch(libinput_device, ic, device_id);
- }
- if (changed) {
- ipc_event_input("libinput_config", device);
- }
-}
-static bool reset_libinput_pointer(struct libinput_device *device,
- const char *device_id) {
- sway_log(SWAY_DEBUG, "reset_libinput_pointer(%s)", device_id);
+ struct libinput_device *device =
+ wlr_libinput_get_device_handle(input_device->wlr_device);
+ sway_log(SWAY_DEBUG, "sway_input_reset_libinput_device(%s)",
+ input_device->identifier);
bool changed = false;
+
changed |= set_send_events(device,
libinput_device_config_send_events_get_default_mode(device));
changed |= set_tap(device,
@@ -343,56 +304,41 @@ static bool reset_libinput_pointer(struct libinput_device *device,
libinput_device_config_scroll_get_default_button(device));
changed |= set_dwt(device,
libinput_device_config_dwt_get_default_enabled(device));
- return changed;
-}
-
-static bool reset_libinput_keyboard(struct libinput_device *device,
- const char *device_id) {
- sway_log(SWAY_DEBUG, "reset_libinput_keyboard(%s)", device_id);
- return set_send_events(device,
- libinput_device_config_send_events_get_default_mode(device));
-}
-
-static bool reset_libinput_switch(struct libinput_device *device,
- const char *device_id) {
- sway_log(SWAY_DEBUG, "reset_libinput_switch(%s)", device_id);
- return set_send_events(device,
- libinput_device_config_send_events_get_default_mode(device));
-}
-
-static bool reset_libinput_touch(struct libinput_device *device,
- const char *device_id) {
- sway_log(SWAY_DEBUG, "reset_libinput_touch(%s)", device_id);
- bool changed = false;
-
- changed |= set_send_events(device,
- libinput_device_config_send_events_get_default_mode(device));
float matrix[6];
libinput_device_config_calibration_get_default_matrix(device, matrix);
changed |= set_calibration_matrix(device, matrix);
- return changed;
+ if (changed) {
+ ipc_event_input("libinput_config", input_device);
+ }
}
-void sway_input_reset_libinput_device(struct sway_input_device *device) {
- if (!wlr_input_device_is_libinput(device->wlr_device)) {
- return;
+bool sway_libinput_device_is_builtin(struct sway_input_device *sway_device) {
+ if (!wlr_input_device_is_libinput(sway_device->wlr_device)) {
+ return false;
}
- bool changed = false;
- struct libinput_device *libinput_device =
- wlr_libinput_get_device_handle(device->wlr_device);
- if (device->wlr_device->type == WLR_INPUT_DEVICE_POINTER ||
- device->wlr_device->type == WLR_INPUT_DEVICE_TABLET_TOOL) {
- changed = reset_libinput_pointer(libinput_device, device->identifier);
- } else if (device->wlr_device->type == WLR_INPUT_DEVICE_KEYBOARD) {
- changed = reset_libinput_keyboard(libinput_device, device->identifier);
- } else if (device->wlr_device->type == WLR_INPUT_DEVICE_SWITCH) {
- changed = reset_libinput_switch(libinput_device, device->identifier);
- } else if (device->wlr_device->type == WLR_INPUT_DEVICE_TOUCH) {
- changed = reset_libinput_touch(libinput_device, device->identifier);
+
+ struct libinput_device *device =
+ wlr_libinput_get_device_handle(sway_device->wlr_device);
+ struct udev_device *udev_device =
+ libinput_device_get_udev_device(device);
+ if (!udev_device) {
+ return false;
}
- if (changed) {
- ipc_event_input("libinput_config", device);
+
+ const char *id_path = udev_device_get_property_value(udev_device, "ID_PATH");
+ if (!id_path) {
+ return false;
}
+
+ const char prefix_platform[] = "platform-";
+ if (strncmp(id_path, prefix_platform, strlen(prefix_platform)) != 0) {
+ return false;
+ }
+
+ const char prefix_pci[] = "pci-";
+ const char infix_platform[] = "-platform-";
+ return (strncmp(id_path, prefix_pci, strlen(prefix_pci)) == 0) &&
+ strstr(id_path, infix_platform);
}
diff --git a/sway/input/seat.c b/sway/input/seat.c
index e16d747cf..c5c8459eb 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -15,10 +15,12 @@
#include "config.h"
#include "list.h"
#include "log.h"
+#include "sway/config.h"
#include "sway/desktop.h"
#include "sway/input/cursor.h"
#include "sway/input/input-manager.h"
#include "sway/input/keyboard.h"
+#include "sway/input/libinput.h"
#include "sway/input/seat.h"
#include "sway/input/switch.h"
#include "sway/input/tablet.h"
@@ -46,11 +48,26 @@ static void seat_device_destroy(struct sway_seat_device *seat_device) {
free(seat_device);
}
+static void seat_node_destroy(struct sway_seat_node *seat_node) {
+ wl_list_remove(&seat_node->destroy.link);
+ wl_list_remove(&seat_node->link);
+ free(seat_node);
+}
+
void seat_destroy(struct sway_seat *seat) {
+ if (seat == config->handler_context.seat) {
+ config->handler_context.seat = input_manager_get_default_seat();
+ }
struct sway_seat_device *seat_device, *next;
wl_list_for_each_safe(seat_device, next, &seat->devices, link) {
seat_device_destroy(seat_device);
}
+ struct sway_seat_node *seat_node, *next_seat_node;
+ wl_list_for_each_safe(seat_node, next_seat_node, &seat->focus_stack,
+ link) {
+ seat_node_destroy(seat_node);
+ }
+ sway_input_method_relay_finish(&seat->im_relay);
sway_cursor_destroy(seat->cursor);
wl_list_remove(&seat->new_node.link);
wl_list_remove(&seat->request_start_drag.link);
@@ -67,12 +84,6 @@ void seat_destroy(struct sway_seat *seat) {
free(seat);
}
-static void seat_node_destroy(struct sway_seat_node *seat_node) {
- wl_list_remove(&seat_node->destroy.link);
- wl_list_remove(&seat_node->link);
- free(seat_node);
-}
-
void seat_idle_notify_activity(struct sway_seat *seat,
enum sway_input_idle_source source) {
uint32_t mask = seat->idle_inhibit_sources;
@@ -199,14 +210,13 @@ void seat_for_each_node(struct sway_seat *seat,
struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat,
struct sway_node *ancestor) {
- if (ancestor->type == N_CONTAINER && ancestor->sway_container->view) {
+ if (node_is_view(ancestor)) {
return ancestor->sway_container;
}
struct sway_seat_node *current;
wl_list_for_each(current, &seat->focus_stack, link) {
struct sway_node *node = current->node;
- if (node->type == N_CONTAINER && node->sway_container->view &&
- node_has_ancestor(node, ancestor)) {
+ if (node_is_view(node) && node_has_ancestor(node, ancestor)) {
return node->sway_container;
}
}
@@ -299,8 +309,8 @@ static void handle_seat_node_destroy(struct wl_listener *listener, void *data) {
// Setting focus_inactive
focus = seat_get_focus_inactive(seat, &root->node);
seat_set_raw_focus(seat, next_focus);
- if (focus->type == N_CONTAINER && focus->sway_container->workspace) {
- seat_set_raw_focus(seat, &focus->sway_container->workspace->node);
+ if (focus->type == N_CONTAINER && focus->sway_container->pending.workspace) {
+ seat_set_raw_focus(seat, &focus->sway_container->pending.workspace->node);
}
seat_set_raw_focus(seat, focus);
}
@@ -656,23 +666,70 @@ static void seat_reset_input_config(struct sway_seat *seat,
sway_device->input_device->wlr_device, NULL);
}
+static bool has_prefix(const char *str, const char *prefix) {
+ return strncmp(str, prefix, strlen(prefix)) == 0;
+}
+
+/**
+ * Get the name of the built-in output, if any. Returns NULL if there isn't
+ * exactly one built-in output.
+ */
+static const char *get_builtin_output_name(void) {
+ const char *match = NULL;
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ const char *name = output->wlr_output->name;
+ if (has_prefix(name, "eDP-") || has_prefix(name, "LVDS-") ||
+ has_prefix(name, "DSI-")) {
+ if (match != NULL) {
+ return NULL;
+ }
+ match = name;
+ }
+ }
+ return match;
+}
+
+static bool is_touch_or_tablet_tool(struct sway_seat_device *seat_device) {
+ switch (seat_device->input_device->wlr_device->type) {
+ case WLR_INPUT_DEVICE_TOUCH:
+ case WLR_INPUT_DEVICE_TABLET_TOOL:
+ return true;
+ default:
+ return false;
+ }
+}
+
static void seat_apply_input_config(struct sway_seat *seat,
struct sway_seat_device *sway_device) {
struct input_config *ic =
input_device_get_config(sway_device->input_device);
- if (ic == NULL) {
- return;
- }
sway_log(SWAY_DEBUG, "Applying input config to %s",
sway_device->input_device->identifier);
- const char *mapped_to_output = ic->mapped_to_output;
- struct wlr_box *mapped_to_region = ic->mapped_to_region;
+ const char *mapped_to_output = ic == NULL ? NULL : ic->mapped_to_output;
+ struct wlr_box *mapped_to_region = ic == NULL ? NULL : ic->mapped_to_region;
+ enum input_config_mapped_to mapped_to =
+ ic == NULL ? MAPPED_TO_DEFAULT : ic->mapped_to;
- switch (ic->mapped_to) {
+ switch (mapped_to) {
case MAPPED_TO_DEFAULT:
+ /*
+ * If the wlroots backend provides an output name, use that.
+ *
+ * Otherwise, try to map built-in touch and tablet tool devices to the
+ * built-in output.
+ */
mapped_to_output = sway_device->input_device->wlr_device->output_name;
+ if (mapped_to_output == NULL && is_touch_or_tablet_tool(sway_device) &&
+ sway_libinput_device_is_builtin(sway_device->input_device)) {
+ mapped_to_output = get_builtin_output_name();
+ if (mapped_to_output) {
+ sway_log(SWAY_DEBUG, "Auto-detected output '%s' for device '%s'",
+ mapped_to_output, sway_device->input_device->identifier);
+ }
+ }
if (mapped_to_output == NULL) {
return;
}
@@ -722,6 +779,8 @@ static void seat_configure_pointer(struct sway_seat *seat,
wlr_cursor_attach_input_device(seat->cursor->cursor,
sway_device->input_device->wlr_device);
seat_apply_input_config(seat, sway_device);
+ wl_event_source_timer_update(
+ seat->cursor->hide_source, cursor_get_timeout(seat->cursor));
}
static void seat_configure_keyboard(struct sway_seat *seat,
@@ -1075,30 +1134,19 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
}
struct sway_workspace *new_workspace = node->type == N_WORKSPACE ?
- node->sway_workspace : node->sway_container->workspace;
+ node->sway_workspace : node->sway_container->pending.workspace;
struct sway_container *container = node->type == N_CONTAINER ?
node->sway_container : NULL;
- // Deny setting focus to a view which is hidden by a fullscreen container
- if (new_workspace && new_workspace->fullscreen && container &&
- !container_is_fullscreen_or_child(container)) {
- // Unless it's a transient container
- if (!container_is_transient_for(container, new_workspace->fullscreen)) {
- return;
- }
+ // Deny setting focus to a view which is hidden by a fullscreen container or global
+ if (container && container_obstructing_fullscreen_container(container)) {
+ return;
}
+
// Deny setting focus to a workspace node when using fullscreen global
if (root->fullscreen_global && !container && new_workspace) {
return;
}
- // Deny setting focus to a view which is hidden by a fullscreen global
- if (root->fullscreen_global && container != root->fullscreen_global &&
- !container_has_ancestor(container, root->fullscreen_global)) {
- // Unless it's a transient container
- if (!container_is_transient_for(container, root->fullscreen_global)) {
- return;
- }
- }
struct sway_output *new_output =
new_workspace ? new_workspace->output : NULL;
@@ -1124,10 +1172,10 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
// Put the container parents on the focus stack, then the workspace, then
// the focused container.
if (container) {
- struct sway_container *parent = container->parent;
+ struct sway_container *parent = container->pending.parent;
while (parent) {
seat_set_raw_focus(seat, &parent->node);
- parent = parent->parent;
+ parent = parent->pending.parent;
}
}
if (new_workspace) {
@@ -1150,7 +1198,7 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
for (int i = 0; i < new_output_last_ws->floating->length; ++i) {
struct sway_container *floater =
new_output_last_ws->floating->items[i];
- if (floater->is_sticky) {
+ if (container_is_sticky(floater)) {
container_detach(floater);
workspace_add_floating(new_workspace, floater);
--i;
@@ -1223,6 +1271,7 @@ void seat_set_focus_surface(struct sway_seat *seat,
wlr_seat_keyboard_notify_clear_focus(seat->wlr_seat);
}
+ sway_input_method_relay_set_focus(&seat->im_relay, surface);
seat_tablet_pads_notify_enter(seat, surface);
}
@@ -1315,7 +1364,7 @@ struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat,
struct sway_node *node = current->node;
if (node->type == N_CONTAINER &&
!container_is_floating_or_child(node->sway_container) &&
- node->sway_container->workspace == workspace) {
+ node->sway_container->pending.workspace == workspace) {
return node->sway_container;
}
}
@@ -1332,7 +1381,7 @@ struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat,
struct sway_node *node = current->node;
if (node->type == N_CONTAINER &&
container_is_floating_or_child(node->sway_container) &&
- node->sway_container->workspace == workspace) {
+ node->sway_container->pending.workspace == workspace) {
return node->sway_container;
}
}
@@ -1380,7 +1429,7 @@ struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat) {
return NULL;
}
if (focus->type == N_CONTAINER) {
- return focus->sway_container->workspace;
+ return focus->sway_container->pending.workspace;
}
if (focus->type == N_WORKSPACE) {
return focus->sway_workspace;
@@ -1393,8 +1442,8 @@ struct sway_workspace *seat_get_last_known_workspace(struct sway_seat *seat) {
wl_list_for_each(current, &seat->focus_stack, link) {
struct sway_node *node = current->node;
if (node->type == N_CONTAINER &&
- node->sway_container->workspace) {
- return node->sway_container->workspace;
+ node->sway_container->pending.workspace) {
+ return node->sway_container->pending.workspace;
} else if (node->type == N_WORKSPACE) {
return node->sway_workspace;
}
@@ -1423,7 +1472,7 @@ void seat_apply_config(struct sway_seat *seat,
wl_list_for_each(seat_device, &seat->devices, link) {
seat_configure_device(seat, seat_device->input_device);
- cursor_handle_activity(seat->cursor,
+ cursor_handle_activity_from_device(seat->cursor,
seat_device->input_device->wlr_device);
}
}
@@ -1476,14 +1525,10 @@ void seat_consider_warp_to_focus(struct sway_seat *seat) {
}
if (focus->type == N_CONTAINER) {
- cursor_warp_to_container(seat->cursor, focus->sway_container);
+ cursor_warp_to_container(seat->cursor, focus->sway_container, false);
} else {
cursor_warp_to_workspace(seat->cursor, focus->sway_workspace);
}
- if (seat->cursor->hidden){
- cursor_unhide(seat->cursor);
- wl_event_source_timer_update(seat->cursor->hide_source, cursor_get_timeout(seat->cursor));
- }
}
void seatop_unref(struct sway_seat *seat, struct sway_container *con) {
@@ -1500,10 +1545,9 @@ void seatop_button(struct sway_seat *seat, uint32_t time_msec,
}
}
-void seatop_pointer_motion(struct sway_seat *seat, uint32_t time_msec,
- double dx, double dy) {
+void seatop_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
if (seat->seatop_impl->pointer_motion) {
- seat->seatop_impl->pointer_motion(seat, time_msec, dx, dy);
+ seat->seatop_impl->pointer_motion(seat, time_msec);
}
}
@@ -1523,11 +1567,11 @@ void seatop_tablet_tool_tip(struct sway_seat *seat,
}
void seatop_tablet_tool_motion(struct sway_seat *seat,
- struct sway_tablet_tool *tool, uint32_t time_msec, double dx, double dy) {
+ struct sway_tablet_tool *tool, uint32_t time_msec) {
if (seat->seatop_impl->tablet_tool_motion) {
- seat->seatop_impl->tablet_tool_motion(seat, tool, time_msec, dx, dy);
+ seat->seatop_impl->tablet_tool_motion(seat, tool, time_msec);
} else {
- seatop_pointer_motion(seat, time_msec, dx, dy);
+ seatop_pointer_motion(seat, time_msec);
}
}
diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c
index 55c9159ac..4320a3b4a 100644
--- a/sway/input/seatop_default.c
+++ b/sway/input/seatop_default.c
@@ -4,10 +4,13 @@
#include
#include
#include
+#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
#include "sway/input/tablet.h"
+#include "sway/output.h"
#include "sway/tree/view.h"
+#include "sway/tree/workspace.h"
#include "log.h"
#if HAVE_XWAYLAND
#include "sway/xwayland.h"
@@ -57,7 +60,7 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) {
return false;
}
}
- cont = cont->parent;
+ cont = cont->pending.parent;
}
return true;
}
@@ -67,22 +70,25 @@ static enum wlr_edges find_edge(struct sway_container *cont,
if (!cont->view || (surface && cont->view->surface != surface)) {
return WLR_EDGE_NONE;
}
- if (cont->border == B_NONE || !cont->border_thickness ||
- cont->border == B_CSD) {
+ if (cont->pending.border == B_NONE || !cont->pending.border_thickness ||
+ cont->pending.border == B_CSD) {
+ return WLR_EDGE_NONE;
+ }
+ if (cont->pending.fullscreen_mode) {
return WLR_EDGE_NONE;
}
enum wlr_edges edge = 0;
- if (cursor->cursor->x < cont->x + cont->border_thickness) {
+ if (cursor->cursor->x < cont->pending.x + cont->pending.border_thickness) {
edge |= WLR_EDGE_LEFT;
}
- if (cursor->cursor->y < cont->y + cont->border_thickness) {
+ if (cursor->cursor->y < cont->pending.y + cont->pending.border_thickness) {
edge |= WLR_EDGE_TOP;
}
- if (cursor->cursor->x >= cont->x + cont->width - cont->border_thickness) {
+ if (cursor->cursor->x >= cont->pending.x + cont->pending.width - cont->pending.border_thickness) {
edge |= WLR_EDGE_RIGHT;
}
- if (cursor->cursor->y >= cont->y + cont->height - cont->border_thickness) {
+ if (cursor->cursor->y >= cont->pending.y + cont->pending.height - cont->pending.border_thickness) {
edge |= WLR_EDGE_BOTTOM;
}
@@ -226,6 +232,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
wlr_layer_surface_v1_from_wlr_surface(surface);
if (layer->current.keyboard_interactive) {
seat_set_focus_layer(seat, layer);
+ transaction_commit_dirty();
}
} else if (cont) {
bool is_floating_or_child = container_is_floating_or_child(cont);
@@ -244,7 +251,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
// Handle moving a tiling container
if (config->tiling_drag && mod_pressed && !is_floating_or_child &&
- cont->fullscreen_mode == FULLSCREEN_NONE) {
+ cont->pending.fullscreen_mode == FULLSCREEN_NONE) {
seatop_begin_move_tiling(seat, cont);
return;
}
@@ -263,6 +270,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
seat_set_focus_surface(seat, xsurface->surface, false);
+ transaction_commit_dirty();
}
}
#endif
@@ -351,6 +359,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
if (node && node->type == N_WORKSPACE) {
if (state == WLR_BUTTON_PRESSED) {
seat_set_focus(seat, node);
+ transaction_commit_dirty();
}
seat_pointer_notify_button(seat, time_msec, button, state);
return;
@@ -362,6 +371,10 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
wlr_layer_surface_v1_from_wlr_surface(surface);
if (layer->current.keyboard_interactive) {
seat_set_focus_layer(seat, layer);
+ transaction_commit_dirty();
+ }
+ if (state == WLR_BUTTON_PRESSED) {
+ seatop_begin_down_on_surface(seat, surface, time_msec, sx, sy);
}
seat_pointer_notify_button(seat, time_msec, button, state);
return;
@@ -376,7 +389,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
struct sway_container *cont_to_focus = cont;
enum sway_container_layout layout = container_parent_layout(cont);
if (layout == L_TABBED || layout == L_STACKED) {
- cont_to_focus = seat_get_focus_inactive_view(seat, &cont->parent->node);
+ cont_to_focus = seat_get_focus_inactive_view(seat, &cont->pending.parent->node);
}
seat_set_focus_container(seat, cont_to_focus);
@@ -392,9 +405,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
BTN_LEFT : BTN_RIGHT;
if (button == btn_resize) {
edge = 0;
- edge |= cursor->cursor->x > cont->x + cont->width / 2 ?
+ edge |= cursor->cursor->x > cont->pending.x + cont->pending.width / 2 ?
WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
- edge |= cursor->cursor->y > cont->y + cont->height / 2 ?
+ edge |= cursor->cursor->y > cont->pending.y + cont->pending.height / 2 ?
WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
const char *image = NULL;
@@ -441,9 +454,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
if (mod_pressed && button == btn_resize) {
struct sway_container *floater = container_toplevel_ancestor(cont);
edge = 0;
- edge |= cursor->cursor->x > floater->x + floater->width / 2 ?
+ edge |= cursor->cursor->x > floater->pending.x + floater->pending.width / 2 ?
WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
- edge |= cursor->cursor->y > floater->y + floater->height / 2 ?
+ edge |= cursor->cursor->y > floater->pending.y + floater->pending.height / 2 ?
WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
seatop_begin_resize_floating(seat, floater, edge);
return;
@@ -453,7 +466,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
// Handle moving a tiling container
if (config->tiling_drag && (mod_pressed || on_titlebar) &&
state == WLR_BUTTON_PRESSED && !is_floating_or_child &&
- cont && cont->fullscreen_mode == FULLSCREEN_NONE) {
+ cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) {
struct sway_container *focus = seat_get_focused_container(seat);
bool focused = focus == cont || container_has_ancestor(focus, cont);
if (on_titlebar && !focused) {
@@ -482,6 +495,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
if (cont && state == WLR_BUTTON_PRESSED) {
node = seat_get_focus_inactive(seat, &cont->node);
seat_set_focus(seat, node);
+ transaction_commit_dirty();
seat_pointer_notify_button(seat, time_msec, button, state);
return;
}
@@ -496,6 +510,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
seat_set_focus_surface(seat, xsurface->surface, false);
+ transaction_commit_dirty();
seat_pointer_notify_button(seat, time_msec, button, state);
return;
}
@@ -513,6 +528,23 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
struct seatop_default_event *e, struct sway_node *hovered_node) {
struct sway_node *focus = seat_get_focus(seat);
+ // This is the case if a layer-shell surface is hovered.
+ // If it's on another output, focus the active workspace there.
+ if (!hovered_node) {
+ struct wlr_output *wlr_output = wlr_output_layout_output_at(
+ root->output_layout, seat->cursor->cursor->x, seat->cursor->cursor->y);
+ if (wlr_output == NULL) {
+ return;
+ }
+ struct sway_output *hovered_output = wlr_output->data;
+ if (focus && hovered_output != node_get_output(focus)) {
+ struct sway_workspace *ws = output_get_active_workspace(hovered_output);
+ seat_set_focus(seat, &ws->node);
+ transaction_commit_dirty();
+ }
+ return;
+ }
+
// If a workspace node is hovered (eg. in the gap area), only set focus if
// the workspace is on a different output to the previous focus.
if (focus && hovered_node->type == N_WORKSPACE) {
@@ -520,6 +552,7 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
struct sway_output *hovered_output = node_get_output(hovered_node);
if (hovered_output != focused_output) {
seat_set_focus(seat, seat_get_focus_inactive(seat, hovered_node));
+ transaction_commit_dirty();
}
return;
}
@@ -535,12 +568,12 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
if (hovered_node != e->previous_node ||
config->focus_follows_mouse == FOLLOWS_ALWAYS) {
seat_set_focus(seat, hovered_node);
+ transaction_commit_dirty();
}
}
}
-static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec,
- double dx, double dy) {
+static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
struct seatop_default_event *e = seat->seatop_data;
struct sway_cursor *cursor = seat->cursor;
@@ -549,7 +582,7 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec,
struct sway_node *node = node_at_coords(seat,
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
- if (node && config->focus_follows_mouse != FOLLOWS_NO) {
+ if (config->focus_follows_mouse != FOLLOWS_NO) {
check_focus_follows_mouse(seat, e, node);
}
@@ -574,7 +607,7 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec,
}
static void handle_tablet_tool_motion(struct sway_seat *seat,
- struct sway_tablet_tool *tool, uint32_t time_msec, double dx, double dy) {
+ struct sway_tablet_tool *tool, uint32_t time_msec) {
struct seatop_default_event *e = seat->seatop_data;
struct sway_cursor *cursor = seat->cursor;
@@ -583,7 +616,7 @@ static void handle_tablet_tool_motion(struct sway_seat *seat,
struct sway_node *node = node_at_coords(seat,
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
- if (node && config->focus_follows_mouse != FOLLOWS_NO) {
+ if (config->focus_follows_mouse != FOLLOWS_NO) {
check_focus_follows_mouse(seat, e, node);
}
@@ -644,7 +677,7 @@ static void handle_pointer_axis(struct sway_seat *seat,
bool on_border = edge != WLR_EDGE_NONE;
bool on_titlebar = cont && !on_border && !surface;
bool on_titlebar_border = cont && on_border &&
- cursor->cursor->y < cont->content_y;
+ cursor->cursor->y < cont->pending.content_y;
bool on_contents = cont && !on_border && surface;
bool on_workspace = node && node->type == N_WORKSPACE;
float scroll_factor =
@@ -686,19 +719,15 @@ static void handle_pointer_axis(struct sway_seat *seat,
} else if (desired >= siblings->length) {
desired = siblings->length - 1;
}
- struct sway_node *old_focus = seat_get_focus(seat);
+
struct sway_container *new_sibling_con = siblings->items[desired];
struct sway_node *new_sibling = &new_sibling_con->node;
struct sway_node *new_focus =
seat_get_focus_inactive(seat, new_sibling);
- if (node_has_ancestor(old_focus, tabcontainer)) {
- seat_set_focus(seat, new_focus);
- } else {
- // Scrolling when focus is not in the tabbed container at all
- seat_set_raw_focus(seat, new_sibling);
- seat_set_raw_focus(seat, new_focus);
- seat_set_raw_focus(seat, old_focus);
- }
+ // Use the focused child of the tabbed/stacked container, not the
+ // container the user scrolled on.
+ seat_set_focus(seat, new_focus);
+ transaction_commit_dirty();
handled = true;
}
}
diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c
index 0d24f480d..ecc34feab 100644
--- a/sway/input/seatop_down.c
+++ b/sway/input/seatop_down.c
@@ -5,10 +5,14 @@
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
#include "sway/tree/view.h"
+#include "sway/desktop/transaction.h"
#include "log.h"
struct seatop_down_event {
struct sway_container *con;
+ struct sway_seat *seat;
+ struct wl_listener surface_destroy;
+ struct wlr_surface *surface;
double ref_lx, ref_ly; // cursor's x/y at start of op
double ref_con_lx, ref_con_ly; // container's x/y at start of op
};
@@ -37,11 +41,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
}
}
-static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec,
- double dx, double dy) {
+static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
struct seatop_down_event *e = seat->seatop_data;
- struct sway_container *con = e->con;
- if (seat_is_input_allowed(seat, con->view->surface)) {
+ if (seat_is_input_allowed(seat, e->surface)) {
double moved_x = seat->cursor->cursor->x - e->ref_lx;
double moved_y = seat->cursor->cursor->y - e->ref_ly;
double sx = e->ref_con_lx + moved_x;
@@ -60,10 +62,9 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
}
static void handle_tablet_tool_motion(struct sway_seat *seat,
- struct sway_tablet_tool *tool, uint32_t time_msec, double dx, double dy) {
+ struct sway_tablet_tool *tool, uint32_t time_msec) {
struct seatop_down_event *e = seat->seatop_data;
- struct sway_container *con = e->con;
- if (seat_is_input_allowed(seat, con->view->surface)) {
+ if (seat_is_input_allowed(seat, e->surface)) {
double moved_x = seat->cursor->cursor->x - e->ref_lx;
double moved_y = seat->cursor->cursor->y - e->ref_ly;
double sx = e->ref_con_lx + moved_x;
@@ -72,6 +73,14 @@ static void handle_tablet_tool_motion(struct sway_seat *seat,
}
}
+static void handle_destroy(struct wl_listener *listener, void *data) {
+ struct seatop_down_event *e =
+ wl_container_of(listener, e, surface_destroy);
+ if (e) {
+ seatop_begin_default(e->seat);
+ }
+}
+
static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
struct seatop_down_event *e = seat->seatop_data;
if (e->con == con) {
@@ -79,6 +88,11 @@ static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
}
}
+static void handle_end(struct sway_seat *seat) {
+ struct seatop_down_event *e = seat->seatop_data;
+ wl_list_remove(&e->surface_destroy.link);
+}
+
static const struct sway_seatop_impl seatop_impl = {
.button = handle_button,
.pointer_motion = handle_pointer_motion,
@@ -86,11 +100,22 @@ static const struct sway_seatop_impl seatop_impl = {
.tablet_tool_tip = handle_tablet_tool_tip,
.tablet_tool_motion = handle_tablet_tool_motion,
.unref = handle_unref,
+ .end = handle_end,
.allow_set_cursor = true,
};
void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
- uint32_t time_msec, int sx, int sy) {
+ uint32_t time_msec, double sx, double sy) {
+ seatop_begin_down_on_surface(seat, con->view->surface, time_msec, sx, sy);
+ struct seatop_down_event *e = seat->seatop_data;
+ e->con = con;
+
+ container_raise_floating(con);
+ transaction_commit_dirty();
+}
+
+void seatop_begin_down_on_surface(struct sway_seat *seat,
+ struct wlr_surface *surface, uint32_t time_msec, double sx, double sy) {
seatop_end(seat);
struct seatop_down_event *e =
@@ -98,7 +123,11 @@ void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
if (!e) {
return;
}
- e->con = con;
+ e->con = NULL;
+ e->seat = seat;
+ e->surface = surface;
+ wl_signal_add(&e->surface->events.destroy, &e->surface_destroy);
+ e->surface_destroy.notify = handle_destroy;
e->ref_lx = seat->cursor->cursor->x;
e->ref_ly = seat->cursor->cursor->y;
e->ref_con_lx = sx;
@@ -106,6 +135,4 @@ void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
seat->seatop_impl = &seatop_impl;
seat->seatop_data = e;
-
- container_raise_floating(con);
}
diff --git a/sway/input/seatop_move_floating.c b/sway/input/seatop_move_floating.c
index b9a20402a..ddcd4c53e 100644
--- a/sway/input/seatop_move_floating.c
+++ b/sway/input/seatop_move_floating.c
@@ -1,6 +1,7 @@
#define _POSIX_C_SOURCE 200809L
#include
#include "sway/desktop.h"
+#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
@@ -14,7 +15,8 @@ static void finalize_move(struct sway_seat *seat) {
// We "move" the container to its own location
// so it discovers its output again.
- container_floating_move_to(e->con, e->con->x, e->con->y);
+ container_floating_move_to(e->con, e->con->pending.x, e->con->pending.y);
+ transaction_commit_dirty();
seatop_begin_default(seat);
}
@@ -34,13 +36,13 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
finalize_move(seat);
}
}
-static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec,
- double dx, double dy) {
+static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
struct seatop_move_floating_event *e = seat->seatop_data;
struct wlr_cursor *cursor = seat->cursor->cursor;
desktop_damage_whole_container(e->con);
container_floating_move_to(e->con, cursor->x - e->dx, cursor->y - e->dy);
desktop_damage_whole_container(e->con);
+ transaction_commit_dirty();
}
static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
@@ -68,13 +70,14 @@ void seatop_begin_move_floating(struct sway_seat *seat,
return;
}
e->con = con;
- e->dx = cursor->cursor->x - con->x;
- e->dy = cursor->cursor->y - con->y;
+ e->dx = cursor->cursor->x - con->pending.x;
+ e->dy = cursor->cursor->y - con->pending.y;
seat->seatop_impl = &seatop_impl;
seat->seatop_data = e;
container_raise_floating(con);
+ transaction_commit_dirty();
cursor_set_image(cursor, "grab", NULL);
wlr_seat_pointer_notify_clear_focus(seat->wlr_seat);
diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c
index 09689183e..223c6c08c 100644
--- a/sway/input/seatop_move_tiling.c
+++ b/sway/input/seatop_move_tiling.c
@@ -3,8 +3,10 @@
#include
#include
#include "sway/desktop.h"
+#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
+#include "sway/ipc-server.h"
#include "sway/output.h"
#include "sway/tree/arrange.h"
#include "sway/tree/node.h"
@@ -14,6 +16,10 @@
// Thickness of the dropzone when dragging to the edge of a layout container
#define DROP_LAYOUT_BORDER 30
+// Thickness of indicator when dropping onto a titlebar. This should be a
+// multiple of 2.
+#define DROP_SPLIT_INDICATOR 10
+
struct seatop_move_tiling_event {
struct sway_container *con;
struct sway_node *target_node;
@@ -21,6 +27,8 @@ struct seatop_move_tiling_event {
struct wlr_box drop_box;
double ref_lx, ref_ly; // cursor's x/y at start of op
bool threshold_reached;
+ bool split_target;
+ bool insert_after_target;
};
static void handle_render(struct sway_seat *seat,
@@ -90,8 +98,76 @@ static void resize_box(struct wlr_box *box, enum wlr_edges edge,
}
}
+static void split_border(double pos, int offset, int len, int n_children,
+ int avoid, int *out_pos, bool *out_after) {
+ int region = 2 * n_children * (pos - offset) / len;
+ // If the cursor is over the right side of a left-adjacent titlebar, or the
+ // left side of a right-adjacent titlebar, it's position when dropped will
+ // be the same. To avoid this, shift the region for adjacent containers.
+ if (avoid >= 0) {
+ if (region == 2 * avoid - 1 || region == 2 * avoid) {
+ region--;
+ } else if (region == 2 * avoid + 1 || region == 2 * avoid + 2) {
+ region++;
+ }
+ }
+
+ int child_index = (region + 1) / 2;
+ *out_after = region % 2;
+ // When dropping at the beginning or end of a container, show the drop
+ // region within the container boundary, otherwise show it on top of the
+ // border between two titlebars.
+ if (child_index == 0) {
+ *out_pos = offset;
+ } else if (child_index == n_children) {
+ *out_pos = offset + len - DROP_SPLIT_INDICATOR;
+ } else {
+ *out_pos = offset + child_index * len / n_children -
+ DROP_SPLIT_INDICATOR / 2;
+ }
+}
+
+static bool split_titlebar(struct sway_node *node, struct sway_container *avoid,
+ struct wlr_cursor *cursor, struct wlr_box *title_box, bool *after) {
+ struct sway_container *con = node->sway_container;
+ struct sway_node *parent = &con->pending.parent->node;
+ int title_height = container_titlebar_height();
+ struct wlr_box box;
+ int n_children, avoid_index;
+ enum sway_container_layout layout =
+ parent ? node_get_layout(parent) : L_NONE;
+ if (layout == L_TABBED || layout == L_STACKED) {
+ node_get_box(parent, &box);
+ n_children = node_get_children(parent)->length;
+ avoid_index = list_find(node_get_children(parent), avoid);
+ } else {
+ node_get_box(node, &box);
+ n_children = 1;
+ avoid_index = -1;
+ }
+ if (layout == L_STACKED && cursor->y < box.y + title_height * n_children) {
+ // Drop into stacked titlebars.
+ title_box->width = box.width;
+ title_box->height = DROP_SPLIT_INDICATOR;
+ title_box->x = box.x;
+ split_border(cursor->y, box.y, title_height * n_children,
+ n_children, avoid_index, &title_box->y, after);
+ return true;
+ } else if (layout != L_STACKED && cursor->y < box.y + title_height) {
+ // Drop into side-by-side titlebars.
+ title_box->width = DROP_SPLIT_INDICATOR;
+ title_box->height = title_height;
+ title_box->y = box.y;
+ split_border(cursor->x, box.x, box.width, n_children,
+ avoid_index, &title_box->x, after);
+ return true;
+ }
+ return false;
+}
+
static void handle_motion_postthreshold(struct sway_seat *seat) {
struct seatop_move_tiling_event *e = seat->seatop_data;
+ e->split_target = false;
struct wlr_surface *surface = NULL;
double sx, sy;
struct sway_cursor *cursor = seat->cursor;
@@ -118,34 +194,60 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
// Deny moving within own workspace if this is the only child
struct sway_container *con = node->sway_container;
- if (workspace_num_tiling_views(e->con->workspace) == 1 &&
- con->workspace == e->con->workspace) {
+ if (workspace_num_tiling_views(e->con->pending.workspace) == 1 &&
+ con->pending.workspace == e->con->pending.workspace) {
e->target_node = NULL;
e->target_edge = WLR_EDGE_NONE;
return;
}
+ // Check if the cursor is over a tilebar only if the destination
+ // container is not a descendant of the source container.
+ if (!surface && !container_has_ancestor(con, e->con) &&
+ split_titlebar(node, e->con, cursor->cursor,
+ &e->drop_box, &e->insert_after_target)) {
+ // Don't allow dropping over the source container's titlebar
+ // to give users a chance to cancel a drag operation.
+ if (con == e->con) {
+ e->target_node = NULL;
+ } else {
+ e->target_node = node;
+ e->split_target = true;
+ }
+ e->target_edge = WLR_EDGE_NONE;
+ return;
+ }
+
// Traverse the ancestors, trying to find a layout container perpendicular
// to the edge. Eg. close to the top or bottom of a horiz layout.
+ int thresh_top = con->pending.content_y + DROP_LAYOUT_BORDER;
+ int thresh_bottom = con->pending.content_y +
+ con->pending.content_height - DROP_LAYOUT_BORDER;
+ int thresh_left = con->pending.content_x + DROP_LAYOUT_BORDER;
+ int thresh_right = con->pending.content_x +
+ con->pending.content_width - DROP_LAYOUT_BORDER;
while (con) {
enum wlr_edges edge = WLR_EDGE_NONE;
enum sway_container_layout layout = container_parent_layout(con);
- struct wlr_box parent;
- con->parent ? container_get_box(con->parent, &parent) :
- workspace_get_box(con->workspace, &parent);
+ struct wlr_box box;
+ node_get_box(node_get_parent(&con->node), &box);
if (layout == L_HORIZ || layout == L_TABBED) {
- if (cursor->cursor->y < parent.y + DROP_LAYOUT_BORDER) {
+ if (cursor->cursor->y < thresh_top) {
edge = WLR_EDGE_TOP;
- } else if (cursor->cursor->y > parent.y + parent.height
- - DROP_LAYOUT_BORDER) {
+ box.height = thresh_top - box.y;
+ } else if (cursor->cursor->y > thresh_bottom) {
edge = WLR_EDGE_BOTTOM;
+ box.height = box.y + box.height - thresh_bottom;
+ box.y = thresh_bottom;
}
} else if (layout == L_VERT || layout == L_STACKED) {
- if (cursor->cursor->x < parent.x + DROP_LAYOUT_BORDER) {
+ if (cursor->cursor->x < thresh_left) {
edge = WLR_EDGE_LEFT;
- } else if (cursor->cursor->x > parent.x + parent.width
- - DROP_LAYOUT_BORDER) {
+ box.width = thresh_left - box.x;
+ } else if (cursor->cursor->x > thresh_right) {
edge = WLR_EDGE_RIGHT;
+ box.width = box.x + box.width - thresh_right;
+ box.x = thresh_right;
}
}
if (edge) {
@@ -154,12 +256,11 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
e->target_node = node_get_parent(e->target_node);
}
e->target_edge = edge;
- node_get_box(e->target_node, &e->drop_box);
- resize_box(&e->drop_box, edge, DROP_LAYOUT_BORDER);
+ e->drop_box = box;
desktop_damage_box(&e->drop_box);
return;
}
- con = con->parent;
+ con = con->pending.parent;
}
// Use the hovered view - but we must be over the actual surface
@@ -172,23 +273,23 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
}
// Find the closest edge
- size_t thickness = fmin(con->content_width, con->content_height) * 0.3;
+ size_t thickness = fmin(con->pending.content_width, con->pending.content_height) * 0.3;
size_t closest_dist = INT_MAX;
size_t dist;
e->target_edge = WLR_EDGE_NONE;
- if ((dist = cursor->cursor->y - con->y) < closest_dist) {
+ if ((dist = cursor->cursor->y - con->pending.y) < closest_dist) {
closest_dist = dist;
e->target_edge = WLR_EDGE_TOP;
}
- if ((dist = cursor->cursor->x - con->x) < closest_dist) {
+ if ((dist = cursor->cursor->x - con->pending.x) < closest_dist) {
closest_dist = dist;
e->target_edge = WLR_EDGE_LEFT;
}
- if ((dist = con->x + con->width - cursor->cursor->x) < closest_dist) {
+ if ((dist = con->pending.x + con->pending.width - cursor->cursor->x) < closest_dist) {
closest_dist = dist;
e->target_edge = WLR_EDGE_RIGHT;
}
- if ((dist = con->y + con->height - cursor->cursor->y) < closest_dist) {
+ if ((dist = con->pending.y + con->pending.height - cursor->cursor->y) < closest_dist) {
closest_dist = dist;
e->target_edge = WLR_EDGE_BOTTOM;
}
@@ -198,22 +299,22 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
}
e->target_node = node;
- e->drop_box.x = con->content_x;
- e->drop_box.y = con->content_y;
- e->drop_box.width = con->content_width;
- e->drop_box.height = con->content_height;
+ e->drop_box.x = con->pending.content_x;
+ e->drop_box.y = con->pending.content_y;
+ e->drop_box.width = con->pending.content_width;
+ e->drop_box.height = con->pending.content_height;
resize_box(&e->drop_box, e->target_edge, thickness);
desktop_damage_box(&e->drop_box);
}
-static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec,
- double dx, double dy) {
+static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
struct seatop_move_tiling_event *e = seat->seatop_data;
if (e->threshold_reached) {
handle_motion_postthreshold(seat);
} else {
handle_motion_prethreshold(seat);
}
+ transaction_commit_dirty();
}
static bool is_parallel(enum sway_container_layout layout,
@@ -232,14 +333,15 @@ static void finalize_move(struct sway_seat *seat) {
}
struct sway_container *con = e->con;
- struct sway_container *old_parent = con->parent;
- struct sway_workspace *old_ws = con->workspace;
+ struct sway_container *old_parent = con->pending.parent;
+ struct sway_workspace *old_ws = con->pending.workspace;
struct sway_node *target_node = e->target_node;
struct sway_workspace *new_ws = target_node->type == N_WORKSPACE ?
- target_node->sway_workspace : target_node->sway_container->workspace;
+ target_node->sway_workspace : target_node->sway_container->pending.workspace;
enum wlr_edges edge = e->target_edge;
int after = edge != WLR_EDGE_TOP && edge != WLR_EDGE_LEFT;
- bool swap = edge == WLR_EDGE_NONE && target_node->type == N_CONTAINER;
+ bool swap = edge == WLR_EDGE_NONE && target_node->type == N_CONTAINER &&
+ !e->split_target;
if (!swap) {
container_detach(con);
@@ -247,7 +349,15 @@ static void finalize_move(struct sway_seat *seat) {
// Moving container into empty workspace
if (target_node->type == N_WORKSPACE && edge == WLR_EDGE_NONE) {
- workspace_add_tiling(new_ws, con);
+ con = workspace_add_tiling(new_ws, con);
+ } else if (e->split_target) {
+ struct sway_container *target = target_node->sway_container;
+ enum sway_container_layout layout = container_parent_layout(target);
+ if (layout != L_TABBED && layout != L_STACKED) {
+ container_split(target, L_TABBED);
+ }
+ container_add_sibling(target, con, e->insert_after_target);
+ ipc_event_window(con, "move");
} else if (target_node->type == N_CONTAINER) {
// Moving container before/after another
struct sway_container *target = target_node->sway_container;
@@ -261,6 +371,7 @@ static void finalize_move(struct sway_seat *seat) {
container_split(target, new_layout);
}
container_add_sibling(target, con, after);
+ ipc_event_window(con, "move");
}
} else {
// Target is a workspace which requires splitting
@@ -282,8 +393,8 @@ static void finalize_move(struct sway_seat *seat) {
int index = list_find(siblings, con);
struct sway_container *sibling = index == 0 ?
siblings->items[1] : siblings->items[index - 1];
- con->width = sibling->width;
- con->height = sibling->height;
+ con->pending.width = sibling->pending.width;
+ con->pending.height = sibling->pending.height;
con->width_fraction = sibling->width_fraction;
con->height_fraction = sibling->height_fraction;
}
@@ -293,6 +404,7 @@ static void finalize_move(struct sway_seat *seat) {
arrange_workspace(new_ws);
}
+ transaction_commit_dirty();
seatop_begin_default(seat);
}
@@ -347,6 +459,7 @@ void seatop_begin_move_tiling_threshold(struct sway_seat *seat,
seat->seatop_data = e;
container_raise_floating(con);
+ transaction_commit_dirty();
wlr_seat_pointer_notify_clear_focus(seat->wlr_seat);
}
diff --git a/sway/input/seatop_resize_floating.c b/sway/input/seatop_resize_floating.c
index 10af06fed..8400a4b30 100644
--- a/sway/input/seatop_resize_floating.c
+++ b/sway/input/seatop_resize_floating.c
@@ -2,6 +2,7 @@
#include
#include
#include
+#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
#include "sway/tree/arrange.h"
@@ -27,12 +28,12 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
if (seat->cursor->pressed_button_count == 0) {
container_set_resizing(con, false);
arrange_container(con); // Send configure w/o resizing hint
+ transaction_commit_dirty();
seatop_begin_default(seat);
}
}
-static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec,
- double dx, double dy) {
+static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
struct seatop_resize_floating_event *e = seat->seatop_data;
struct sway_container *con = e->con;
enum wlr_edges edge = e->edge;
@@ -117,23 +118,24 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec,
// Determine the amounts we need to bump everything relative to the current
// size.
- int relative_grow_width = width - con->width;
- int relative_grow_height = height - con->height;
- int relative_grow_x = (e->ref_con_lx + grow_x) - con->x;
- int relative_grow_y = (e->ref_con_ly + grow_y) - con->y;
+ int relative_grow_width = width - con->pending.width;
+ int relative_grow_height = height - con->pending.height;
+ int relative_grow_x = (e->ref_con_lx + grow_x) - con->pending.x;
+ int relative_grow_y = (e->ref_con_ly + grow_y) - con->pending.y;
// Actually resize stuff
- con->x += relative_grow_x;
- con->y += relative_grow_y;
- con->width += relative_grow_width;
- con->height += relative_grow_height;
+ con->pending.x += relative_grow_x;
+ con->pending.y += relative_grow_y;
+ con->pending.width += relative_grow_width;
+ con->pending.height += relative_grow_height;
- con->content_x += relative_grow_x;
- con->content_y += relative_grow_y;
- con->content_width += relative_grow_width;
- con->content_height += relative_grow_height;
+ con->pending.content_x += relative_grow_x;
+ con->pending.content_y += relative_grow_y;
+ con->pending.content_width += relative_grow_width;
+ con->pending.content_height += relative_grow_height;
arrange_container(con);
+ transaction_commit_dirty();
}
static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
@@ -167,16 +169,17 @@ void seatop_begin_resize_floating(struct sway_seat *seat,
e->edge = edge == WLR_EDGE_NONE ? WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT : edge;
e->ref_lx = seat->cursor->cursor->x;
e->ref_ly = seat->cursor->cursor->y;
- e->ref_con_lx = con->x;
- e->ref_con_ly = con->y;
- e->ref_width = con->width;
- e->ref_height = con->height;
+ e->ref_con_lx = con->pending.x;
+ e->ref_con_ly = con->pending.y;
+ e->ref_width = con->pending.width;
+ e->ref_height = con->pending.height;
seat->seatop_impl = &seatop_impl;
seat->seatop_data = e;
container_set_resizing(con, true);
container_raise_floating(con);
+ transaction_commit_dirty();
const char *image = edge == WLR_EDGE_NONE ?
"se-resize" : wlr_xcursor_get_resize_name(edge);
diff --git a/sway/input/seatop_resize_tiling.c b/sway/input/seatop_resize_tiling.c
index 0dfafbd07..869d11b50 100644
--- a/sway/input/seatop_resize_tiling.c
+++ b/sway/input/seatop_resize_tiling.c
@@ -2,6 +2,7 @@
#include
#include
#include "sway/commands.h"
+#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
#include "sway/tree/arrange.h"
@@ -52,27 +53,27 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
if (e->h_con) {
container_set_resizing(e->h_con, false);
container_set_resizing(e->h_sib, false);
- if (e->h_con->parent) {
- arrange_container(e->h_con->parent);
+ if (e->h_con->pending.parent) {
+ arrange_container(e->h_con->pending.parent);
} else {
- arrange_workspace(e->h_con->workspace);
+ arrange_workspace(e->h_con->pending.workspace);
}
}
if (e->v_con) {
container_set_resizing(e->v_con, false);
container_set_resizing(e->v_sib, false);
- if (e->v_con->parent) {
- arrange_container(e->v_con->parent);
+ if (e->v_con->pending.parent) {
+ arrange_container(e->v_con->pending.parent);
} else {
- arrange_workspace(e->v_con->workspace);
+ arrange_workspace(e->v_con->pending.workspace);
}
}
+ transaction_commit_dirty();
seatop_begin_default(seat);
}
}
-static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec,
- double dx, double dy) {
+static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
struct seatop_resize_tiling_event *e = seat->seatop_data;
int amount_x = 0;
int amount_y = 0;
@@ -81,16 +82,16 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec,
if (e->h_con) {
if (e->edge & WLR_EDGE_LEFT) {
- amount_x = (e->h_con_orig_width - moved_x) - e->h_con->width;
+ amount_x = (e->h_con_orig_width - moved_x) - e->h_con->pending.width;
} else if (e->edge & WLR_EDGE_RIGHT) {
- amount_x = (e->h_con_orig_width + moved_x) - e->h_con->width;
+ amount_x = (e->h_con_orig_width + moved_x) - e->h_con->pending.width;
}
}
if (e->v_con) {
if (e->edge & WLR_EDGE_TOP) {
- amount_y = (e->v_con_orig_height - moved_y) - e->v_con->height;
+ amount_y = (e->v_con_orig_height - moved_y) - e->v_con->pending.height;
} else if (e->edge & WLR_EDGE_BOTTOM) {
- amount_y = (e->v_con_orig_height + moved_y) - e->v_con->height;
+ amount_y = (e->v_con_orig_height + moved_y) - e->v_con->pending.height;
}
}
@@ -100,6 +101,7 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec,
if (amount_y != 0) {
container_resize_tiled(e->v_con, e->edge_y, amount_y);
}
+ transaction_commit_dirty();
}
static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
@@ -107,6 +109,9 @@ static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
if (e->con == con) {
seatop_begin_default(seat);
}
+ if (e->h_sib == con || e->v_sib == con) {
+ seatop_begin_default(seat);
+ }
}
static const struct sway_seatop_impl seatop_impl = {
@@ -138,7 +143,7 @@ void seatop_begin_resize_tiling(struct sway_seat *seat,
if (e->h_con) {
container_set_resizing(e->h_con, true);
container_set_resizing(e->h_sib, true);
- e->h_con_orig_width = e->h_con->width;
+ e->h_con_orig_width = e->h_con->pending.width;
}
}
if (edge & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) {
@@ -149,12 +154,13 @@ void seatop_begin_resize_tiling(struct sway_seat *seat,
if (e->v_con) {
container_set_resizing(e->v_con, true);
container_set_resizing(e->v_sib, true);
- e->v_con_orig_height = e->v_con->height;
+ e->v_con_orig_height = e->v_con->pending.height;
}
}
seat->seatop_impl = &seatop_impl;
seat->seatop_data = e;
+ transaction_commit_dirty();
wlr_seat_pointer_notify_clear_focus(seat->wlr_seat);
}
diff --git a/sway/input/switch.c b/sway/input/switch.c
index b7c28df1f..9ea87a1a7 100644
--- a/sway/input/switch.c
+++ b/sway/input/switch.c
@@ -1,5 +1,4 @@
#include "sway/config.h"
-#include "sway/desktop/transaction.h"
#include "sway/input/switch.h"
#include
#include "log.h"
@@ -61,9 +60,6 @@ static void execute_binding(struct sway_switch *sway_switch) {
seat_execute_command(seat, dummy_binding);
free(dummy_binding);
}
-
- transaction_commit_dirty();
-
}
static void handle_switch_toggle(struct wl_listener *listener, void *data) {
diff --git a/sway/input/tablet.c b/sway/input/tablet.c
index b74347aab..26e86e364 100644
--- a/sway/input/tablet.c
+++ b/sway/input/tablet.c
@@ -2,6 +2,8 @@
#include
#include
#include
+#include
+#include
#include "log.h"
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
@@ -140,6 +142,29 @@ void sway_tablet_tool_configure(struct sway_tablet *tablet,
return;
}
+ switch (wlr_tool->type) {
+ case WLR_TABLET_TOOL_TYPE_LENS:
+ case WLR_TABLET_TOOL_TYPE_MOUSE:
+ tool->mode = SWAY_TABLET_TOOL_MODE_RELATIVE;
+ break;
+ default:
+ tool->mode = SWAY_TABLET_TOOL_MODE_ABSOLUTE;
+
+ struct input_config *ic = input_device_get_config(
+ tablet->seat_device->input_device);
+ if (!ic) {
+ break;
+ }
+
+ for (int i = 0; i < ic->tools->length; i++) {
+ struct input_config_tool *tool_config = ic->tools->items[i];
+ if (tool_config->type == wlr_tool->type) {
+ tool->mode = tool_config->mode;
+ break;
+ }
+ }
+ }
+
tool->seat = tablet->seat_device->sway_seat;
tool->tablet = tablet;
tool->tablet_v2_tool =
diff --git a/sway/input/text_input.c b/sway/input/text_input.c
index 2fb25eef6..b8c19c179 100644
--- a/sway/input/text_input.c
+++ b/sway/input/text_input.c
@@ -55,6 +55,37 @@ static void handle_im_commit(struct wl_listener *listener, void *data) {
wlr_text_input_v3_send_done(text_input->input);
}
+static void handle_im_keyboard_grab_destroy(struct wl_listener *listener, void *data) {
+ struct sway_input_method_relay *relay = wl_container_of(listener, relay,
+ input_method_keyboard_grab_destroy);
+ struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data;
+ wl_list_remove(&relay->input_method_keyboard_grab_destroy.link);
+
+ if (keyboard_grab->keyboard) {
+ // send modifier state to original client
+ wlr_seat_keyboard_notify_modifiers(keyboard_grab->input_method->seat,
+ &keyboard_grab->keyboard->modifiers);
+ }
+}
+
+static void handle_im_grab_keyboard(struct wl_listener *listener, void *data) {
+ struct sway_input_method_relay *relay = wl_container_of(listener, relay,
+ input_method_grab_keyboard);
+ struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data;
+
+ // send modifier state to grab
+ struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(relay->seat->wlr_seat);
+ wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab,
+ active_keyboard);
+ wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab,
+ &active_keyboard->modifiers);
+
+ wl_signal_add(&keyboard_grab->events.destroy,
+ &relay->input_method_keyboard_grab_destroy);
+ relay->input_method_keyboard_grab_destroy.notify =
+ handle_im_keyboard_grab_destroy;
+}
+
static void text_input_set_pending_focused_surface(
struct sway_text_input *text_input, struct wlr_surface *surface) {
wl_list_remove(&text_input->pending_focused_surface_destroy.link);
@@ -92,13 +123,18 @@ static void relay_send_im_state(struct sway_input_method_relay *relay,
return;
}
// TODO: only send each of those if they were modified
- wlr_input_method_v2_send_surrounding_text(input_method,
- input->current.surrounding.text, input->current.surrounding.cursor,
- input->current.surrounding.anchor);
+ if (input->active_features & WLR_TEXT_INPUT_V3_FEATURE_SURROUNDING_TEXT) {
+ wlr_input_method_v2_send_surrounding_text(input_method,
+ input->current.surrounding.text, input->current.surrounding.cursor,
+ input->current.surrounding.anchor);
+ }
wlr_input_method_v2_send_text_change_cause(input_method,
input->current.text_change_cause);
- wlr_input_method_v2_send_content_type(input_method,
- input->current.content_type.hint, input->current.content_type.purpose);
+ if (input->active_features & WLR_TEXT_INPUT_V3_FEATURE_CONTENT_TYPE) {
+ wlr_input_method_v2_send_content_type(input_method,
+ input->current.content_type.hint,
+ input->current.content_type.purpose);
+ }
wlr_input_method_v2_send_done(input_method);
// TODO: pass intent, display popup size
}
@@ -144,6 +180,10 @@ static void handle_text_input_disable(struct wl_listener *listener,
void *data) {
struct sway_text_input *text_input = wl_container_of(listener, text_input,
text_input_disable);
+ if (text_input->input->focused_surface == NULL) {
+ sway_log(SWAY_DEBUG, "Disabling text input, but no longer focused");
+ return;
+ }
relay_disable_text_input(text_input->relay, text_input);
}
@@ -236,6 +276,9 @@ static void relay_handle_input_method(struct wl_listener *listener,
wl_signal_add(&relay->input_method->events.commit,
&relay->input_method_commit);
relay->input_method_commit.notify = handle_im_commit;
+ wl_signal_add(&relay->input_method->events.grab_keyboard,
+ &relay->input_method_grab_keyboard);
+ relay->input_method_grab_keyboard.notify = handle_im_grab_keyboard;
wl_signal_add(&relay->input_method->events.destroy,
&relay->input_method_destroy);
relay->input_method_destroy.notify = handle_im_destroy;
@@ -263,6 +306,11 @@ void sway_input_method_relay_init(struct sway_seat *seat,
&relay->input_method_new);
}
+void sway_input_method_relay_finish(struct sway_input_method_relay *relay) {
+ wl_list_remove(&relay->input_method_new.link);
+ wl_list_remove(&relay->text_input_new.link);
+}
+
void sway_input_method_relay_set_focus(struct sway_input_method_relay *relay,
struct wlr_surface *surface) {
struct sway_text_input *text_input;
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index 9330de09f..1b64f86e1 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -1,7 +1,11 @@
+#include
+#include
#include
#include
#include
-#include
+#include
+#include
+#include
#include "config.h"
#include "log.h"
#include "sway/config.h"
@@ -13,16 +17,26 @@
#include "sway/input/input-manager.h"
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
-#include
-#include
-#include
-#include
#include "wlr-layer-shell-unstable-v1-protocol.h"
#include "sway/desktop/idle_inhibit_v1.h"
static const int i3_output_id = INT32_MAX;
static const int i3_scratch_id = INT32_MAX - 1;
+static const char *ipc_json_node_type_description(enum sway_node_type node_type) {
+ switch (node_type) {
+ case N_ROOT:
+ return "root";
+ case N_OUTPUT:
+ return "output";
+ case N_WORKSPACE:
+ return "workspace";
+ case N_CONTAINER:
+ return "con";
+ }
+ return "none";
+}
+
static const char *ipc_json_layout_description(enum sway_container_layout l) {
switch (l) {
case L_VERT:
@@ -189,16 +203,22 @@ static json_object *ipc_json_create_empty_rect(void) {
return ipc_json_create_rect(&empty);
}
-static json_object *ipc_json_create_node(int id, char *name,
+static json_object *ipc_json_create_node(int id, const char* type, char *name,
bool focused, json_object *focus, struct wlr_box *box) {
json_object *object = json_object_new_object();
json_object_object_add(object, "id", json_object_new_int(id));
- json_object_object_add(object, "name",
- name ? json_object_new_string(name) : NULL);
- json_object_object_add(object, "rect", ipc_json_create_rect(box));
+ json_object_object_add(object, "type", json_object_new_string(type));
+ json_object_object_add(object, "orientation",
+ json_object_new_string(
+ ipc_json_orientation_description(L_HORIZ)));
+ json_object_object_add(object, "percent", NULL);
+ json_object_object_add(object, "urgent", json_object_new_boolean(false));
+ json_object_object_add(object, "marks", json_object_new_array());
json_object_object_add(object, "focused", json_object_new_boolean(focused));
- json_object_object_add(object, "focus", focus);
+ json_object_object_add(object, "layout",
+ json_object_new_string(
+ ipc_json_layout_description(L_HORIZ)));
// set default values to be compatible with i3
json_object_object_add(object, "border",
@@ -206,35 +226,25 @@ static json_object *ipc_json_create_node(int id, char *name,
ipc_json_border_description(B_NONE)));
json_object_object_add(object, "current_border_width",
json_object_new_int(0));
- json_object_object_add(object, "layout",
- json_object_new_string(
- ipc_json_layout_description(L_HORIZ)));
- json_object_object_add(object, "orientation",
- json_object_new_string(
- ipc_json_orientation_description(L_HORIZ)));
- json_object_object_add(object, "percent", NULL);
- json_object_object_add(object, "window_rect", ipc_json_create_empty_rect());
+ json_object_object_add(object, "rect", ipc_json_create_rect(box));
json_object_object_add(object, "deco_rect", ipc_json_create_empty_rect());
+ json_object_object_add(object, "window_rect", ipc_json_create_empty_rect());
json_object_object_add(object, "geometry", ipc_json_create_empty_rect());
+ json_object_object_add(object, "name",
+ name ? json_object_new_string(name) : NULL);
json_object_object_add(object, "window", NULL);
- json_object_object_add(object, "urgent", json_object_new_boolean(false));
- json_object_object_add(object, "marks", json_object_new_array());
- json_object_object_add(object, "fullscreen_mode", json_object_new_int(0));
json_object_object_add(object, "nodes", json_object_new_array());
json_object_object_add(object, "floating_nodes", json_object_new_array());
+ json_object_object_add(object, "focus", focus);
+ json_object_object_add(object, "fullscreen_mode", json_object_new_int(0));
json_object_object_add(object, "sticky", json_object_new_boolean(false));
return object;
}
-static void ipc_json_describe_root(struct sway_root *root, json_object *object) {
- json_object_object_add(object, "type", json_object_new_string("root"));
-}
-
static void ipc_json_describe_output(struct sway_output *output,
json_object *object) {
struct wlr_output *wlr_output = output->wlr_output;
- json_object_object_add(object, "type", json_object_new_string("output"));
json_object_object_add(object, "active", json_object_new_boolean(true));
json_object_object_add(object, "dpms",
json_object_new_boolean(wlr_output->enabled));
@@ -369,11 +379,9 @@ static json_object *ipc_json_describe_scratchpad_output(void) {
json_object_new_int(container->node.id));
}
- json_object *workspace = ipc_json_create_node(i3_scratch_id,
+ json_object *workspace = ipc_json_create_node(i3_scratch_id, "workspace",
"__i3_scratch", false, workspace_focus, &box);
json_object_object_add(workspace, "fullscreen_mode", json_object_new_int(1));
- json_object_object_add(workspace, "type",
- json_object_new_string("workspace"));
// List all hidden scratchpad containers as floating nodes
json_object *floating_array = json_object_new_array();
@@ -390,10 +398,8 @@ static json_object *ipc_json_describe_scratchpad_output(void) {
json_object *output_focus = json_object_new_array();
json_object_array_add(output_focus, json_object_new_int(i3_scratch_id));
- json_object *output = ipc_json_create_node(i3_output_id,
+ json_object *output = ipc_json_create_node(i3_output_id, "output",
"__i3", false, output_focus, &box);
- json_object_object_add(output, "type",
- json_object_new_string("output"));
json_object_object_add(output, "layout",
json_object_new_string("output"));
@@ -423,7 +429,6 @@ static void ipc_json_describe_workspace(struct sway_workspace *workspace,
json_object_object_add(object, "fullscreen_mode", json_object_new_int(1));
json_object_object_add(object, "output", workspace->output ?
json_object_new_string(workspace->output->wlr_output->name) : NULL);
- json_object_object_add(object, "type", json_object_new_string("workspace"));
json_object_object_add(object, "urgent",
json_object_new_boolean(workspace->urgent));
json_object_object_add(object, "representation", workspace->representation ?
@@ -451,27 +456,27 @@ static void get_deco_rect(struct sway_container *c, struct wlr_box *deco_rect) {
bool tab_or_stack = parent_layout == L_TABBED || parent_layout == L_STACKED;
if (((!tab_or_stack || container_is_floating(c)) &&
c->current.border != B_NORMAL) ||
- c->fullscreen_mode != FULLSCREEN_NONE ||
- c->workspace == NULL) {
+ c->pending.fullscreen_mode != FULLSCREEN_NONE ||
+ c->pending.workspace == NULL) {
deco_rect->x = deco_rect->y = deco_rect->width = deco_rect->height = 0;
return;
}
- if (c->parent) {
- deco_rect->x = c->x - c->parent->x;
- deco_rect->y = c->y - c->parent->y;
+ if (c->pending.parent) {
+ deco_rect->x = c->pending.x - c->pending.parent->pending.x;
+ deco_rect->y = c->pending.y - c->pending.parent->pending.y;
} else {
- deco_rect->x = c->x - c->workspace->x;
- deco_rect->y = c->y - c->workspace->y;
+ deco_rect->x = c->pending.x - c->pending.workspace->x;
+ deco_rect->y = c->pending.y - c->pending.workspace->y;
}
- deco_rect->width = c->width;
+ deco_rect->width = c->pending.width;
deco_rect->height = container_titlebar_height();
if (!container_is_floating(c)) {
if (parent_layout == L_TABBED) {
- deco_rect->width = c->parent
- ? c->parent->width / c->parent->children->length
- : c->workspace->width / c->workspace->tiling->length;
+ deco_rect->width = c->pending.parent
+ ? c->pending.parent->pending.width / c->pending.parent->pending.children->length
+ : c->pending.workspace->width / c->pending.workspace->tiling->length;
deco_rect->x += deco_rect->width * container_sibling_index(c);
} else if (parent_layout == L_STACKED) {
if (!c->view) {
@@ -494,10 +499,10 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
json_object_object_add(object, "visible", json_object_new_boolean(visible));
struct wlr_box window_box = {
- c->content_x - c->x,
+ c->pending.content_x - c->pending.x,
(c->current.border == B_PIXEL) ? c->current.border_thickness : 0,
- c->content_width,
- c->content_height
+ c->pending.content_width,
+ c->pending.content_height
};
json_object_object_add(object, "window_rect", ipc_json_create_rect(&window_box));
@@ -583,16 +588,18 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
static void ipc_json_describe_container(struct sway_container *c, json_object *object) {
json_object_object_add(object, "name",
c->title ? json_object_new_string(c->title) : NULL);
- json_object_object_add(object, "type",
- json_object_new_string(container_is_floating(c) ? "floating_con" : "con"));
+ if (container_is_floating(c)) {
+ json_object_object_add(object, "type",
+ json_object_new_string("floating_con"));
+ }
json_object_object_add(object, "layout",
json_object_new_string(
- ipc_json_layout_description(c->layout)));
+ ipc_json_layout_description(c->pending.layout)));
json_object_object_add(object, "orientation",
json_object_new_string(
- ipc_json_orientation_description(c->layout)));
+ ipc_json_orientation_description(c->pending.layout)));
bool urgent = c->view ?
view_is_urgent(c->view) : container_has_urgent_child(c);
@@ -600,7 +607,7 @@ static void ipc_json_describe_container(struct sway_container *c, json_object *o
json_object_object_add(object, "sticky", json_object_new_boolean(c->is_sticky));
json_object_object_add(object, "fullscreen_mode",
- json_object_new_int(c->fullscreen_mode));
+ json_object_new_int(c->pending.fullscreen_mode));
struct sway_node *parent = node_get_parent(&c->node);
struct wlr_box parent_box = {0, 0, 0, 0};
@@ -610,8 +617,8 @@ static void ipc_json_describe_container(struct sway_container *c, json_object *o
}
if (parent_box.width != 0 && parent_box.height != 0) {
- double percent = ((double)c->width / parent_box.width)
- * ((double)c->height / parent_box.height);
+ double percent = ((double)c->pending.width / parent_box.width)
+ * ((double)c->pending.height / parent_box.height);
json_object_object_add(object, "percent", json_object_new_double(percent));
}
@@ -692,12 +699,11 @@ json_object *ipc_json_describe_node(struct sway_node *node) {
};
seat_for_each_node(seat, focus_inactive_children_iterator, &data);
- json_object *object = ipc_json_create_node(
- (int)node->id, name, focused, focus, &box);
+ json_object *object = ipc_json_create_node((int)node->id,
+ ipc_json_node_type_description(node->type), name, focused, focus, &box);
switch (node->type) {
case N_ROOT:
- ipc_json_describe_root(root, object);
break;
case N_OUTPUT:
ipc_json_describe_output(node->sway_output, object);
@@ -743,10 +749,10 @@ json_object *ipc_json_describe_node_recursive(struct sway_node *node) {
}
break;
case N_CONTAINER:
- if (node->sway_container->children) {
- for (i = 0; i < node->sway_container->children->length; ++i) {
+ if (node->sway_container->pending.children) {
+ for (i = 0; i < node->sway_container->pending.children->length; ++i) {
struct sway_container *child =
- node->sway_container->children->items[i];
+ node->sway_container->pending.children->items[i];
json_object_array_add(children,
ipc_json_describe_node_recursive(&child->node));
}
@@ -996,6 +1002,17 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
}
}
+ if (device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) {
+ struct input_config *ic = input_device_get_config(device);
+ float scroll_factor = 1.0f;
+ if (ic != NULL && !isnan(ic->scroll_factor) &&
+ ic->scroll_factor != FLT_MIN) {
+ scroll_factor = ic->scroll_factor;
+ }
+ json_object_object_add(object, "scroll_factor",
+ json_object_new_double(scroll_factor));
+ }
+
if (wlr_input_device_is_libinput(device->wlr_device)) {
struct libinput_device *libinput_dev;
libinput_dev = wlr_libinput_get_device_handle(device->wlr_device);
@@ -1102,12 +1119,16 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) {
json_object_new_boolean(bar->strip_workspace_numbers));
json_object_object_add(json, "strip_workspace_name",
json_object_new_boolean(bar->strip_workspace_name));
+ json_object_object_add(json, "workspace_min_width",
+ json_object_new_int(bar->workspace_min_width));
json_object_object_add(json, "binding_mode_indicator",
json_object_new_boolean(bar->binding_mode_indicator));
json_object_object_add(json, "verbose",
json_object_new_boolean(bar->verbose));
json_object_object_add(json, "pango_markup",
- json_object_new_boolean(bar->pango_markup));
+ json_object_new_boolean(bar->pango_markup == PANGO_MARKUP_DEFAULT
+ ? config->pango_markup
+ : bar->pango_markup));
json_object *colors = json_object_new_object();
json_object_object_add(colors, "background",
diff --git a/sway/main.c b/sway/main.c
index 57716071e..6c71048b0 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -6,12 +6,14 @@
#include
#include
#include
+#include
#include
#include
#include
#include
#include
#include
+#include
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/server.h"
@@ -26,6 +28,7 @@
static bool terminate_request = false;
static int exit_value = 0;
+static struct rlimit original_nofile_rlimit = {0};
struct sway_server server = {0};
struct sway_debug debug = {0};
@@ -46,43 +49,6 @@ void sig_handler(int signal) {
sway_terminate(EXIT_SUCCESS);
}
-void detect_raspi(void) {
- bool raspi = false;
- FILE *f = fopen("/sys/firmware/devicetree/base/model", "r");
- if (!f) {
- return;
- }
- char *line = NULL;
- size_t line_size = 0;
- while (getline(&line, &line_size, f) != -1) {
- if (strstr(line, "Raspberry Pi")) {
- raspi = true;
- break;
- }
- }
- fclose(f);
- FILE *g = fopen("/proc/modules", "r");
- if (!g) {
- free(line);
- return;
- }
- bool vc4 = false;
- while (getline(&line, &line_size, g) != -1) {
- if (strstr(line, "vc4")) {
- vc4 = true;
- break;
- }
- }
- free(line);
- fclose(g);
- if (!vc4 && raspi) {
- fprintf(stderr, "\x1B[1;31mWarning: You have a "
- "Raspberry Pi, but the vc4 Module is "
- "not loaded! Set 'dtoverlay=vc4-kms-v3d'"
- "in /boot/config.txt and reboot.\x1B[0m\n");
- }
-}
-
void detect_proprietary(int allow_unsupported_gpu) {
FILE *f = fopen("/proc/modules", "r");
if (!f) {
@@ -99,7 +65,7 @@ void detect_proprietary(int allow_unsupported_gpu) {
sway_log(SWAY_ERROR,
"Proprietary Nvidia drivers are NOT supported. "
"Use Nouveau. To launch sway anyway, launch with "
- "--my-next-gpu-wont-be-nvidia and DO NOT report issues.");
+ "--unsupported-gpu and DO NOT report issues.");
exit(EXIT_FAILURE);
}
break;
@@ -205,6 +171,33 @@ static bool drop_permissions(void) {
return true;
}
+static void increase_nofile_limit(void) {
+ if (getrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) {
+ sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: "
+ "getrlimit(NOFILE) failed");
+ return;
+ }
+
+ struct rlimit new_rlimit = original_nofile_rlimit;
+ new_rlimit.rlim_cur = new_rlimit.rlim_max;
+ if (setrlimit(RLIMIT_NOFILE, &new_rlimit) != 0) {
+ sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: "
+ "setrlimit(NOFILE) failed");
+ sway_log(SWAY_INFO, "Running with %d max open files",
+ (int)original_nofile_rlimit.rlim_cur);
+ }
+}
+
+void restore_nofile_limit(void) {
+ if (original_nofile_rlimit.rlim_cur == 0) {
+ return;
+ }
+ if (setrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) {
+ sway_log_errno(SWAY_ERROR, "Failed to restore max open files limit: "
+ "setrlimit(NOFILE) failed");
+ }
+}
+
void enable_debug_flag(const char *flag) {
if (strcmp(flag, "damage=highlight") == 0) {
debug.damage = DAMAGE_HIGHLIGHT;
@@ -218,15 +211,36 @@ void enable_debug_flag(const char *flag) {
debug.txn_timings = true;
} else if (strncmp(flag, "txn-timeout=", 12) == 0) {
server.txn_timeout_ms = atoi(&flag[12]);
+ } else if (strcmp(flag, "noscanout") == 0) {
+ debug.noscanout = true;
} else {
sway_log(SWAY_ERROR, "Unknown debug flag: %s", flag);
}
}
+static sway_log_importance_t convert_wlr_log_importance(
+ enum wlr_log_importance importance) {
+ switch (importance) {
+ case WLR_ERROR:
+ return SWAY_ERROR;
+ case WLR_INFO:
+ return SWAY_INFO;
+ default:
+ return SWAY_DEBUG;
+ }
+}
+
+static void handle_wlr_log(enum wlr_log_importance importance,
+ const char *fmt, va_list args) {
+ static char sway_fmt[1024];
+ snprintf(sway_fmt, sizeof(sway_fmt), "[wlr] %s", fmt);
+ _sway_vlog(convert_wlr_log_importance(importance), sway_fmt, args);
+}
+
int main(int argc, char **argv) {
static int verbose = 0, debug = 0, validate = 0, allow_unsupported_gpu = 0;
- static struct option long_options[] = {
+ static const struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"config", required_argument, NULL, 'c'},
{"validate", no_argument, NULL, 'C'},
@@ -235,7 +249,6 @@ int main(int argc, char **argv) {
{"verbose", no_argument, NULL, 'V'},
{"get-socketpath", no_argument, NULL, 'p'},
{"unsupported-gpu", no_argument, NULL, 'u'},
- {"my-next-gpu-wont-be-nvidia", no_argument, NULL, 'u'},
{0, 0, 0, 0}
};
@@ -262,7 +275,7 @@ int main(int argc, char **argv) {
}
switch (c) {
case 'h': // help
- fprintf(stdout, "%s", usage);
+ printf("%s", usage);
exit(EXIT_SUCCESS);
break;
case 'c': // config
@@ -282,7 +295,7 @@ int main(int argc, char **argv) {
allow_unsupported_gpu = 1;
break;
case 'v': // version
- fprintf(stdout, "sway version " SWAY_VERSION "\n");
+ printf("sway version " SWAY_VERSION "\n");
exit(EXIT_SUCCESS);
break;
case 'V': // verbose
@@ -290,7 +303,7 @@ int main(int argc, char **argv) {
break;
case 'p': ; // --get-socketpath
if (getenv("SWAYSOCK")) {
- fprintf(stdout, "%s\n", getenv("SWAYSOCK"));
+ printf("%s\n", getenv("SWAYSOCK"));
exit(EXIT_SUCCESS);
} else {
fprintf(stderr, "sway socket not detected.\n");
@@ -315,21 +328,20 @@ int main(int argc, char **argv) {
// sway, we do not need to override it.
if (debug) {
sway_log_init(SWAY_DEBUG, sway_terminate);
- wlr_log_init(WLR_DEBUG, NULL);
+ wlr_log_init(WLR_DEBUG, handle_wlr_log);
} else if (verbose) {
sway_log_init(SWAY_INFO, sway_terminate);
- wlr_log_init(WLR_INFO, NULL);
+ wlr_log_init(WLR_INFO, handle_wlr_log);
} else {
sway_log_init(SWAY_ERROR, sway_terminate);
- wlr_log_init(WLR_ERROR, NULL);
+ wlr_log_init(WLR_ERROR, handle_wlr_log);
}
sway_log(SWAY_INFO, "Sway version " SWAY_VERSION);
+ sway_log(SWAY_INFO, "wlroots version " WLR_VERSION_STR);
log_kernel();
log_distro();
log_env();
- detect_proprietary(allow_unsupported_gpu);
- detect_raspi();
if (optind < argc) { // Behave as IPC client
if (optind != 1) {
@@ -356,6 +368,8 @@ int main(int argc, char **argv) {
return 0;
}
+ detect_proprietary(allow_unsupported_gpu);
+
if (!server_privileged_prepare(&server)) {
return 1;
}
@@ -365,8 +379,11 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE);
}
+ increase_nofile_limit();
+
// handle SIGTERM signals
signal(SIGTERM, sig_handler);
+ signal(SIGINT, sig_handler);
// prevent ipc from crashing sway
signal(SIGPIPE, SIG_IGN);
diff --git a/sway/meson.build b/sway/meson.build
index 0db458362..1402db154 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -8,6 +8,7 @@ sway_sources = files(
'main.c',
'server.c',
'swaynag.c',
+ 'xdg_activation_v1.c',
'xdg_decoration.c',
'desktop/desktop.c',
@@ -144,6 +145,7 @@ sway_sources = files(
'commands/bar/tray_output.c',
'commands/bar/tray_padding.c',
'commands/bar/workspace_buttons.c',
+ 'commands/bar/workspace_min_width.c',
'commands/bar/wrap_scroll.c',
'commands/input/accel_profile.c',
@@ -167,6 +169,7 @@ sway_sources = files(
'commands/input/scroll_method.c',
'commands/input/tap.c',
'commands/input/tap_button_map.c',
+ 'commands/input/tool_mode.c',
'commands/input/xkb_capslock.c',
'commands/input/xkb_file.c',
'commands/input/xkb_layout.c',
@@ -202,9 +205,11 @@ sway_sources = files(
sway_deps = [
cairo,
+ drm,
jsonc,
libevdev,
libinput,
+ libudev,
math,
pango,
pcre,
diff --git a/sway/server.c b/sway/server.c
index 28d680f87..7b5bd4044 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -1,19 +1,21 @@
-#define _POSIX_C_SOURCE 200112L
+#define _POSIX_C_SOURCE 200809L
#include
#include
#include
+#include
#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include
+#include
#include
#include
-#include
#include
#include
#include
@@ -24,7 +26,11 @@
#include
#include
#include
+#include
#include
+#include
+#include
+#include
#include
#include "config.h"
#include "list.h"
@@ -43,7 +49,7 @@ bool server_privileged_prepare(struct sway_server *server) {
sway_log(SWAY_DEBUG, "Preparing Wayland server initialization");
server->wl_display = wl_display_create();
server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
- server->backend = wlr_backend_autocreate(server->wl_display, NULL);
+ server->backend = wlr_backend_autocreate(server->wl_display);
if (!server->backend) {
sway_log(SWAY_ERROR, "Unable to create backend");
@@ -52,7 +58,6 @@ bool server_privileged_prepare(struct sway_server *server) {
return true;
}
-
static void handle_workspace_manager_commit_request(struct wl_listener *listener, void *data) {
struct sway_server *_server = wl_container_of(listener, _server, workspace_manager_commit_request);
struct wlr_workspace_manager_v1 *manager = data;
@@ -70,7 +75,19 @@ static void handle_workspace_manager_commit_request(struct wl_listener *listener
}
struct sway_workspace *sw_workspace = workspace_by_name(next_active_workspace->name);
- workspace_switch(sw_workspace, false);
+ workspace_switch(sw_workspace);
+ }
+}
+
+static void handle_drm_lease_request(struct wl_listener *listener, void *data) {
+ /* We only offer non-desktop outputs, but in the future we might want to do
+ * more logic here. */
+
+ struct wlr_drm_lease_request_v1 *req = data;
+ struct wlr_drm_lease_v1 *lease = wlr_drm_lease_request_v1_grant(req);
+ if (!lease) {
+ sway_log(SWAY_ERROR, "Failed to grant lease request");
+ wlr_drm_lease_request_v1_reject(req);
}
}
@@ -91,7 +108,6 @@ bool server_init(struct sway_server *server) {
wlr_data_device_manager_create(server->wl_display);
wlr_gamma_control_manager_v1_create(server->wl_display);
- wlr_gtk_primary_selection_device_manager_create(server->wl_display);
server->new_output.notify = handle_new_output;
wl_signal_add(&server->backend->events.new_output, &server->new_output);
@@ -173,13 +189,44 @@ bool server_init(struct sway_server *server) {
wl_signal_add(&server->workspace_manager->events.commit,
&server->workspace_manager_commit_request);
+ server->drm_lease_manager=
+ wlr_drm_lease_v1_manager_create(server->wl_display, server->backend);
+ if (server->drm_lease_manager) {
+ server->drm_lease_request.notify = handle_drm_lease_request;
+ wl_signal_add(&server->drm_lease_manager->events.request,
+ &server->drm_lease_request);
+ } else {
+ sway_log(SWAY_DEBUG, "Failed to create wlr_drm_lease_device_v1");
+ sway_log(SWAY_INFO, "VR will not be available");
+ }
+
wlr_export_dmabuf_manager_v1_create(server->wl_display);
wlr_screencopy_manager_v1_create(server->wl_display);
wlr_data_control_manager_v1_create(server->wl_display);
wlr_primary_selection_v1_device_manager_create(server->wl_display);
wlr_viewporter_create(server->wl_display);
- server->socket = wl_display_add_socket_auto(server->wl_display);
+ struct wlr_xdg_foreign_registry *foreign_registry =
+ wlr_xdg_foreign_registry_create(server->wl_display);
+ wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry);
+ wlr_xdg_foreign_v2_create(server->wl_display, foreign_registry);
+
+ server->xdg_activation_v1 = wlr_xdg_activation_v1_create(server->wl_display);
+ server->xdg_activation_v1_request_activate.notify =
+ xdg_activation_v1_handle_request_activate;
+ wl_signal_add(&server->xdg_activation_v1->events.request_activate,
+ &server->xdg_activation_v1_request_activate);
+
+ // Avoid using "wayland-0" as display socket
+ char name_candidate[16];
+ for (int i = 1; i <= 32; ++i) {
+ sprintf(name_candidate, "wayland-%d", i);
+ if (wl_display_add_socket(server->wl_display, name_candidate) >= 0) {
+ server->socket = strdup(name_candidate);
+ break;
+ }
+ }
+
if (!server->socket) {
sway_log(SWAY_ERROR, "Unable to open wayland socket");
wlr_backend_destroy(server->backend);
@@ -193,7 +240,12 @@ bool server_init(struct sway_server *server) {
server->headless_backend =
wlr_headless_backend_create_with_renderer(server->wl_display, renderer);
- wlr_multi_backend_add(server->backend, server->headless_backend);
+ if (!server->headless_backend) {
+ sway_log(SWAY_INFO, "Failed to create secondary headless backend, "
+ "starting without it");
+ } else {
+ wlr_multi_backend_add(server->backend, server->headless_backend);
+ }
// This may have been set already via -Dtxn-timeout
if (!server->txn_timeout_ms) {
@@ -201,7 +253,6 @@ bool server_init(struct sway_server *server) {
}
server->dirty_nodes = create_list();
- server->transactions = create_list();
server->input = input_manager_create(server);
input_manager_get_default_seat(); // create seat0
@@ -217,7 +268,6 @@ void server_fini(struct sway_server *server) {
wl_display_destroy_clients(server->wl_display);
wl_display_destroy(server->wl_display);
list_free(server->dirty_nodes);
- list_free(server->transactions);
}
bool server_start(struct sway_server *server) {
diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd
index 78124c922..42e59d57d 100644
--- a/sway/sway-bar.5.scd
+++ b/sway/sway-bar.5.scd
@@ -40,7 +40,7 @@ runtime.
*font*
Specifies the font to be used in the bar. _font_ should be specified as a
pango font description. For more information on pango font descriptions,
- see https://developer.gnome.org/pango/stable/pango-Fonts.html#pango-font-description-from-string
+ see https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html#description
*gaps* | |
Sets the gaps from the edge of the screen for the bar. Gaps can either be
@@ -138,6 +138,11 @@ runtime.
*workspace_buttons* yes|no
Enables or disables workspace buttons on the bar. Default is _yes_.
+*workspace_min_width* [px]
+ Specifies the minimum width for the workspace buttons on the bar. Default is _0_.
+
+ This setting also applies to the current binding mode indicator.
+
## TRAY
Swaybar provides a system tray where third-party applications may place icons.
diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd
index 9ec5eeaea..8b702b778 100644
--- a/sway/sway-input.5.scd
+++ b/sway/sway-input.5.scd
@@ -94,12 +94,26 @@ The following commands may only be used in the configuration file.
*input* xkb_numlock enabled|disabled
Initially enables or disables NumLock on startup, the default is disabled.
+## TABLET CONFIGURATION
+
+*input* tool_mode
+ Sets whether movement of a tablet tool should be treated as absolute or
+ relative; the default is absolute.
+
+ Valid values for _\_ are currently "pen", "eraser", "brush",
+ "pencil", "airbrush", and the wildcard _\*_, which matches all tools.
+
+ Mouse and lens tools ignore this setting and are always treated as relative.
+
## MAPPING CONFIGURATION
*input* map_to_output
Maps inputs from this device to the specified output. Only meaningful if the
device is a pointer, touch, or drawing tablet device.
+ The wildcard _\*_ can be used to map the input device to the whole desktop
+ layout.
+
*input* map_to_region